2011-01-07 61 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,妨碍代码重用。