越來越發現這是一本難得的好書,Java程序員不看這本書的話真是很遺憾。本章講述的是類和接口相關的問題。這幾個Item都非常重要.
Item 12:把類和成員的可訪問范圍降到最低
好的模塊設計應該盡最大可能封裝好自己的內部信息,這樣可以把模塊之間的耦合程度降到最低。開發得以并行,無疑這將加快開發的速度,便于系統地維護。Java中通過訪問控制符來解決這個問題。
- public表示這個類在任何范圍都可用。
- protected表示只有子類和包內的類可以使用
- private-package(default)表示在包內可用
- private表示只有類內才可以用
你在設計一個類的時候應該盡量的按照4321得順序設計。如果一個類只是被另一個類使用,那么應該考慮把它設計成這個類的內部類。通常public的類不應該有public得字段,不過我們通常會用一個類來定義所有的常量,這是允許的。不過必須保證這些字段要么是基本數據類型要么引用指向的對象是不可修改的。不然他們將可能被修改。例如下面的定義中data就是不合理的,后面兩個沒有問題。
public class Con
{
public static final int[] data = {1,2,3};// it is bad
public static final String hello = "world";
public static final int i = 1;
}
Item 13:不可修改的類更受青睞
不可修改的類意思是他們一經創建就不會改變,例如String類。他們的設計、實現都很方便,安全性高——它們是線程安全的。設計不可修改類有幾點規則:
- 不要提供任何可以修改對象的方法
- 確保沒有方法能夠被覆蓋,可以通過把它聲明為final
- 所有字段設計成final
- 所有字段設計成private
- 確保外部不能訪問到類的可修改的組件
不可修改類也有個缺點就是創建不同值得類的時候要創建不同的對象,String就是這樣的。通常有個解決的辦法就是提供一個幫助類來彌補,例如StringBuffer類。
Item 14:化合(合成)比繼承更值得考慮
實現代碼重用最重要的辦法就是繼承,但是繼承破壞了封裝,導致軟件的鍵壯性不足。如果子類繼承了父類,那么它從父類繼承的方法就依賴父類的實現,一旦他改變了會導致不可預測的結果。作者介紹了InstrumentedHashSet作為反例進行說明,原因就是沒有明白父類的方法實現。作者給出的解決辦法是通過化合來代替繼承,用包裝類和轉發方法來解決問題。把想擴展的類作為本類的一個private final得成員變量。把方法參數傳遞給這個成員變量并得到返回值。這樣做的缺點是這樣的類不適合回掉框架。繼承雖然好,我們卻不應該濫用,只有我們能確定它們之間是is-a得關系的時候才使用。
Item 15:如果要用繼承那么設計以及文檔都要有質量保證,否則就不要用它
為了避免繼承帶來的問題,你必須提供精確的文檔來說明覆蓋相關方法可能出現的問題。在構造器內千萬不要調用可以被覆蓋的方法,因為子類覆蓋方法的時候會出現問題。
import java.util.*;
public class SubClass extends SuperClass
{
private final Date date;
public SubClass()
{
date = new Date();
}
public void m()
{
System.out.println(date);
}
public static void main(String[] args)
{
SubClass s = new SubClass();
s.m();
}
}
class SuperClass
{
public SuperClass()
{
m();
}
public void m()
{
}
}
由于在date被初始化之前super()已經被調用了,所以第一次輸出null而不是當前的時間。
由于在Clone()或者序列化的時候非常類似構造器的功能,因此readObject()和clone()方法內最好也不要包括能被覆蓋的方法。
Item 16:在接口和抽象類之間優先選擇前者
接口和抽象類都用來實現多態,不過我們應該優先考慮用接口。知道嗎?James說過如果要讓他重新設計java的話他會把所有都設計成接口的。抽象類的優點是方便擴展,因為它是被繼承的,并且方法可以在抽象類內實現,接口則不行。
Item 17:接口只應該用來定義類型
接口可以這樣用的 Collection c = new xxxx();這是我們最常用的。不要把接口用來做其他的事情,比如常量的定義。你應該定義一個類,里面包含public final static 得字段。
Item 18: 在靜態和非靜態內部類之間選擇前者
如果一個類被定義在其他的類內部那么它就是嵌套類,可以分為靜態內部類、非靜態內部類和匿名類。
static member class 得目的是為enclosing class服務,如果還有其他的目的,就應該把它設計成top-level class。nonstatic member class是和enclosing class instance關聯的,如果不需要訪問enclosing class instance的話應該把它設計成static得,不然會浪費時間和空間。anonymous class是聲明和初始化同時進行的。可以放在代碼的任意位置。典型應用是Listener 和process object例如Thread。