標籤:可變 field writer tar xtend end lis 結構 階層
1.使類和成員的可訪問性最小化
a.封裝(資料私人化,方法公開化)/對外提供可調用的,穩定的功能
b.可訪問性應該明確
| 修飾符 |
本類 |
同包類 |
子類 |
其他類 |
| public |
√ |
√ |
√ |
√ |
| protected |
√ |
√ |
√ |
|
| 預設 |
√ |
√ |
|
|
| private |
√ |
|
|
|
c.執行個體域絕不能是公有的
d.例子
- FieldPublicTest
- Point/Dimension
e.包級私人的頂級類只在某一個類內部被用到,就可以使用成為它的嵌套類
2.使可變性最小化(不可變對象)
a.遵循規則
1. 不要提供任何會修改對象狀態的方法
2. 保證類不會被擴充
3. 所有域都要是final,且為私人
4. 確保對於任何可變組件的互斥訪問。
b.優點
1. 安全執行緒
不可變對象是安全執行緒的,線上程之間可以相互共用,不需要利用特殊機制來保證同步問題,因為對象的值無法改變。
2. 易於構造、使用和測試
不可變對象為其他對象提供了大量的構件
c.缺點
1. 需要為每一個不同的值提供不同的對象。如果建立的對象比較大,那麼所產生的代價就有點高了
2. String -> StringBuilder(可變更配置套類)
d.總結
1. 堅決不要為每個get方法編寫一個相應的set方法
e.例子
-- ComplexTest
3.複合優先於繼承
a.原因
1. 繼承打破了封裝性。子類信賴於其超類中特定功能的實現細節。超類的實現有可能會隨著發行版本的不同而有變化,子類有可能會被破壞
Stack/
b.複合優點
1. 不破壞封裝,整體類與局部類之間松耦合,彼此相對獨立
2. 具有較好的可擴充性
3. 支援動態組合。在運行時,整體對象可以選擇不同類型的局部對象
4. 整體類可以對局部類進行封裝,封裝局部類的介面,提供新的介面
c.複合缺點
1. 整體類不能自動獲得和局部類同樣的介面
2. 建立整體類的對象時,需要建立所有局部類的對象
d.總結
1. 只有當子類和父類確實存在子類型關係時,使用繼承才是恰當的
2. 繼承會把父類所有的缺陷繼承過來
3. 複合是has a, 繼承是is a。
e.例子
-- ForwardTest
4.要麼為繼承而設計,提供文檔說明,要麼禁止繼承
a. 注意父類中各方法之間的相互調用,特別是可被覆蓋的方法。一定要在文檔中說明其自用性。(Interator的remove方法)
b. 類必須提供適當的鉤子,以便能進入到它的內部工作流程中。可以是受保護的方法,也可以是受保護的域。(AbstractList的removeRange)
c. 對於為了繼承而設計的類,唯一的測試方法就是編寫子類。經驗表明,三個子類通常可以測試一個可擴充的類。
d. 構造器、靜態Factory 方法和其他具有構造對象功能的方法決不能調用可被覆蓋的方法(例子:)
e. 為了繼承而設計類的時候,Cloneable和Serializable介面出現了特殊的困難。(readResolve應是受保護的方法)
f. 通過完全消除類中的可覆蓋方法的自用特性,也可以建立”能夠安全地進行子類化“的類。(文檔說明/不會調用可覆蓋的方法)
5.介面優先於抽象類別
a.優點
1. 現有類可以很容易的實現更新,通過實現新的介面
2. 介面是定義混合類型的理想選擇
3. 介面允許我們構造非階層的類型架構
1 public interface Songer{2 void song();3 }4 public interface SongWriter{5 Song writeSong();6 }7 pulbic interface SongerWriter extends Songer,SongWrite{8 void act();9 }
b.缺點
1. 在版本演變中很難通過新添加介面方法進行功能添加,但是抽象類別可以很輕鬆搞定這種事
c.總結
1. 當演變的容易性比比靈活性和功能性更為重要時,應該用抽象類別定義類型
6.介面只用於定義類型
a. 常量介面模式是對介面的不良使用。
b. 會導致使用者對介面含義的模糊,而且使用選擇了實現該介面,那麼後續不在需要這些常量的時候,我們不能刪除該介面。(二進位相容性)
1 public interface EarthConstants{2 double EARTH_RADIUS = XXXXX.XXXXX;3 }4 5 public final class EarthConstants{6 private EarthConstants(){}7 public static final double EARTH_RADIUS = XXXXX.XXXXX;8 }
7.類層次優先於標籤類
a. 標籤類過於冗長、容易出錯,並且效率低下。
b. 類層次邏輯清晰,便於維護
8.用函數對象表示策略
a. 利用對象引用實現函數指標的功能,可以實現策略模式。
9.優先考慮靜態成員類
a.原因
1.非靜態成員類的每個執行個體都隱含著與外圍類的一個外圍執行個體想關聯。在其被建立時,關聯關係也建立了,這個關係不能被修改了。
b.優點
1. 內部類包括:成員類、局部類、匿名類。
2. 靜態類不能訪問外部類的非靜態成員和非靜態方法(不管是public還是private的);
3. 靜態類的執行個體不需要先執行個體化外部類成員,可直接執行個體化。
c.成員類、局部類、匿名類
-- 成員類
0. 從技術上來說,可以分為兩種:成員內部類和成員嵌套類。
1. 成員內部類即這裡說的成員類,全稱是非靜態成員內部類
2. 成員嵌套類即上面的靜態嵌套類
3. 可以直接調用外部類的方法
4. 定義一個Adapter,他允許外部類的執行個體被看作是另一個不相關的類的執行個體(Map中的KeySet、entrySet)
1 public class Main{2 public class MemberClass{}//成員內部類,常簡稱為成員類3 }
-- 局部類
1. 任何可以聲明局部變數的地方都可聲明局部類
2. 只有在非靜態環境中使用才會與外部類執行個體關聯
3. 注意到了吧,可以同名,編譯後,形成諸如:外部類名稱+$+同名順序+局部類名稱(Test$1AA.class/Test$2AA.class/Test$3AA.class)
public class Test { { class AA{ // 塊內局部類 }}public Test(){ class AA{ // 構造器內局部類 }}public static void main(String[] args){}public void test(){ class AA{ // 方法內局部類 }}}
-- 匿名類(成員匿名類/局部匿名類)
1. 沒有類名,不能使用繼承,實現介面等特性
2. 只有在使用的時候才會初始化,並與外部類執行個體建立聯絡
3. 可以出現在代碼中的任何允許運算式出現地方
4. 必須保持簡短才能保證程式良好的閱讀性
5. 常見使用:建立對象過程:Thead、Runnable,靜態Factory 方法內部
public class Test { InterfaceA a = new InterfaceA() { //成員匿名類};public static void main(String[] args){ InterfaceA a = new InterfaceA() { //局部匿名類};// 以上兩種是通過實現介面實現匿名類,稱為介面式匿名類,也可以通過繼承類Test test = new Test(){}; //繼承式匿名類// 還可以是位於參數上new Thread(new Runnable() {@Overridepublic void run() {}}).start();// 屬於局部匿名類一種}private interface InterfaceA{}}
d.總結
1. 成員類:位於類內部但不包括位於塊、構造器、方法內,且有名稱的類。
2. 局部類:位於塊、構造器、方法內的有名稱類。
3. 匿名類:類內無名稱類,又可細分為:成員匿名類和局部匿名類。
【讀後感】《effective java》類和對象