2013-11-03 129 views
2

我有一個Executor類,它調用接口IService<T>KeyList<T>參數的實例。方法簽名中的Java泛型類型不匹配

class Executor{ 
     KeyList<?> _keys; 
     IService<?> _service; 
     public Executor(IService<?> service, KeyList<?> keys){ 
     _service = service; 
     _keys = keys; 
     } 

     public void execute(){ 
     _service.invoke(_keys); 
     } 
    } 

    interface IService<T>{ 
     public void invoke(KeyList<T> keys); 
    } 

    class KeyList<T> { 
     List<T> _list; 
    } 

我用<?>用於執行程序的成員,因爲它並不關心IService和密鑰列表是如何參數,但下面提出了一個編譯錯誤說法的論據是不適用的:

public void execute(){ 
    _service.invoke(_keys); //error on invoke 
} 

我估計是因爲抱怨KeyList<?>不等於KeyList<T>,但<?><? extends Object>相同,所以我有點困惑。有更好的選擇嗎?

回答

2

,當你最後分配

IService<?> _service; 

它會有一些類型。考慮這個type-1

,當你最後分配

KeyList<?> _keys; 

它會有一些類型。考慮這個type-2

沒有說這些類型是兼容的,因此編譯器不允許它。這與Capture Conversion有關。

如果Ti爲通配符類型參數(§4.5.1)的形式的,然後Si是 清爽型變量,其上限是UI [A1:?= S1,......,An中:= Sn]和 ,其下限是空類型(§4.1)。

因此,每個<?>是一個不同的類型變量。

的醜陋的解決方案是簡單地刪除通配符類型聲明完全

KeyList _keys; 
IService _service; 

,但你可能會遇到在運行時等煩惱。

+0

原始類型的工作,但想到它讓我蕁麻疹:-D,THX – raffian

3

A wildcard?)代表某種特定的未知類型。但是你在這裏處理兩個單獨的通配符 - 它們可能不一樣。改用以下內容:

class Executor<T> { 
    KeyList<T> _keys; 
    IService<T> _service; 
    public Executor(IService<T> service, KeyList<T> keys){ 
     _service = service; 
     _keys = keys; 
    } 

    public void execute(){ 
     _service.invoke(_keys); 
    } 
} 

聲明一個類型參數T該類Executor,然後使用它作爲_keys_service一個類型參數,以確保它們互相兼容。

如果不能參數Executor,請嘗試使用參數化輔助類:

class Executor { 

    private static final class ServiceAndKeys<T> { 

     private final KeyList<T> keys; 
     private final IService<T> service; 

     ServiceAndKeys(IService<T> service, KeyList<T> keys) { 
      this.service = service; 
      this.keys = keys; 
     } 

     void execute() { 
      service.invoke(keys); 
     } 
    } 

    private final ServiceAndKeys<?> serviceAndKeys; 

    public <T> Executor(IService<T> service, KeyList<T> keys){ 
     serviceAndKeys = new ServiceAndKeys<T>(service, keys); 
    } 

    public void execute() { 
     serviceAndKeys.execute(); 
    } 
}