java隐藏方式运行,Java 数据隐藏和封装
類由一些數據和方法組成。最重要的面向對象技術之一是,是把數據隱藏再類中,只能通過方法獲取。這種技術叫作 封裝(encapsulation),因為它可以把數據(和內部方法)安全的密封在這個“容器”中,只能由可信的用戶(即這個類中的方法)訪問。
為什么要這么做呢?最重要的原因是,隱藏類的內部實現細節。如果避免讓程序員依賴這些細節,你就可以放心的修改實現,而無需擔心會破壞使用這個類的現有代碼。
你應該始終封裝自己的代碼。如果沒有封裝好,那么幾乎無法推知并最終確
認代碼是否正確,尤其是在多線程環境中(而基本上所有 Java 程序都運行在
多線程環境中)。
使用封裝的另一個原因是保護類,避免有意或無意做了糊涂事。類中經常包含一些相互依
賴的字段,而且這些字段的狀態必須始終如一。如果允許程序員(包括你自己)直接操作
這些字段,修改某個字段后可能不會修改重要的相關字段,那么類的狀態就前后不一致
了。然而,如果必須調用方法才能修改字段,那么這個方法可以做一切所需的措施,確保
狀態一致。類似地,如果類中定義的某些方法僅供內部使用,隱藏這些方法能避免這個類
的用戶調用這些方法。
封裝還可以這樣理解:把類的數據都隱藏后,方法就是在這個類的對象上能執行的唯一一
種可能的操作。
只要小心測試和調試方法,就可以認為類能按預期的方式運行。然而,如果類的所有字段
都可以直接操作,那么要測試的可能性根本數不完。
隱藏類的字段和方法還有一些次要的原因。
如果內部字段和方法在外部可見,會弄亂類的 API。讓可見的字段盡量少,可以保持類的整潔,從而更易于使用和理解。
如果方法對類的使用者可見,就必須為其編寫文檔。把方法隱藏起來,可以節省時間和
精力。
訪問控制
Java 定義了一些訪問控制規則,可以禁止類的成員在類外部使用。
這個 public 關鍵字,連同 protected
和 private(還有一個特殊的),是 訪問控制修飾符,為字段或方法指定訪問規則。
訪問包
Java 語言不直接支持包的訪問控制。訪問控制一般在類和類的成員這些層級完成。
已經加載的包始終可以被同一個包中的代碼訪問。一個包在其他包中是否
能訪問,取決于這個包在宿主系統中的部署方式。例如,如果組成包的類
文件存儲在一個目錄中,那么用戶必須能訪問這個目錄和其中的文件才能
訪問包。
訪問類
默認情況下,頂層類在定義它的包中可以訪問。不過,如果頂層類聲明為 public,那么在
任何地方都能訪問。
訪問成員
類的成員在類的主體里始終可以訪問。默認情況下,在定義這個類的包中也可以訪問成員。這種默認的訪問等級一般叫作包訪問。
這只是四個可用的訪問等級中的一個。其他
三個等級使用 public、protected 和 private 修飾符定義。下面是使用這三個修飾符的示例代碼:
public class Laundromat { // 所有人都可以使用這個類
private Laundry[] dirty; // 不能使用這個內部字段
public void wash() { ... } // 但能使用這兩個公開的方法
public void dry() { ... } // 處理內部字段
// 子類可能會想調整這個字段
protected int temperature;
}
下述訪問規則適用于類的成員:
類中的所有字段和方法在類的主體里始終可以使用。
如果類的成員使用 public 修飾符聲明,那么可以在能訪問這個類的任何地方訪問這個成員。這是限制最松的訪問控制類型。
如果類的成員聲明為 private,那么除了在類內部之外,其他地方都不能訪問這個成員。
這是限制最嚴的訪問控制類型。
如果類的成員聲明為 protected,那么包里的所有類都能訪問這個成員(等同于默認的
包訪問規則),而且在這個類的任何子類的主體中也能訪問這個成員,而不管子類在哪
個包中定義。
如果聲明類的成員時沒使用任何修飾符,那么使用默認的訪問規則(有時叫包訪問),
包中的所有類都能訪問這個成員,但在包外部不能訪問。
默認的訪問規則比 protected 嚴格,因為默認規則不允許在包外部的子類中
訪問成員。
使用 protected 修飾的成員時要格外小心。假設 A 類使用 protected 聲明了一個字段 x,而
且在另一個包中定義的 B 類繼承 A 類(重點是 B 類在另一包中定義)。因此,B 類繼承了這
個 protected 聲明的字段 x,那么,在 B 類的代碼中可以訪問當前實例的這個字段,而且
引用 B 類實例的代碼也能訪問這個字段。但是,這并不意味著在 B 類的代碼中能讀取任何
一個 A 類實例的受保護字段。
示例如下:
A類的定義如下:
package javanut6.ch03;
public class A {
protected final String name;
public A(String named) {
name = named;
}
public String getName() {
return name;
}
}
B類的定義如下:
package javanut6.ch03.different;
import javanut6.ch03.A;
public class B extends A {
public B(String named) {
super(named);
}
@Override
public String getName() {
return "B: " + name;
}
}
Java 的包不能“嵌套”,所以 javanut6.ch03.different 和 javanut6.ch03
是不同的包。javanut6.ch03.different 不以任何方式包含在 javanut6.
ch03 中,也和 javanut6.ch03 沒有任何關系。
可是,如果我們試圖把下面這個新方法添加到 B 類中,會導致編譯出錯,因為 B 類的實例無法訪問任何一個 A 類的實例(只能訪問字段):
public String examine(A a) {
return "B sees: " + a.name;
}
如果把這個方法改成:
public String examine(B b) {
return "B sees another B: " + b.name;
}
就能編譯通過,因為同一類型的多個實例可以訪問各自的 protected 字段。當然,如果 B
類和 A 類在同一包中,那么任何一個 B 類的實例都能訪問任何一個 A 類實例的全部受保護字段,因為使用 protected 聲明的字段對同一個包中的每個類都可見。
訪問控制和繼承
Java規范規定:
子類繼承超類中所有可以訪問的示例字段和示例方法;
如果子類和超類在同一個包中定義,那么子類繼承所有沒使用 private 聲明的實例字段和方法。
如果子類在其包中定義,那么它繼承所有使用 protected 和 public 聲明的實例字段和方法。
使用 private 聲明的字段和方法絕不會被繼承;類字段和類方法也一樣;
構造方法不會被繼承(而是鏈在一起調用)
不過,有些程序員會對“子類不繼承超類中不可訪問的字段和方法”感到困惑。這似乎暗
示了,創建子類的實例時不會為超類中使用 private 聲明的字段分配內存。然而,這不是上述規定想表述的。其實,子類的每個實例都包含一個完整的超類實例,其中包括所有不可訪問
的字段和方法。
那么,關于成員訪問性的正確表述應該是:“所有繼承的成員和所有在類中定義的成員都
是可以訪問的。”這句話還可以換種方式說:
類繼承超類的所有實例字段和實例方法(但不繼承構造方法);
在類的主體中始終可以訪問這個類定義的所有字段和方法,而且還可以訪問繼承自超類的可訪問的字段和方法。
成員訪問規則總結
下面是一些使用可見性修飾符的經驗法則:
只使用 public 聲明組成類的公開API的方法和常量。使用 public 聲明的字段只能是常量和不能修改的對象,而且必須同時使用 final 聲明。
使用 protected 聲明大多數使用這個類的程序員不會用到的字段和方法,但在其他包中定義子類時可能會用到。
如果字段和方法供類的內部實現細節使用,但是同一個包中協作的類也要使用,那么就使用默認的包可見性。
使用 private 聲明旨在類內部使用,在其他地方都要隱藏的字段和方法。
嚴格來說,使用 protected 聲明的成員是類公開 API 的一部分,必須為其編
寫文檔,而且不能輕易修改,以防破壞依賴這些成員的代碼。
如果不確定該使用 protected、包還是 private 可見性,那么先使用 private。如果太過嚴
格,可以稍微放松訪問限制(如果是字段的話,還可以提供訪問器方法)。
設計 API 時這么做尤其重要,因為提高訪問限制是不向后兼容的改動,可能會破壞依賴成員訪問性的代碼。
數據訪問器方法
Circle 類的這個版本使用 protected 聲明 r 字段,還定義了訪問器方法 getRadius() 和
setRadius(),用于讀寫這個字段的值,而且限制半徑不能為負數。r 字段使用 protected
聲明,所以可以在子類中直接(且高效地)訪問。使用數據隱藏和封裝技術定義的 Circle 類。
package shapes; // 為這個類指定一個包
public class Circle { // 這個類還使用public聲明
// 這是通用的常量,所以要保證聲明為public
public static final double PI = 3.14159;
protected double r; // 半徑被隱藏了,但在子類中可見
// 限制半徑取值的方法
// 這是子類可能感興趣的實現細節
protected void checkRadius(double radius) {
if (radius < 0.0)
throw new IllegalArgumentException("radius may not be negative.");
}
// 非默認的構造方法
public Circle(double r) {
checkRadius(r);
this.r = r;
}
// 公開的數據訪問器方法
public double getRadius() { return r; }
public void setRadius(double r) {
checkRadius(r);
this.r = r;
}
// 操作實例字段的方法
public double area() { return PI * r * r; }
public double circumference() { return 2 * PI * r; }
}
我們在一個名為 shapes 的包中定義 Circle 類。因為 r 字段使用 protected 聲明,所以
shapes 包中的任何其他類都能直接訪問這個字段,而且能把它設為任何值。這里假設
shapes 包中的所有類都由同一個作者或者協作的多個作者編寫,而且包中的類相互信任,
不會濫用擁有的訪問權限影響彼此的實現細節。
最后,限制半徑不能使用負數的代碼在一個使用 protected 聲明的方法中,這個方法是
checkRadius()。雖然 Circle 類的用戶無法調用這個方法,但這個類的子類可以調用,而
且如果想修改對半徑的限制,還可以覆蓋這個方法。
在 Java 中,數據訪問器方法的命名有個通用約定,即以“get”和“set”開
頭。但是,如果要訪問的字段是 boolean 類型,那么讀取字段的方法使用的
名稱可能會以“is”開頭。例如,名為 readable 的 boolean 類型字段對應的
訪問器方法是 isReadable() 而不是 getReadable()。
總結
以上是生活随笔為你收集整理的java隐藏方式运行,Java 数据隐藏和封装的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: yii2 引入php文件,Yii2中Yi
- 下一篇: php读取屏幕大小,jQuery 获取屏