2016-09-24 81 views
1

如何在泛型類型級別或方法級別定義之間進行選擇?下面我有兩個例子,用於解決某些問題的替代(正確)實現。我試圖理解這些差異,以及爲什麼我會選擇一個。在類級別或方法級別泛型之間進行選擇

示例1: 給出一些處理搜索樹的算法。爲了幫助用戶進行調試,算法中的某些狀態會觸發事件。用戶可以實現監聽這些事件的例如EventListener,例如,一些記錄器實用程序。

public Node<N extends Number>{ .. } 

的事件可以通過以下兩種方式來實現:

選項1:(類級)

public class PruneNodeEvent<N extends Number> extends EventObject 
{ 
    public final Node<N> node; //Node being pruned 

    public PruneNodeEvent(Object source, Node<N> node) 
    { 
     super(source); 
     this.node = node; 
    } 
} 

選項2:(方法級)

public class PruneNodeEvent extends EventObject 
{ 
    public final Node<? extends Number> node; //Node being pruned 

    public PruneNodeEvent(Object source, Node<? extends Number> node) 
    { 
     super(source); 
     this.node = node; 
    } 
} 

其中考慮應該做出選擇一個在另一個上?

示例2: 給出一些偵聽決策的算法的抽象實現。每次做出新決策時,算法都會更新其數據結構,但不會存儲決策。由於這是一個抽象類(模板),我們不知道最終用戶將如何使用這個類。同樣,我們有2種選擇:

選項1:(職業等級)

public abstract class AbstractAlgorithm<T extends Data> 
implements DecisionListener<T> { 

    @Override 
    public void makeDecision(Decision<T> d) 
    { 
    } 

    @Override 
    public void reverseDecision(Decision<T> d) 
    { 
    } 
} 

選項2:(方法級別)

public abstract class AbstractAlgorithm implements DecisionListener 
{ 
    @Override 
    public void makeDecision(Decision<? extends Data> d) { 
    } 

    @Override 
    public void reverseDecision(Decision<? extends Data> d) { 
    } 
} 

哪些方面的考慮提出,要選擇一個在另一方面?

鼓勵在設計泛型類(ala Effective Java 2nd Edition)時提供處理Dos,注意事項和注意事項的良好參考以支持您的答案。

+0

許多優秀的問題都會根據專家的經驗產生一定程度的意見,但對這個問題的回答往往基於意見而非事實,參考或具體專業知識。 –

+0

這些例子都涵蓋消費者,考慮供應商的情況(例如'List.get(...)',如果返回'?extends Object'會怎麼樣)。 –

+0

@RomanC第一個答覆已經是一個很好的**事實**答案......並非所有的設計問題都是基於作者的偏好,還是星星的排列... –

回答

3

例1

這兩者之間的主要區別在於,你可以用node做什麼。

我們只是在第三個選項添加的完整性:

public final Node<? super Number> node; 

記住的縮寫PECS

生產者延伸消費者超級

  • 在第二個選項,Node<? extends T> node生產:你只能調用其產生T它的方法。

    T instanceOfT = node.get(); 
    

    ,但你不能調用消費者方法比其他null參數:

    node.accept(null);   // OK. 
    node.accept(instanceOfT); // Compiler error. 
    
  • 在第三個選項,Node<? super T> node消費者:它只能調用方法其中採取一個T,例如

    node.accept(instanceOfT); 
    

    ,但你不能調用製作方法及其結果分配給一個類型依賴於T

    Object obj = node.get();   // OK. 
    List<?> list = node.getList(); // OK. 
    T t = node.get();    // Compiler error. 
    List<T> listT = node.getList(); // Compiler error. 
    
  • 在第一個選項,Node<T> node生產者和消費者,因爲它是選項2和3的交集(類型是<? extends T><? super T><T>):

    T t = node.get(); // OK. 
    node.accept(t); // OK. 
    

因此,3個選項之間的選擇取決於你需要做什麼node

  • 如果你需要它來生產T S,選擇使用<T><? extends T>;
  • 如果你需要消耗T S,選擇使用<T><? super T>;
  • 如果您需要它生產消耗T s,請選擇<T>

實施例2

使用第一個如果只想調用的方法的具體參數類型的Decision,例如

AbstractAlgorithm<StringData> foo = new AbstractAlgorithm<>(); 
foo.makeDecision(new Decision<StringData>()); // OK. 
foo.makeDecision(new Decision<IntegerData>()); // Compiler error. 

,如果你希望能夠用相同的AbstractAlgorithm,例如調用該方法對於任何類型的使用第二

AbstractAlgorithm foo = new AbstractAlgorithm(); 
foo.makeDecision(new Decision<StringData>()); // OK. 
foo.makeDecision(new Decision<IntegerData>()); // OK. 
+0

hm,那麼第一個例子呢? –

+0

@JorisKinable添加。 –