2008-10-25 77 views
2

我正在重讀Effective Java(第2版)第18項prefer interfaces to abstract classes。在該項目喬希布洛赫提供的骨幹實現Map.Entry<K,V>接口的一個例子:接口的骨架實現中的抽象方法

// Skeletal Implementation 
public abstract class AbstractMapEntry<K,V> 
     implements Map.Entry<K,V> { 
    // Primitive operations 
    public abstract K getKey(); 
    public abstract V getValue(); 

// ... remainder omitted 
} 

兩個問題從這個例子幹:

  1. 爲什麼信息getKey和getValue明確聲明這裏的抽象方法?它們是Map.Entry接口的一部分,所以我沒有看到抽象類中冗餘聲明的原因。
  2. 爲什麼用布洛赫先生提到的這些原始方法來表達抽象的成語?爲什麼不這樣做:

    //骨架實現 public abstract class AbstractMapEntry implements Map.Entry { private K key;私人V值爲 ;

    // Primitive operations 
        public K getKey() {return key;} 
        public V getValue() {return value;} 
    
    // ... remainder omitted 
    

    }

這樣做的好處是,每個子類沒有定義自己的字段集,並且仍然可以訪問他們的存取鍵和值。如果一個子類真的需要爲訪問者定義自己的行爲,那麼它可以直接實現Map.Entry接口。另一個缺點是,在由骨骼實現提供的equals方法,將抽象訪問被稱爲:

// Implements the general contract of Map.Entry.equals 
@Override public boolean equals(Object o) { 
    if (o == this) 
     return true; 
    if (! (o instanceof Map.Entry)) 
     return false; 
    Map.Entry<?,?> arg = (Map.Entry) o; 
    return equals(getKey(), arg.getKey()) && 
      equals(getValue(), arg.getValue()); 
} 

布洛赫警告不要從設計繼承的類調用重寫的方法(17項),因爲它離開超容易由子類進行的更改。 也許這是一個意見問題,但我希望能夠確定是否有更多的故事,因爲布洛赫在書中沒有詳細說明這一點。

回答

0

AbstractMapEntry#getKeygetValue是抽象(即未實現)的一個原因是Map.EntryMap的內部接口。使用嵌套類/接口是Java實現組合的方式。構圖中的想法是組成部分不是一流的概念。相反,組成部分只有在整體中才有意義。在這種情況下,組成部分是Map.Entry,組合的根對象是Map。顯然表達的概念是Map有許多Map.Entry s。

因此,AbstractMapEntry#getKeygetValue的語義將基本上取決於我們正在討論的Map的實現。正如你寫的一個簡單的舊的getter實現將工作得很好,爲HashMap。它不適用於需要線程安全的ConcurrentHashMap之類的東西。 ConcurrentHashMapgetKeygetValue的執行很可能成爲防禦性副本。 (建議您自己檢查源代碼)。

另一個原因不執行getKeygetValue是實現Map字符是完全不同的範圍從那些不應該讓屬於(即Properties)以完全不同的宇宙從Map直觀impls(例如ProviderTabularDataSupport)。

總之,實現,因爲API設計的這條黃金法則的AbstractMapEntry#getKeygetValue,:

如果有疑問,離開它(見here

+0

錯誤,你似乎完全忽略了這個問題... – 2008-10-25 23:39:22

0
  1. 我沒有看到任何理由

  2. 允許實現定義鍵和值的存儲方式。

1
  1. 我會說這有助於強調什麼具體的類旨在應對,而不是隻留給了編譯器告訴你(或你有比較既要看到什麼是丟失) 。一種自我記錄的代碼。但是,我可以看到,它當然沒有必要,它更像是一種風格的東西。
  2. 返回這些值的邏輯比簡單的getter和setting更有意義。我在標準JDK(1.5)中檢查過的每個類都至少在其中一個方法上做了非簡單的事情,所以我猜測他認爲這樣的實現太幼稚了,它會鼓勵子類使用它,而不是通過思考這個問題靠自己解決。

關於與平等的問題,如果抽象類實現它們,因爲這個問題是overrid 能夠沒有什麼會改變。在這種情況下,我會說平等正在試圖仔細實施以預測實施。由於協方差問題,通常等於一般不應該被實現爲在它自己和它的子類之間返回真(儘管有很多事情是這樣做的)(超類將認爲它等於子類,但子類不會認爲它等於超類) ,所以無論你做什麼,這種類型的equals實現都很棘手。

1

布洛赫警告說,不要叫從 類設計繼承 重寫的方法(17項),因爲它 樹葉子類

他警告有關調用在重寫的方法做出的超容易 變化構造函數,而不是其他方法。