通用对象数组,其中通用对象的上限与 Object 不同

Array of generic objects where generic object has a different upper bound than Object

谁能解释一下下面的场景是怎么回事?为什么一个报错,一个不报错?

public class TestClass<T extends Comparable<T>> {
    protected T []items;

    public TestClass(int size, T... values) {
        items = (T[]) new Object[size];
        for (int v = 0; v < Math.min(size, values.length); v++) {
            items[v] = values[v];
        }
    }

    public T getItem() {
        return items[0];
    }

    public static void main(String []args) {
        System.out.println(new TestClass<>(2, 6).getItem()); // Error
    }
}

执行上面的class会出现以下错误:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
    at TestClass.<init>(TestClass.java:5)
    at TestClass.main(TestClass.java:16)
Java Result: 1

还有这个:

public class TestClass<T> {
    protected T []items;

    public TestClass(int size, T... values) {
        items = (T[]) new Object[size];
        for (int v = 0; v < Math.min(size, values.length); v++) {
            items[v] = values[v];
        }
    }

    public T getItem() {
        return items[0];
    }

    public static void main(String []args) {
        System.out.println(new TestClass<>(2, 6).getItem()); // Prints 6
    }
}

我还应该提到,数组的创建是在超级 class 中完成的,因此我无法更改数组初始化的完成方式。这也是在 Java 8

下编译的

我采用的解决方案是: this.items = (T[])new Comparable[size];

以上仅在您不尝试在 class 之外使用数组时才有效。例如,这样做是错误的:

TestClass<Integer> t = new TestClass<>(2, 6);
System.out.println(t.items[0]); // error more ClassCastException

但这样做不是:

System.out.println(new TestClass<>(2, 6).getItem()); // Prints 6

还有其他人觉得 java 泛型类型有点不一致吗?

我相信你的问题出在这里

items = (T[]) new Object[size];

class Object[] 不扩展 Comparable(或与此相关的任何接口),因此,你不能说 Comparable c = (Comparable)(new Object()),你也不能将 Object[] 转换为Comparable[] if it is not originally one.

已根据问题的变化进行更新

如果在泛型类型参数上声明了上限,编译器将在调用 returns 泛型类型的方法或将某些内容赋值给变量时插入到正确类型的强制转换泛型类型,确保类型安全。

在第一种情况下,因为 ComparableT 的上限,编译器在构造函数中插入了对 Comparable[] 的强制转换,因为数组被分配给了 T[]。但是,分配的实际上是 Object[],因此转换失败。

在第二种情况下,没有上限,所以编译器不会在构造函数中插入对 Comparable[] 的转换,因此没有转换失败。

要使第一种情况成功,即使在泛型类型参数上声明了上限,您也应该遵循 How to create a generic array in Java? 的建议来创建泛型数组。这需要传入 Class 对象,以便创建适当的 class 数组。

@SuppressWarnings("unchecked")
public TestClass(int size, Class<T> clazz, T... values) {
    items = (T[]) Array.newInstance(clazz, size);
    // ...
}

如果当 T 的上限是 Object 时,您可以接受 (T[]) new Object[size],那么当 T extends Comparable<T> 时,类似的事情将是:

(T[]) new Comparable[size]

原因是T被擦除到了它的上限。因此,在 T 的上限为 Object 的情况下,强制转换被擦除为 Object[],这是可以的。但是,当 T 的上限为 Comparable<...> 时,强制转换被擦除为强制转换为 Comparable[],如果对象的运行时 class 为 [=18],则此操作无效=].将其更改为 Comparable[] 可解决此问题。