Java性能优化(12):最小化类和成员可访问能力
類和接口是Java程序設計語言的核心,它們也是Java語言的基本抽象單元。Java語言提供了許多強大的基本元素,供程序猿來設計類和接口。
要想?yún)^(qū)別一個設計良好的模塊與一個設計不好的模塊,最重要的因素是,這個模塊對于外部其他模塊而言,是否隱藏了內(nèi)部的數(shù)據(jù)和其他的實現(xiàn)細節(jié)。一個設計良好的模塊會隱藏所有的實現(xiàn)細節(jié),把它的API與實現(xiàn)清晰的隔離開來。然后,模塊之間只通過它們的API進行通信,一個模塊不需要知道其他模塊內(nèi)部的工作情況,也就是所謂的封裝。
封裝之所以非常重要有許多理由,其中大多數(shù)理由都源于這樣一個事實:它可以有效地解除一個系統(tǒng)中各模塊之間的耦合關系,使得這些模塊可以被獨立地開發(fā)、測試、優(yōu)化、使用、理解和修改。這樣可以加速系統(tǒng)開發(fā)的速度,因為這些模塊可以被并行地開發(fā)。它也減輕了維護的負擔,因為程序員很快就可以理解這些模塊,并且在調(diào)試它們的時候可以不傷害其他的模塊。雖然封裝本身無論是對內(nèi)還是對外,都不會帶來更好的性能,但是它使得有效的性能調(diào)節(jié)成為可能。一旦一個系統(tǒng)已經(jīng)完成,通過分析就可以知道哪些模塊影響了系統(tǒng)的性能,那么這些模塊可以被進一步優(yōu)化,而不會影響到其他模塊的正確性。封裝可以提高軟件的可重用性,因為單獨的模塊并不依賴于其他的模塊,除了開發(fā)這些模塊所使用的環(huán)境之外,它們在其他環(huán)境中往往是有用。最后,封裝也降低了構建大型系統(tǒng)的風險;即使整個系統(tǒng)并不成功,這些獨立模塊也有可能是成功的。
Java程序設計語言提供了許多設施來幫助坐到信息隱藏。其中一個設施是訪問控制機制,它決定了類、接口和成員的可訪問性。
一個實體的可訪問性是由該實體聲明所在的位置,以及該實體聲明中所出現(xiàn)的訪問修飾符公同決定的。正確地使用這些修飾符對于實現(xiàn)封裝是非常關鍵的。
經(jīng)驗表明,你應該盡可能地使每一個類或成員不被外界訪問。換句話說,你應該使用時最低可能的、并且與該軟件的正確功能相一致的訪問級別。
對于頂層的類和接口,它們只有兩種可能的訪問級別:包級私有的和公有的。如果你聲明了一個具有public修飾符的頂層類或者接口,那么它是公有的;否則,它將是包級私有的。如果一個類或者接口能被做成包級私有的,那么它就應該被做成包級私有的。通過把一個類或接口做成包級私有的,它實際上成了這個包的實現(xiàn)的一部分,而不是該包導出API的一部分;并且,在以后的發(fā)行版本中,你可以對它進行修改、替換,或者去除,而無需擔心會傷害到現(xiàn)有的客戶。如果你把它做成公有的,你就有義務永遠支持它,以保持兼容性。
如果一個包級私有的頂層類或接口只是在某一個類的內(nèi)部被用到,那么你應該考慮使它成為后者的一個私有嵌套類。這樣可以進一步降低它的可訪問性,然而,這樣做不像”使一個不必要的共公有類成為包級私有的類”那樣重要,因為一個包級私有的類已經(jīng)是這個包的實現(xiàn)的一部分,而不是其API的一部分。
對于成員有四種可能訪問級別,下面按照可訪問性遞增的順序列出來:
私有的——只有在聲明該成員的頂層類內(nèi)部才可以訪問這個成員
包級私有的——聲明該成員的包內(nèi)部的任何類都可以訪問這個成員。在技術上,它被稱為”默認訪問級別”,如果沒有為成員指定訪問修飾符的話,那么它就具有這樣的訪問級別。
受保護的——該成員聲明所在類的子類可以訪問這個成員,并且,該成員聲明所在的包內(nèi)部的任何類也可以訪問這個成員。
公有的——任何地方都可以訪問該成員。
當你仔細地設計了一個類的公有API之后,接下去應該把所有其他的成員都變成私有的。只有當同一個包內(nèi)的另一個類真正需要訪問一個成員的時候,你才應該去掉private修飾符,使該成員變成包級私有的。如果你發(fā)現(xiàn)自己經(jīng)常要做這樣的事情,那么你應該重新檢查你的系統(tǒng)設計,看看是否另一種分解方案所得到的類具有更好的分離特性,彼此之間耦合度更小。可以這樣說,私有成員和包級私有成員都是一個類實現(xiàn)中的一部分,并不會影響到其導出的API。然而,如果這些域所在類是實現(xiàn)了Serializable接口,那么這些域可能會被”泄露”其導出的API中。
對于公有類的成員,當訪問級別從包級私有變成保護級別時,會出現(xiàn)可訪問性的巨大增加。受保護成員是一個類導出API的一部分,必須永遠被支持。更進一步,一個導出的類的每一個受保護成員代表了該類對于一個實現(xiàn)細節(jié)的公開承諾。受保護的成員應該盡量少用。
有一條規(guī)則使得你無法降低一個方法的可訪問性。如果一個方法改寫了超類中的一個方法,那么子類中該方法的訪問級別低于超類中的訪問級別時不允許的。這樣可以確保子類實例可以被用在任何可使用超類的實例的場合。如果你違反了這條規(guī)則,那么當你試圖編譯該子類的時候,編譯器會產(chǎn)生一條錯誤信息。這條規(guī)則的一種特殊情形是,如果一個類實現(xiàn)了一個接口,那么接口中所有的方法在這個類中都必須被聲明為公有的。這是因為接口中所有方法都隱含著公有訪問級別。
公有類應該盡可能地包含公有的域。如果一個域是非final的,或者是一個指向可變對象的final引用,那么你一旦使它成為公有的,就放棄了對存儲在這個域中的值進行限制的能力;當這個域被修改的時候,你也失去了采取任何行動的能力。一個簡單的后果是,包含公有可變域的類不是線程安全地的。即使一個域是final的,并沒有指向任何一個可變對象,那么,一旦你把這個域變成公有的,也就放棄了“切換到一個新的內(nèi)部數(shù)據(jù)表示”的靈活性。
對于“公有類不應該包含公有域”這條規(guī)則也有一個例外,通過公有的靜態(tài)final域來暴露類的常量是允許的。按照慣例,這樣域的名字由大寫字母組成,單詞之間用下劃線隔開。很重要的一點是,這些域要么包含原語類型的值,要么包含指向非可變對象的引用。如果一個final域包含一個指向可變對象的引用,那么它具有非final域的所有缺點。雖然引用本身不能被修改,但是它引用的對象可以被修改——這會導致災難性的后果。
注意,非零長度的數(shù)組總是可變的,所以,具有公有的靜態(tài)final數(shù)組域幾乎總是錯誤的。如果一個類包含這樣的一個域,客戶將能夠修改數(shù)組中的內(nèi)容。這是安全漏洞中的一個常見根源:
public static final Type[] VALUES = {...}; private static final Type[] PRIVATE_VALUES ={...}; public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));另一種辦法是,如果你要求編譯時的類型的安全性,并且愿意損失一點性能的話,你可以把公有的數(shù)組替換成一個公有的辦法,它返回私有數(shù)組的一份拷貝:
private static final Type [] PRIVATE_VALUES = {...}; public static final Type [] values(){ return (Type[])PRIVATE_VALUES.clone(); }總之,你應該總會可能地降低可訪問性,再仔細設計了一個最小的公有API之后,應該防止把任何雜散的類、接口和成員變成API的一部分。除了公有靜態(tài)final域的特殊情形之外,公有類不應該包含公有域。并且確保公有靜態(tài)final域所引用對象是不可變的。
轉載于:https://www.cnblogs.com/ainima/p/6331825.html
總結
以上是生活随笔為你收集整理的Java性能优化(12):最小化类和成员可访问能力的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用IB_DESIGNABLE与IBIn
- 下一篇: Java -Inverse covari