如何使用此类的泛型类型(Java)的泛型类型?

时间:2015-02-02 05:37:36

标签: java generics inheritance polymorphism wildcard

我有一个带有通用通配符T的抽象类A<T>。有两个扩展名A,

public class A1 extends A<Integer> {...}

public class A2 extends A<String> {...}

现在我有另一个类,我们称之为B,它基本上是A1或A2的集合。所以我把它定义为一类泛型类型T extends A:

public class B<T extends A> {...}

我希望能够在B中创建返回T类通用类型的方法。例如,

B<A1> foo = new B<A1>;
foo.get(); // returns Integer, corresponding to A1's generic type

B<A2> bar = new B<A2>;
bar.get(); // returns String, corresponding to A2's generic type

是否可以在Java中执行此操作?在声明B的方法时,我无法确定要返回的返回类型(如果我想让B返回T,我会放置public T get() {...},但我实际上想要返回参数化类型 T)。或者是否有一种模式可以比我接近它的方式更好地解决这个问题?

感谢。

2 个答案:

答案 0 :(得分:3)

您可以为B声明第二个类型参数,并将其作为A的参数化

class B<K, T extends A<K>> {
    public K get() {
        // actual implementation
        return null;
    }
}

然后声明你的变量

B<String, A2> var = new B<>();
String ret = var.get();

What is a raw type and why shouldn't we use it?

答案 1 :(得分:1)

我想提供一个示例,可以帮助您更好地理解为什么我们需要两个泛型类型参数。首先,A及其直接子类的示例声明。

class A<T> {

    private T value;

    public A(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }   
}

class A1 extends A<Integer> {
    A1(Integer i) {
        super(i);
    }
}

class A2 extends A<String> {
    A2(String str) {
        super(str);
    }
}

现在,B类声明。请注意,它如何引用其定义中的泛型类型以提供对包装的A子类成员的访问。

public class B<T, X extends A<T>> {

    private X data;

    public B(X data) {
        this.data = data;
    }

    public T get() {
        return data.getValue();
    }

    public static void main(String[] args) {

        B<Integer, A1> foo = new B<Integer, A1>(new A1(10));
        System.out.println(foo.get()); // returns Integer

        B<String, A2> bar = new B<String, A2>(new A2("Ten"));
        System.out.println(bar.get()); // returns String
    }
}

如果只切换到一个类型参数,则有两个选项。

您要么保留A子类的类型,如

public class B<T extends A<?>> {

    private T data;

    public B(T data) {
        this.data = data;
    }

    public Object get() {
        return data.getValue();
    }

    ...
}

或者,实际的return类型的getter。

public class B<T> {

    private T value;

    @SuppressWarnings("unchecked")
    public B(A<?> data) {
        this.value = (T) data.getValue();
    }

    public T get() {
        return value;
    }

    ... 
}

请注意,这两种解决方案都是如此脆弱。

一个人返回Object并要求使用instanceof正确投射,另一个更加脆弱,并且未经检查投射。既然您没有提供所需的通用类型,那么您已经限制了您的班级设计,并冒着现在获得ClassCastException的风险。