《Java從小白到大?!芳堎|(zhì)版已經(jīng)上架了?。。?/p>

封裝性與訪(fǎng)問(wèn)控制
Java面向?qū)ο蟮姆庋b性是通過(guò)對(duì)成員變量和方法進(jìn)行訪(fǎng)問(wèn)控制實(shí)現(xiàn)的,訪(fǎng)問(wèn)控制分為4個(gè)等級(jí):私有、默認(rèn)、保護(hù)和公有,具體規(guī)則如表10-1所示。
表 101 Java類(lèi)成員的訪(fǎng)問(wèn)控制
| 可否直接訪(fǎng)問(wèn)控制等級(jí) | 同一個(gè)類(lèi) | 同一個(gè)包 | 不同包的子類(lèi) | 不同包非子類(lèi) |
|---|---|---|---|---|
| 私有 | Yes | |||
| 默認(rèn) | Yes | Yes | ||
| 保護(hù) | Yes | Yes | Yes | |
| 公有 | Yes | Yes | Yes | Yes |
下面詳細(xì)解釋一下這4種訪(fǎng)問(wèn)級(jí)別。
私有級(jí)別 {#-0}
私有級(jí)別的關(guān)鍵字是private,私有級(jí)別的成員變量和方法只能在其所在類(lèi)的內(nèi)部自由使用,在其他的類(lèi)中則不允許直接訪(fǎng)問(wèn)。私有級(jí)別限制性最高。私有級(jí)別示例代碼如下:
// 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文件調(diào)用PrivateClass
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
PrivateClass p;
p = new PrivateClass();
//編譯錯(cuò)誤,PrivateClass中的方法 printX()不可見(jiàn)
p.printX(); ⑤
}
}
上述代碼第①行聲明PrivateClass類(lèi),其中的代碼第②行是聲明私有實(shí)例變量x,代碼第③行是聲明公有的構(gòu)造方法,構(gòu)造方法將在第12章詳細(xì)介紹。代碼第④行聲明私有實(shí)例方法。
HelloWorld類(lèi)中代碼第⑤行會(huì)有編譯錯(cuò)誤,因?yàn)镻rivateClass中printX()的方法是私有方法。
默認(rèn)級(jí)別 {#-1}
默認(rèn)級(jí)別沒(méi)有關(guān)鍵字,也就是沒(méi)有訪(fǎng)問(wèn)修飾符,默認(rèn)級(jí)別的成員變量和方法,可以在其所在類(lèi)內(nèi)部和同一個(gè)包的其他類(lèi)中被直接訪(fǎng)問(wèn),但在不同包的類(lèi)中則不允許直接訪(fǎng)問(wèn)。
默認(rèn)級(jí)別示例代碼如下:
// 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變量前沒(méi)有訪(fǎng)問(wèn)限制修飾符,代碼第②行的方法也是沒(méi)有訪(fǎng)問(wèn)限制修飾符。它們的訪(fǎng)問(wèn)級(jí)別都有默認(rèn)訪(fǎng)問(wèn)級(jí)別。
在相同包(com.a51work6)中調(diào)用DefaultClass類(lèi)代碼如下:
// com.a51work6包中HelloWorld.java文件
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
DefaultClass p;
p = new DefaultClass();
p.printX();
}
}
默認(rèn)訪(fǎng)問(wèn)級(jí)別可以在同一包中訪(fǎng)問(wèn),上述代碼可以編譯通過(guò)。
在不同的包中調(diào)用DefaultClass類(lèi)代碼如下:
// 默認(rèn)包中HelloWorld.java文件
import com.a51work6.DefaultClass;
public class HelloWorld {
public static void main(String[] args) {
DefaultClass p;
p = new DefaultClass();
// 編譯錯(cuò)誤,DefaultClass中的方法 printX()不可見(jiàn)
p.printX();
}
}
該HelloWorld.java文件與DefaultClass類(lèi)不在同一個(gè)包中,printX()是默認(rèn)訪(fǎng)問(wèn)級(jí)別,所以p.printX()方法無(wú)法編譯通過(guò)。
公有級(jí)別 {#-2}
公有級(jí)別的關(guān)鍵字是public,公有級(jí)別的成員變量和方法可以在任何場(chǎng)合被直接訪(fǎng)問(wèn),是最寬松的一種訪(fǎng)問(wèn)控制等級(jí)。
公有級(jí)別示例代碼如下:
// 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變量是公有級(jí)別,代碼第②行的方法也是公有級(jí)別。調(diào)用PublicClass類(lèi)代碼如下:
// 默認(rèn)包中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類(lèi)不在同一個(gè)包中,可以公有的printX()方法。
保護(hù)級(jí)別 {#-3}
保護(hù)級(jí)別的關(guān)鍵字是protected,保護(hù)級(jí)別在同一包中完全與默認(rèn)訪(fǎng)問(wèn)級(jí)別一樣,但是不同包中子類(lèi)能夠繼承父類(lèi)中的protected變量和方法,這就是所謂的保護(hù)級(jí)別,“保護(hù)”就是保護(hù)某個(gè)類(lèi)的子類(lèi)都能繼承該類(lèi)的變量和方法。
保護(hù)級(jí)別示例代碼如下:
// 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變量是保護(hù)級(jí)別,代碼第②行的方法也是保護(hù)級(jí)別。
在相同包(com.a51work6)中調(diào)用ProtectedClass類(lèi)代碼如下:
// 默認(rèn)包中HelloWorld.java文件
package com.a51work6;
import com.a51work6.ProtectedClass;
public class HelloWorld {
public static void main(String[] args) {
ProtectedClass p;
p = new ProtectedClass();
// 同一包中可以直接訪(fǎng)問(wèn)ProtectedClass中的方法 printX()
p.printX();
}
}
同一包中保護(hù)訪(fǎng)問(wèn)級(jí)別與默認(rèn)訪(fǎng)問(wèn)級(jí)別一樣,可以直接訪(fǎng)問(wèn)ProtectedClass的printX()方法,上述代碼可以編譯通過(guò)。
在不同的包中調(diào)用ProtectedClass類(lèi)代碼如下:
// 默認(rèn)包中HelloWorld.java文件
import com.a51work6.ProtectedClass;
public class HelloWorld {
public static void main(String[] args) {
ProtectedClass p;
p = new ProtectedClass();
// 編譯錯(cuò)誤,不同包中不能直接訪(fǎng)問(wèn)保護(hù)方法printX()
p.printX();
}
}
該HelloWorld.java文件與ProtectedClass類(lèi)不在同一個(gè)包中,不同包中不能直接訪(fǎng)問(wèn)保護(hù)方法printX(),所以p.printX()方法無(wú)法編譯通過(guò)。
在不同的包中繼承ProtectedClass類(lèi)代碼如下:
// 默認(rèn)包中SubClass.java文件
import com.a51work6.ProtectedClass;
public class SubClass extends ProtectedClass {
void display() {
//printX()方法是從父類(lèi)繼承過(guò)來(lái)
printX(); ①
//x實(shí)例變量是從父類(lèi)繼承過(guò)來(lái)
System.out.println(x); ②
}
}
不同包中SubClass從ProtectedClass類(lèi)繼承了printX()方法和x實(shí)例變量。代碼第①行是調(diào)用從父類(lèi)繼承下來(lái)的方法,代碼第②行是調(diào)用從父類(lèi)繼承下來(lái)的實(shí)例變量。
提示 訪(fǎng)問(wèn)成員有兩種方式:一種是調(diào)用,即通過(guò)類(lèi)或?qū)ο笳{(diào)用它的成員,如p.printX()語(yǔ)句;另一種是繼承,即子類(lèi)繼承父類(lèi)的成員變量和方法。
- 公有訪(fǎng)問(wèn)級(jí)別任何情況下兩種方式都可以;
- 默認(rèn)訪(fǎng)問(wèn)級(jí)別在同一包中兩種訪(fǎng)問(wèn)方式都可以,不能在包之外訪(fǎng)問(wèn);
- 保護(hù)訪(fǎng)問(wèn)級(jí)別在同一包中與默認(rèn)訪(fǎng)問(wèn)級(jí)別一樣,兩種訪(fǎng)問(wèn)方式都可以。但是在不同包之外只能繼承訪(fǎng)問(wèn);
- 私有訪(fǎng)問(wèn)級(jí)別只能在本類(lèi)中通過(guò)調(diào)用方法訪(fǎng)問(wèn),不能繼承訪(fǎng)問(wèn)。
提示 訪(fǎng)問(wèn)類(lèi)成員時(shí),在能滿(mǎn)足使用的前提下,應(yīng)盡量限制類(lèi)中成員的可見(jiàn)性,訪(fǎng)問(wèn)級(jí)別順序是:私有級(jí)別→默認(rèn)級(jí)別→保護(hù)級(jí)別→公有級(jí)別。
靜態(tài)變量和靜態(tài)方法
有一個(gè)Account(銀行賬戶(hù))類(lèi),假設(shè)它有三個(gè)成員變量:amount(賬戶(hù)金額)、interestRate(利率)和owner(賬戶(hù)名)。在這三個(gè)成員變量中,amount和owner會(huì)因人而異,對(duì)于不同的賬戶(hù)這些內(nèi)容是不同的,而所有賬戶(hù)的interestRate都是相同的。
amount和owner成員變量與賬戶(hù)個(gè)體有關(guān),稱(chēng)為“實(shí)例變量”,interestRate成員變量與個(gè)體無(wú)關(guān),或者說(shuō)是所有賬戶(hù)個(gè)體共享的,這種變量稱(chēng)為“靜態(tài)變量”或“類(lèi)變量”。
靜態(tài)變量和靜態(tài)方法示例代碼如下:
// Account.java文件
package com.a51work6;
public class Account {
// 實(shí)例變量賬戶(hù)金額
double amount = 0.0; ①
// 實(shí)例變量賬戶(hù)名
String owner; ②
// 靜態(tài)變量利率
static double interestRate = 0.0668; ③
// 靜態(tài)方法
public static double interestBy(double amt) { ④
//靜態(tài)方法可以訪(fǎng)問(wèn)靜態(tài)變量和其他靜態(tài)方法
return interestRate * amt; ⑤
}
// 實(shí)例方法
public String messageWith(double amt) { ⑥
//實(shí)例方法可以訪(fǎng)問(wèn)實(shí)例變量、實(shí)例方法、靜態(tài)變量和靜態(tài)方法
double interest = Account.interestBy(amt); ⑦
StringBuilder sb = new StringBuilder();
// 拼接字符串
sb.append(owner).append("的利息是").append(interest);
// 返回字符串
return sb.toString();
}
}
static修飾的成員變量是靜態(tài)變量,見(jiàn)代碼第③行。staitc修飾的方法是靜態(tài)方法,見(jiàn)代碼第④行。相反,沒(méi)有static修飾的成員變量是實(shí)例變量,見(jiàn)代碼第①行和第②行;沒(méi)有staitc修飾的方法是實(shí)例方法,見(jiàn)代碼第⑥行。
注意 靜態(tài)方法可以訪(fǎng)問(wèn)靜態(tài)變量和其他靜態(tài)方法,例如訪(fǎng)問(wèn)代碼第⑤行中的interestRate靜態(tài)變量。實(shí)例方法可以訪(fǎng)問(wèn)實(shí)例變量、其他實(shí)例方法、靜態(tài)變量和靜態(tài)方法,例如訪(fǎng)問(wèn)代碼第⑦行interestBy靜態(tài)方法。
調(diào)用Account代碼如下:
// HelloWorld.java文件
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
// 訪(fǎng)問(wèn)靜態(tài)變量
System.out.println(Account.interestRate); ①
// 訪(fǎng)問(wèn)靜態(tài)方法
System.out.println(Account.interestBy(1000)); ②
Account myAccount = new Account();
// 訪(fǎng)問(wèn)實(shí)例變量
myAccount.amount = 1000000; ③
myAccount.owner = "Tony"; ④
// 訪(fǎng)問(wèn)實(shí)例方法
System.out.println(myAccount.messageWith(1000)); ⑤
// 通過(guò)實(shí)例訪(fǎng)問(wèn)靜態(tài)變量
System.out.println(myAccount.interestRate); ⑥
}
}
調(diào)用靜態(tài)變量或靜態(tài)方法時(shí),可以通過(guò)類(lèi)名或?qū)嵗{(diào)用,代碼第①行Account.interestRate通過(guò)類(lèi)名調(diào)用靜態(tài)變量,代碼第②行Account.interestBy(1000)是通過(guò)類(lèi)名調(diào)用靜態(tài)方法。代碼第⑥行是通過(guò)實(shí)例調(diào)用靜態(tài)變量。
靜態(tài)代碼塊
前面介紹的靜態(tài)變量interestRate,可以在聲明同時(shí)初始化,如下代碼所示。
public class Account {
// 靜態(tài)變量利率
static double interestRate = 0.0668;
...
}
如果初始化靜態(tài)變量不是簡(jiǎn)單常量,需要進(jìn)行計(jì)算才能初始化,可以使用靜態(tài)(static)代碼塊,靜態(tài)代碼塊在類(lèi)第一次加載時(shí)執(zhí)行,并只執(zhí)行一次。示例代碼如下:
// Account.java文件
package com.a51work6;
public class Account {
// 實(shí)例變量賬戶(hù)金額
double amount = 0.0;
// 實(shí)例變量賬戶(hù)名
String owner;
// 靜態(tài)變量利率
static double interestRate;
// 靜態(tài)方法
public static double interestBy(double amt) {
// 靜態(tài)方法可以訪(fǎng)問(wèn)靜態(tài)變量和其他靜態(tài)方法
return interestRate * amt;
}
// 靜態(tài)代碼塊
static { ①
System.out.println("靜態(tài)代碼塊被調(diào)用...");
// 初始化靜態(tài)變量
interestRate = 0.0668; ②
}
}
上述代碼第①行是靜態(tài)代碼塊,在靜態(tài)代碼塊中可以初始化靜態(tài)變量,見(jiàn)代碼第②行,也可以調(diào)用靜態(tài)方法。
調(diào)用Account代碼如下:
// HelloWorld.java文件
package com.a51work6;
public class HelloWorld {
public static void main(String[] args) {
Account myAccount = new Account(); ①
// 訪(fǎng)問(wèn)靜態(tài)變量
System.out.println(Account.interestRate); ②
// 訪(fǎng)問(wèn)靜態(tài)方法
System.out.println(Account.interestBy(1000));
}
}
Account靜態(tài)代碼塊是在第一次加載Account類(lèi)時(shí)調(diào)用。上述代碼第①行是第一次使用Account類(lèi),此時(shí)會(huì)調(diào)用靜態(tài)代碼塊。
本章小結(jié)
本章主要介紹了面向?qū)ο蠡A(chǔ)知識(shí)。首先介紹了面向?qū)ο笠恍┗靖拍?,面向?qū)ο笕齻€(gè)基本特性。然后介紹了類(lèi)、包、方法重載和訪(fǎng)問(wèn)控制。最后介紹了靜態(tài)變量、靜態(tài)方法和靜態(tài)代碼塊。
配套視頻
http://www.zhijieketang.com/classroom/6/courses
配套源代碼
http://www.zhijieketang.com/group/5