《Java從小白到大牛》紙質版已經上架了!!!
封裝性與訪問控制
Java面向對象的封裝性是通過對成員變量和方法進行訪問控制實現的,訪問控制分爲4個等級:私有、默認、保護和公有,具體規則如表10-1所示。
表 101 Java類成員的訪問控制
可否直接訪問控制等級 | 同一個類 | 同一個包 | 不同包的子類 | 不同包非子類 |
---|---|---|---|---|
私有 | Yes | |||
默認 | Yes | Yes | ||
保護 | Yes | Yes | Yes | |
公有 | Yes | Yes | Yes | Yes |
下面詳細解釋一下這4種訪問級別。
私有級別 {#-0}
私有級別的關鍵字是private,私有級別的成員變量和方法只能在其所在類的內部自由使用,在其他的類中則不允許直接訪問。私有級別限制性最高。私有級別示例代碼如下:
// PrivateClass.java文件
package com.a51work6;
public class PrivateClass { ①
private int x; ②
public PrivateClass() { ③
x = 100;
}
private void printX() { ④
System.out.println("Value Of x is" + x);
}
}
// HelloWorld.java文件調用PrivateClass
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
PrivateClass p;
p = new PrivateClass();
//編譯錯誤,PrivateClass中的方法 printX()不可見
p.printX(); ⑤
}
}
上述代碼第①行聲明PrivateClass類,其中的代碼第②行是聲明私有實例變量x,代碼第③行是聲明公有的構造方法,構造方法將在第12章詳細介紹。代碼第④行聲明私有實例方法。
HelloWorld類中代碼第⑤行會有編譯錯誤,因爲PrivateClass中printX()的方法是私有方法。
默認級別 {#-1}
默認級別沒有關鍵字,也就是沒有訪問修飾符,默認級別的成員變量和方法,可以在其所在類內部和同一個包的其他類中被直接訪問,但在不同包的類中則不允許直接訪問。
默認級別示例代碼如下:
// DefaultClass.java文件
package com.a51work6;
public class DefaultClass {
int x; ①
public DefaultClass() {
x = 100;
}
void printX() { ②
System.out.println("Value Of x is" + x);
}
}
上述代碼第①行的x變量前沒有訪問限制修飾符,代碼第②行的方法也是沒有訪問限制修飾符。它們的訪問級別都有默認訪問級別。
在相同包(com.a51work6)中調用DefaultClass類代碼如下:
// com.a51work6包中HelloWorld.java文件
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
DefaultClass p;
p = new DefaultClass();
p.printX();
}
}
默認訪問級別可以在同一包中訪問,上述代碼可以編譯通過。
在不同的包中調用DefaultClass類代碼如下:
// 默認包中HelloWorld.java文件
import com.a51work6.DefaultClass;
public class HelloWorld {
public static void main(String[] args) {
DefaultClass p;
p = new DefaultClass();
// 編譯錯誤,DefaultClass中的方法 printX()不可見
p.printX();
}
}
該HelloWorld.java文件與DefaultClass類不在同一個包中,printX()是默認訪問級別,所以p.printX()方法無法編譯通過。
公有級別 {#-2}
公有級別的關鍵字是public,公有級別的成員變量和方法可以在任何場合被直接訪問,是最寬鬆的一種訪問控制等級。
公有級別示例代碼如下:
// PublicClass.java文件
package com.a51work6;
public class PublicClass {
public int x; ①
public PublicClass() {
x = 100;
}
public void printX() { ②
System.out.println("Value Of x is" + x);
}
}
上述代碼第①行的x變量是公有級別,代碼第②行的方法也是公有級別。調用PublicClass類代碼如下:
// 默認包中HelloWorld.java文件
import com.a51work6.PublicClass;
public class HelloWorld {
public static void main(String[] args) {
PublicClass p;
p = new PublicClass();
p.printX();
}
}
該HelloWorld.java文件與PublicClass類不在同一個包中,可以公有的printX()方法。
保護級別 {#-3}
保護級別的關鍵字是protected,保護級別在同一包中完全與默認訪問級別一樣,但是不同包中子類能夠繼承父類中的protected變量和方法,這就是所謂的保護級別,“保護”就是保護某個類的子類都能繼承該類的變量和方法。
保護級別示例代碼如下:
// ProtectedClass.java文件
package com.a51work6;
public class ProtectedClass {
protected int x; ①
public ProtectedClass() {
x = 100;
}
protected void printX() { ②
System.out.println("Value Of x is " + x);
}
}
上述代碼第①行的x變量是保護級別,代碼第②行的方法也是保護級別。
在相同包(com.a51work6)中調用ProtectedClass類代碼如下:
// 默認包中HelloWorld.java文件
package com.a51work6;
import com.a51work6.ProtectedClass;
public class HelloWorld {
public static void main(String[] args) {
ProtectedClass p;
p = new ProtectedClass();
// 同一包中可以直接訪問ProtectedClass中的方法 printX()
p.printX();
}
}
同一包中保護訪問級別與默認訪問級別一樣,可以直接訪問ProtectedClass的printX()方法,上述代碼可以編譯通過。
在不同的包中調用ProtectedClass類代碼如下:
// 默認包中HelloWorld.java文件
import com.a51work6.ProtectedClass;
public class HelloWorld {
public static void main(String[] args) {
ProtectedClass p;
p = new ProtectedClass();
// 編譯錯誤,不同包中不能直接訪問保護方法printX()
p.printX();
}
}
該HelloWorld.java文件與ProtectedClass類不在同一個包中,不同包中不能直接訪問保護方法printX(),所以p.printX()方法無法編譯通過。
在不同的包中繼承ProtectedClass類代碼如下:
// 默認包中SubClass.java文件
import com.a51work6.ProtectedClass;
public class SubClass extends ProtectedClass {
void display() {
//printX()方法是從父類繼承過來
printX(); ①
//x實例變量是從父類繼承過來
System.out.println(x); ②
}
}
不同包中SubClass從ProtectedClass類繼承了printX()方法和x實例變量。代碼第①行是調用從父類繼承下來的方法,代碼第②行是調用從父類繼承下來的實例變量。
提示 訪問成員有兩種方式:一種是調用,即通過類或對象調用它的成員,如p.printX()語句;另一種是繼承,即子類繼承父類的成員變量和方法。
- 公有訪問級別任何情況下兩種方式都可以;
- 默認訪問級別在同一包中兩種訪問方式都可以,不能在包之外訪問;
- 保護訪問級別在同一包中與默認訪問級別一樣,兩種訪問方式都可以。但是在不同包之外只能繼承訪問;
- 私有訪問級別只能在本類中通過調用方法訪問,不能繼承訪問。
提示 訪問類成員時,在能滿足使用的前提下,應儘量限制類中成員的可見性,訪問級別順序是:私有級別→默認級別→保護級別→公有級別。
靜態變量和靜態方法
有一個Account(銀行賬戶)類,假設它有三個成員變量:amount(賬戶金額)、interestRate(利率)和owner(賬戶名)。在這三個成員變量中,amount和owner會因人而異,對於不同的賬戶這些內容是不同的,而所有賬戶的interestRate都是相同的。
amount和owner成員變量與賬戶個體有關,稱爲“實例變量”,interestRate成員變量與個體無關,或者說是所有賬戶個體共享的,這種變量稱爲“靜態變量”或“類變量”。
靜態變量和靜態方法示例代碼如下:
// Account.java文件
package com.a51work6;
public class Account {
// 實例變量賬戶金額
double amount = 0.0; ①
// 實例變量賬戶名
String owner; ②
// 靜態變量利率
static double interestRate = 0.0668; ③
// 靜態方法
public static double interestBy(double amt) { ④
//靜態方法可以訪問靜態變量和其他靜態方法
return interestRate * amt; ⑤
}
// 實例方法
public String messageWith(double amt) { ⑥
//實例方法可以訪問實例變量、實例方法、靜態變量和靜態方法
double interest = Account.interestBy(amt); ⑦
StringBuilder sb = new StringBuilder();
// 拼接字符串
sb.append(owner).append("的利息是").append(interest);
// 返回字符串
return sb.toString();
}
}
static修飾的成員變量是靜態變量,見代碼第③行。staitc修飾的方法是靜態方法,見代碼第④行。相反,沒有static修飾的成員變量是實例變量,見代碼第①行和第②行;沒有staitc修飾的方法是實例方法,見代碼第⑥行。
注意 靜態方法可以訪問靜態變量和其他靜態方法,例如訪問代碼第⑤行中的interestRate靜態變量。實例方法可以訪問實例變量、其他實例方法、靜態變量和靜態方法,例如訪問代碼第⑦行interestBy靜態方法。
調用Account代碼如下:
// HelloWorld.java文件
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
// 訪問靜態變量
System.out.println(Account.interestRate); ①
// 訪問靜態方法
System.out.println(Account.interestBy(1000)); ②
Account myAccount = new Account();
// 訪問實例變量
myAccount.amount = 1000000; ③
myAccount.owner = "Tony"; ④
// 訪問實例方法
System.out.println(myAccount.messageWith(1000)); ⑤
// 通過實例訪問靜態變量
System.out.println(myAccount.interestRate); ⑥
}
}
調用靜態變量或靜態方法時,可以通過類名或實例名調用,代碼第①行Account.interestRate通過類名調用靜態變量,代碼第②行Account.interestBy(1000)是通過類名調用靜態方法。代碼第⑥行是通過實例調用靜態變量。
靜態代碼塊
前面介紹的靜態變量interestRate,可以在聲明同時初始化,如下代碼所示。
public class Account {
// 靜態變量利率
static double interestRate = 0.0668;
...
}
如果初始化靜態變量不是簡單常量,需要進行計算才能初始化,可以使用靜態(static)代碼塊,靜態代碼塊在類第一次加載時執行,並只執行一次。示例代碼如下:
// Account.java文件
package com.a51work6;
public class Account {
// 實例變量賬戶金額
double amount = 0.0;
// 實例變量賬戶名
String owner;
// 靜態變量利率
static double interestRate;
// 靜態方法
public static double interestBy(double amt) {
// 靜態方法可以訪問靜態變量和其他靜態方法
return interestRate * amt;
}
// 靜態代碼塊
static { ①
System.out.println("靜態代碼塊被調用...");
// 初始化靜態變量
interestRate = 0.0668; ②
}
}
上述代碼第①行是靜態代碼塊,在靜態代碼塊中可以初始化靜態變量,見代碼第②行,也可以調用靜態方法。
調用Account代碼如下:
// HelloWorld.java文件
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
Account myAccount = new Account(); ①
// 訪問靜態變量
System.out.println(Account.interestRate); ②
// 訪問靜態方法
System.out.println(Account.interestBy(1000));
}
}
Account靜態代碼塊是在第一次加載Account類時調用。上述代碼第①行是第一次使用Account類,此時會調用靜態代碼塊。
本章小結
本章主要介紹了面向對象基礎知識。首先介紹了面向對象一些基本概念,面向對象三個基本特性。然後介紹了類、包、方法重載和訪問控制。最後介紹了靜態變量、靜態方法和靜態代碼塊。
配套視頻
http://edu.51cto.com/topic/1246.html
配套源代碼
http://www.zhijieketang.com/group/5