Java:使用通用通配符和子类

时间:2011-01-07 14:14:58

标签: java generics inheritance constructor

假设我有一个类Foo,一个A类和一个A的子类B.Foo接受A及其子类作为泛型类型。 A和B都需要在构造函数中使用Foo实例。我希望A的Foo是A类,而B的Foo是B类或B的超类。所以实际上,我只想要这个:

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。

4 个答案:

答案 0 :(得分:1)

如果将A构造函数更改为:

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>());

为了正确输入A中的foo元素,您可能还需要使A成为参数化类。

答案 1 :(得分:0)

这样做的唯一方法就是......

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

但看起来这不是你想要的。您不能使用其他方法,因为在创建B实例时,您还要创建A的实例(它是B实例的一部分)。因此B不能为A中的部分采用特殊字段。我不确定为什么你不允许A的foo为B类,你可以扩展它吗?

答案 2 :(得分: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>());
}

这是你要找的吗?

答案 3 :(得分: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,这会阻碍代码重用。