標籤:protected 計算 view subclass 完全 prot 賬戶 關鍵字 不能
《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檔案調用PrivateClasspackage 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
與本書免費版對應的還有一個收費版本:
進入百度閱讀電子書
- 進入圖靈社區電子書
《Java從小白到大牛》之第10章 物件導向基礎(下)