《Java從小白到大牛》之第10章 面向對象基礎(下)

《Java從小白到大牛》紙質版已經上架了!!!
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

與本書免費版對應的還有一個收費版本:

  1. 進入百度閱讀電子書

  2. 進入圖靈社區電子書
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章