簡體   English   中英

具有繼承和協方差的Java泛型

[英]Java Generics with inheritance and covariance

在Java中使用泛型時,我有點難以理解如何正確使用協方差和通配符。

我試圖避免使用鑄造。

這是我的情況:

class Element {}

class ChildElement extends Element {}

interface A<T> {
    T doSomething(T foo);
}

interface B extends A<Element> {}

interface C extends B {}

class D implements B {

    @Override
    public Element doSomething(Element foo) {} 
}

class E extends D implements C {
    @Override
    public Element doSomething(Element foo) {}
}

這種情況有效,但我希望能夠為E類做到這一點:

class E extends D implements C {

    @Override
    public ChildElement doSomething(ChildEment foo) {}
}

從我所看到的,我想要做的是協方差,但我不能在當前的情況下這樣做,因為我需要使用通配符。 但我讀過你不能對泛型和通配符做協變。

有沒有解決這個問題的方法? 我想保持每個類之間的強大依賴關系。

謝謝你的幫助 !

你必須使B泛型,但你可以在泛型參數上設置一個綁定,使它至少是一個Element

interface B<T extends Element> extends A<T> {}

interface C<T extends Element> extends B<T> {}

然后你可以得到的最近的是:

 class D<T extends Element> implements B<T> {
    @Override
    public T doSomething(T foo) { return null;}
}

class E extends D<ChildElement> implements C<ChildElement> {
    @Override
    public ChildElement doSomething(ChildElement foo) { return null;}
}

編譯。

但我讀過你不能對泛型和通配符做協變。

此聲明不是關於協變返回類型,但它意味着您不能這樣做:

List<Number> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
l1 = l2; //illegal

但它也是T的任何子類。所以這樣的事情:

interface Interface<T> {
    T method();
}

class SomeClass implements Interface<Number>{
    @Override
    public Float method() {
        return 1F;
    }
}

工作良好。 但是方法的子類(實現)和超類(接口)的簽名必須匹配。 所以在你的例子中

class E extends D implements C {

    @Override
    public ChildElement doSomething(ChildEment foo) {}
}

這是非法的。

您描述的界面不能協變。 您希望/期望在此代碼中發生什么?

class OtherElement extends Element{}
Element oe = new OtherElement();
E e = new E();
B b = e;
b.doSomething(oe);

這正確編譯,因為它必須 - 但如果E#doSomething期望ChildElement我們會在這里失敗。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM