2013-07-18 118 views
2

我有這種設計,我不確定它爲什麼不起作用。泛型有界類型參數

interface BaseType {} 

interface TypeA extends BaseType {} 

interface TypeB extends BaseType {} 

interface Query<T extends BaseType> { 
    public String get(); 
} 

interface Result<T extends BaseType> { 
    public String get(); 
} 

interface Service<T extends BaseType> { 
    public Result<T> get(Query<T> query); 
} 

class SomeResult implements Result<TypeA> { 
    private String s; 
    public SomeResult(String s) { this.s = s; } 
    public String get() { return this.s; } 
} 

class SomeQuery implements Query<TypeA> { 
    public String get() { return "blah"; } 
} 

class SomeQuery2 implements Query<TypeA> { 
    public String get() { return "blah2"; } 
} 

class SomeService implements Service<TypeA> { 
    /** OK -- but notice the ambiguous parameter type */ 
    /* 
    public SomeResult get(Query<TypeA> query) { 
     if (query instanceof SomeQuery) return new SomeResult(query.get()); 
     else return null; 
    } 
    */ 

    /** NOT OK -- but this is the parameter I want to keep; notice SomeQuery IS-A Query<TypeA> */ 
    public SomeResult get(SomeQuery query) { return new SomeResult(query.get()); }; 
    /** 
    * Main.java:27: error: SomeService is not abstract and does not override abstract method get(Query<TypeA>) in Service 
    * class SomeService implements Service<TypeA> { 
    *^
    * 1 error 
    */ 
} 

public class Main { 
    public static void main(String args[]) { 
     SomeQuery someQuery = new SomeQuery(); 
     SomeQuery2 someQuery2 = new SomeQuery2(); 
     SomeService someService = new SomeService(); 
     System.out.println(someService.get(someQuery).get()); 
    } 
} 

我是新來的泛型,並不完全明白我在這裏違反什麼合同。我希望服務能夠緊密綁定,即使我可以綁定返回類型,但似乎無法爲參數設置。這意味着,我需要在服務內部執行instanceof檢查,以確保獲得正確的參數。我想避免這種情況。有任何想法嗎?

回答

1

由於return type covariance,您可以使覆蓋方法的返回類型更具體,但是您不能更改方法的參數而不更改其簽名。這就是爲什麼編譯器會抱怨當您將其更改爲get(SomeQuery)時,您沒有實現get(Query<TypeA>)。你需要做Service更加靈活,以獲得想要的東西:

interface Service<T extends BaseType, Q extends Query<T>> { 
    public Result<T> get(Q query); 
} 

class SomeService implements Service<TypeA, SomeQuery> { 

    @Override 
    public SomeResult get(SomeQuery query) { 
     ... 
    } 
} 

還要注意的是編碼接口時縮小返回類型並不重要:當SomeService的類型是Service<TypeA, SomeQuery>get仍然會返回Result<TypeA>。因此,您可能會考慮對結果類型進行類似的更改:

interface Service<T extends BaseType, Q extends Query<T>, R extends Result<T>> { 
    public R get(Q query); 
} 

class SomeService implements Service<TypeA, SomeQuery, SomeResult> { 

    @Override 
    public SomeResult get(SomeQuery query) { 
     ... 
    } 
} 
+1

+1。或者,換句話說,'SomeService'是'服務'和'SomeQuery2''是'Query ',所以這個必須能夠工作:'服務 service = new SomeService(); service.get(new SomeQuery2());' –

+0

謝謝。這是有道理的。 – bdas