2011-01-07 19 views
0

假設我有一個Foo類,A類和A的一些子類B.Foo接受A及其子類作爲泛型類型。 A和B在構造函數中都需要一個Foo實例。我想A的富是A型和B的富是B型或B的所以實際上是一個超類的,所以我只希望這樣的:Java:使用通用通配符與子類化

Foo<X> bar = new Foo<X>; 
new B(bar); 

是可能的,如果X是A, B,或A的兩個子類和超類B.

的到目前爲止,這是我:

class Foo<? extends A>{ 
    //construct 
} 


class A(Foo<A> bar){ 
    //construct 
} 

class B(Foo<? super B> bar){ 
    super(bar); 
    //construct 
} 

super(...)調用不起作用,因爲<A><? super B>嚴格。在執行這些類型時是否可以使用構造函數(或通過其他方式避免代碼重複)?

編輯:Foo保留泛型參數類型的元素的集合,並且這些元素和Foo具有雙向鏈接。因此應該不可能將A鏈接到Foo。

+0

這看起來並不是你的實際代碼。 – 2011-01-07 14:33:26

+0

是的,它是代碼的簡化版本。你覺得我錯過了什麼嗎? – gibberish 2011-01-07 14:48:47

回答

1

如果你改變了構造函數:

class A(Foo<? extends A> bar){ 
    //construct 
} 

將它做你想要什麼?

如果你真的想限制A的構造函數爲Foo,那麼你需要提供另一個受保護的方法(也可以從派生類中使用)來設置Foo實例。 事情是這樣的:

public class A { 

    Foo<?> foo; 

    public A(Foo<A> foo) { 
     setFoo(foo); 
    } 

    protected A() { 
    } 

    protected void setFoo(Foo<?> foo) { 
     this.foo = foo; 
    } 
} 

和B

public class B extends A { 

    public B(Foo<? super B> foo) { 
     setFoo(foo); 
    } 
} 

現在這個工程:

new A(new Foo<A>()); 
new A(new Foo<B>()); // this fails compilation 
new B(new Foo<B>()); 

爲了在一個Foo元素被正確輸入您可能需要做出一個參數化的類。

+0

是的,似乎沒有辦法避免這種可能性 – gibberish 2011-01-07 15:34:56

+0

hehe :)我剛剛更新了我認爲更好的變體的答案。 – 2011-01-07 15:36:07

0

這樣做將有唯一的辦法......

class A(Foo<? extends A> bar) { 
    //construct 
} 

但現在看來,這是不是你想要的。你不能有另一種方法,因爲當你創建一個B的實例時,你還創建了一個A的實例(它是B實例的一部分)。所以B不能爲A部分的特殊領域。我不知道爲什麼你不允許A的Foo是B型,你可以擴展嗎?

0

以下設置編譯對我來說:

public interface MarkerInterface { 

} 

public class A implements MarkerInterface { 

    public A(Foo<A> fooA) { 

    } 
} 

public class SuperB implements MarkerInterface { 

} 


public class B extends SuperB { 

    public B(Foo<? super B> fooB) { 

    } 
} 

並與main方法:

public static void main(String[] args) { 
    B b = new B(new Foo<SuperB>()); 
} 

這是你在找什麼?

0

Java泛型功能強大且設計良好;儘管如此,我們有時會發現他們缺乏。我不認爲有一個好方法可以做你想做的事。

最簡單的做法是將Foo<X>的聲明更改爲Foo<X extends A>。如果這是不能接受的,你也可以繼承Foo這樣的:

class Foo<X> { } 

class FooA<X extends A> extends Foo<X> { } 

class A { 
    public A(FooA<? extends A> foo) { } 
} 

class B extends A { 
    public B(FooA<? super B> foo) { 
     super(foo); 
    } 
} 

(注意:如果你有以下的,當你看到Foo,認爲ArrayList麻煩。)

這有明顯的缺點,你必須使用FooA而不是Foo,妨礙代碼重用。