0

对于以下泛型类,r=g 行存在编译错误:类型不匹配:无法从 GenericTest1<Integer> 转换为 GenericTest1<Number> 如何修复?

public class GenericTest1<T> {
    private T t;

    public GenericTest1(T t) {
        this.t = t;
    }

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public static void main(String[] args) {
        GenericTest1<Integer> g = new GenericTest1<>(6);
        GenericTest1<Number> r = g; <==here
    }
}
4

5 回答 5

1

这里的误解是它GenericTest1<Number>GenericTest1<Integer>. 它不是,所以你必须单独施放每个成员。

于 2012-11-14T06:43:13.783 回答
1

在使用泛型编程时,这是一个常见的误解。这里两种具体类型GenericTest1<Integer>GenericTest1<Number>没有关系。唯一的共同点是两者都是Object.

于 2012-11-14T06:43:47.357 回答
1

两个类 GenericTest<Number> 和 GenericTest<Integer> 不兼容分配。你甚至不能施放它们。但是,如果您不介意复制对象,则可以执行以下操作:

向您的类添加一个复制构造函数:

public GenericTest1(GenericTest1<? extends T> other) {
    this.t = other.t;
}

然后复制对象:

public static void main(String[] args) {
    GenericTest1<Integer> g = new GenericTest1<>(6);
    GenericTest1<Number> r = new GenericTest1<Number>(g);
}
于 2012-11-14T06:45:37.790 回答
0

First of all, I would limit acceptable types in your class and introduce method that compares the field with Number or with other GenericNumber and define your generic class like

public class GenericNumber<T extends Number> {
    private T number;
    public T getNumber() {
        return number;
    }
    public void setNumber(T number) {
        this.number = number;
    }
    public void setNumber(T number) {
        this.number = number;
    }
    //constructors
    public int compareTo(Number n) throws Exception {
        if((number == null) || (n == null))
            throw new Exception("Can't compare null values");
        else if(number.doubleValue() > n.doubleValue)
            return 1;
        else if(number.doubleValue() == n.doubleValue)
            return 0;
        else
            return 1;
    }
    public int compareTo(GenericNumber n) throws Exception {
        if(n == null)
            throw new Exception("Can't compare null values");
        return compateTo(n.getNumber());
    }
}

With this approach testing for equality of instances will transform into the following condition, with your objects: (r.compareTo(g) == 0).

If you don't want to use the java-flavoured comparing class method of this type you can, of course, typecast the fields and compare with = operator.

For the behaviour you expect it is not right to make such an assignment because GenericNumber<Integer> is not a subtype of GenericNumber<Number>, as our intuition implies, though Integer is subtype of Number. To understand that suppose that in your case you would like to call a set method on an instance of GenericNumber<Number>:

GenericNumber<Integer> i = new GenericNumber<Integer>();
Integer ii = 3;
i.setNumber(ii);
GenericNumber<Number> n = i;//suppose it will be consumed by compiler
//in this case it will be tempting to forget about i and use n instead, like in the following lines
Folat f = 2.5f;
n.setNumber(f);
//would be valid because method signature will be 
//public void Number setNumber(Number number)
//but what actually happens is that you will try to call method of class
//GenericNumber<Integer> with signature public void Integer setNumber(Integer number)

As you see, the last line will cause an error, so you need to use generics with caution.

By the way, tutorial section on generics of then-Sun, now-Oracle site is worth visiting, namely: http://docs.oracle.com/javase/tutorial/java/generics/index.html and/or http://docs.oracle.com/javase/tutorial/extra/generics/index.html.

于 2012-11-14T07:28:04.117 回答
0

GenericTest1<Integer>并且GenericTest1<Number>不兼容,您不能在它们之间进行转换!但是,如果您不想公开 Integer,则可以使用绑定:

GenericTest1<? extends Number> r = g;

rGenericTest1<Integer>真实的,但声明只允许访问 Number。由于不特定的类型 T,您不能调用set()(好的,与 null 一起使用),但您可以使用get()

g.set(Integer.valueOf(1)); // OK
r.set(Integer.valueOf(1)); // compile ERROR
if (r.get().intValue() == 1) { //OK
    ...  
}
于 2012-11-14T07:02:51.443 回答