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