私有成員,即私有方法、域和類型這些概念的幕后思想是它們只是實現(xiàn)細節(jié):一個類的實現(xiàn)者可以隨意地添加一個新的私有成員,或者修改和移除一個舊的私有成員,而不需要擔心對該類的客戶造成任何損害。換句話說,私有成員被包含它們的類完全封裝了。
遺憾的是,在這種嚴密的盔甲保護中仍然存在細小的裂縫。例如,序列化就可以打破這種封裝。如果使一個類成為可序列化的,并且接受缺省的序列化形式,那么該類的私有實例域?qū)⒊蔀槠鋵С鯝PI的一部分[EJ Item 54,55]。當客戶正在使用現(xiàn)有的被序列化對象時,對私有表示的修改將會導致異常或者是錯誤的行為。
但是編譯期的錯誤又會怎么樣呢?你能否寫出一個final的“庫”類和“客戶”類,這兩者都可以毫無問題地通過編譯,然后在庫類中添加一個私有成員,使得庫類仍然能夠編譯,而客戶類卻再也不能編譯了?
如果你的解謎方案是要對庫類添加一個私有構(gòu)造器,以抑制通過缺省的公共構(gòu)造器而創(chuàng)建實例的行為,那么你只是一知半解。本謎題要求你添加一個私有成員,嚴格地講,構(gòu)造器不是成員[JLS 6.4.3]。
本謎題有數(shù)個解謎方案,其中一個是使用遮蔽:
package library;
public final class Api {
// private static class String{ }
public static String newString() {
return new String();
}
}
package client;
import library.Api;
public class Client {
String s = Api.newString();
}
如上編寫,該程序就可以毫無問題地通過編譯。如果我們不注釋掉library.Api中的局部類String的私有聲明,那么Api.newString方法就再也不會返回java.lang.String類型了,因此變量Client.s的初始化將不能通過編譯:
client/Client.java:4: incompatible types
found: library.Api.String, required: java.lang.String
String s = Api.newString();
^
盡管我們所做的文本修改僅僅是添加了一個私有類聲明,但是我們間接地修改了一個現(xiàn)有公共方法的返回類型,而這是一個不兼容的API修改,因為我們修改了一個被導出API所使用的名字的含義。
遺憾的是,在這種嚴密的盔甲保護中仍然存在細小的裂縫。例如,序列化就可以打破這種封裝。如果使一個類成為可序列化的,并且接受缺省的序列化形式,那么該類的私有實例域?qū)⒊蔀槠鋵С鯝PI的一部分[EJ Item 54,55]。當客戶正在使用現(xiàn)有的被序列化對象時,對私有表示的修改將會導致異常或者是錯誤的行為。
但是編譯期的錯誤又會怎么樣呢?你能否寫出一個final的“庫”類和“客戶”類,這兩者都可以毫無問題地通過編譯,然后在庫類中添加一個私有成員,使得庫類仍然能夠編譯,而客戶類卻再也不能編譯了?
如果你的解謎方案是要對庫類添加一個私有構(gòu)造器,以抑制通過缺省的公共構(gòu)造器而創(chuàng)建實例的行為,那么你只是一知半解。本謎題要求你添加一個私有成員,嚴格地講,構(gòu)造器不是成員[JLS 6.4.3]。
本謎題有數(shù)個解謎方案,其中一個是使用遮蔽:
package library;
public final class Api {
// private static class String{ }
public static String newString() {
return new String();
}
}
package client;
import library.Api;
public class Client {
String s = Api.newString();
}
如上編寫,該程序就可以毫無問題地通過編譯。如果我們不注釋掉library.Api中的局部類String的私有聲明,那么Api.newString方法就再也不會返回java.lang.String類型了,因此變量Client.s的初始化將不能通過編譯:
client/Client.java:4: incompatible types
found: library.Api.String, required: java.lang.String
String s = Api.newString();
^
盡管我們所做的文本修改僅僅是添加了一個私有類聲明,但是我們間接地修改了一個現(xiàn)有公共方法的返回類型,而這是一個不兼容的API修改,因為我們修改了一個被導出API所使用的名字的含義。

