2013-06-30 52 views
11

如何類似的功能沒有錯誤來實現的?強制Java的泛型參數是同類型

class A<K> { 
    void f(K x) {} 
} 

void foo(A<? extends X> a, X x) { 
    a.f(x); // AN error: The method f(capture#1-of ? extends X) in the 
      // type A<capture#1-of ? extends X> is not applicable for the 
      // arguments (X) 
} 

我知道,這是因爲「A」可以是A <「非X」>的一個實例,因此它的「F」不得接受X的實例作爲參數,但怎麼也我強制參數是相同的類型?

這裏是更多的代碼:

測試類:

class Test { 
    <T> void foo(A<T> a, T x) { 
    a.f(x); // now it works! 
} 
} 

在某些類:

Container<X> container; 
public void test() { 
    X x = new X(); 
    new Test().foo(container.get(), x); 
} 

這裏的容器類:

public class Container<K> { 
    A<? extends K> get() { 
    return new A<K>(); 
    } 
} 
+0

X是類還是類型參數? – Joni

回答

17

您可以力參數ERS做是同一類型以下:

// the first class, A<K>: 
class A<K> { 
    void f(K x) {} 
} 

// the second class, defining the method with generic type parameters 
class Test { 
    <T> void foo(A<T> a, T x) { 
    a.f(x); // now it works! 
    } 
} 

// a third class, that uses the above two: 
class Main { 
    public static void main(final String... args) { 
    final Test test = new Test(); 
    final A<String> a = new A<>(); 
    test.foo(a, "bar"); 
    } 
} 

這裏做的事情是:該方法foo定義泛型類型參數T,並用它來執行該類AK類型參數必須匹配的x類型,foo第二個參數。

如果您願意並且您的問題有意義,例如<T extends Bar> void foo(A<T> a, T x) {...}super,您甚至可以對<T>施加限制。你想這個,如果作爲喬尼問上問題的評論,X實際上是一個類型,而不是一個類型參數:你會使用<T extends X> void foo(...)


當您顯示更多代碼後,問題就變得清晰。

方法容器.get()返回A<? extends K>一個實例。因此,您從.get()獲取的實例的類型參數未完全指定。通常,返回這種非特定類型的設計並不是很好。對於約書亞布洛赫有效的Java和許多API和功能在Java中的作者的視頻演示,展示瞭如何改善這樣的API,檢查:http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu.be&t=22m。正好25'36" ,約書亞·布洛克說:‘不要嘗試使用它們[通配符類型]的返回值’,並解釋說,他後來基本上,你不使用他們獲得更多的靈活性,並且只是使API的用戶很難處理它(你只是覺得這樣做的效果......)

要解決這個問題,你可以簡單地嘗試將.get()的簽名改爲A<K> get(),這樣容器類將是:

public class Container<K> { 
    A<K> get() { 
    return new A<K>(); 
    } 
} 

你既然知道get()正在返回的A<K>一個實例,我們沒有理由使用舊的簽名:它只是使你失去你已經知道的信息!

如果這仍然不起作用,你的問題可能在其他地方,你需要顯示更多的代碼......或者更好,還有其他問題!:)

+0

但是如何使用? 'new Test().foo(a,x);'仍然返回錯誤: 類型A .Test中的方法foo(A ,T)不適用於參數(A ,X) – Evgeny

+0

您似乎將'Test'類定義爲'A'的內部類,這不正是我在上面顯示的內容。 –

+0

這似乎並不重要:現在的錯誤是'類型Test中的方法foo(A ,T)不適用於參數(A ,X)' – Evgeny

6

在牢記PECS rule,並給予您使用X的方式,你應該指定爲而不是上限:

void foo(A<? super X> a, X x) 

這樣沒有編譯錯誤產生,並且您有最適合的一般簽名。

+1

這不完全是問題所在:OP要求讓'X'在'A a'和'X x'上成爲*相同*類型。也許他確實需要你的回答,但這個問題應該改寫。 –

+0

OP還詢問「如何在沒有錯誤的情況下實現類似的功能?」 - 而Marko的答案就是這樣。 – meriton

+0

@meriton的確如此。但是,這似乎有點太模糊,沒有說明。 –