import java.lang.reflect.Array;

public class PrimitiveArrayGeneric {
    static <T> T[] genericArrayNewInstance(Class<T> componentType) {
        return (T[]) Array.newInstance(componentType, 0);
    }

    public static void main(String args[]) {
        int[] intArray;
        Integer[] integerArray;

        intArray = (int[]) Array.newInstance(int.class, 0);
        // Okay!

        integerArray = genericArrayNewInstance(Integer.class);
        // Okay!

        intArray = genericArrayNewInstance(int.class);
        // Compile time error:
           // cannot convert from Integer[] to int[]

        integerArray = genericArrayNewInstance(int.class);
        // Run time error:
           // ClassCastException: [I cannot be cast to [Ljava.lang.Object;
    }    
}

我试图完全理解泛型在 Java 中是如何工作的。在上面代码片段的第三个作业中,事情对我来说有点奇怪:编译器抱怨说 Integer[] 不能转换为 int[]. 。当然,这个说法 100% 正确,但我想知道 为什么 编译器正在提出此投诉。

如果您注释该行,并遵循编译器的“建议”,如第四个作业中所示, 编译器实际上很满意! 现在 代码编译得很好!当然,这很疯狂,因为就像运行时行为表明的那样, int[] 不能转换为 Object[] (这是什么 T[] 在运行时被类型擦除)。

所以我的问题是:为什么编译器“建议”我分配给 Integer[] 而不是第三个作业?编译器如何得出这个(错误的!)结论?


到目前为止,这两个答案存在很多混乱,因此我创建了另一个令人困惑的示例来说明此处的根本问题:

public class PrimitiveClassGeneric {    
    static <T extends Number> T test(Class<T> c) {
        System.out.println(c.getName() + " extends " + c.getSuperclass());
        return (T) null;
    }
    public static void main(String args[]) {
        test(Integer.class);
        // "java.lang.Integer extends class java.lang.Number"

        test(int.class);
        // "int extends null"
    }
}

我是唯一一个认为编译器让上述代码编译绝对疯狂的人吗?

打印出来也不是没有道理 c.getSuperclass().getName() 例如,在上面的代码中,因为我指定了 T extends Number. 。当然现在 getName() 会扔 NullPointerException 什么时候 c == int.class, , 自从 c.getSuperclass() == null.

对我来说,这是首先拒绝编译代码的一个很好的理由。


也许最终的疯狂是:

    int.class.cast(null);

该代码编译 运行良好。

有帮助吗?

解决方案

在型int.class的是Class<Integer>,所以genericArrayNewInstance()将被推断为返回一个Integer[]。但是函数实际上创建了一个int[],所以返回时,它会有一个类转换异常。基本上,浇铸到T[]内部的功能在这种情况下合法的,因为int[]不是T[](基元不能在类型变量可以使用)。你不能笼统处理基本数组类型;所以你要么必须有你的方法只是返回类型Object,或者你必须做出引用类型和原始类型不同的方法。

其他提示

几点:

  1. 原语是 自动装箱 需要时到其对象对应物(包装器)
  2. 原始数组是对象,因此它们不会自动装箱。
  3. 泛型不能使用基元作为类型参数

对于您的示例,以下是我的假设:

在3中,自动装箱发生在 类型参数, ,但返回的数组不会发生这种情况
在4中,自动装箱发生在 类型参数, ,但不会发生 方法参数, ,所以事实上 int[] 已生成,但是 Integer[] 是期待

在类型参数的情况下自动装箱可能不完全正确 自动装箱, ,但是是具有相同想法的东西。

更新: 你的第二个例子没有任何问题。 int.class 是一个 Class, ,所以编译器没有理由拒绝它。

我同意原来的海报。这太疯狂了。为什么我不能使用原始的与通用的?这可能不是问题的编译器,但它是语言的问题。根本就是错误的,从通用跳过基本类型。

有关这样的:

intArray =(INT [])Array.newInstance(int.class,0);

int.class只是一类对象。所以,它的确定传了过来。 “INT”是一种类型,是因为它显然是原始它也不行。不是说这是“最好”的方式来创建的语言,只是坚持的语言。

这是如此疯狂,我不能创建用于使用通用基元的存储器(阵列)的分配的包装。如果使用对象,如此臃肿的庞大收藏是一种浪费。谁创造了Java语言/机器的人显然在他们的大脑有点限制。他们可以这样做不对的第一时间,但修复它需要十年,而不是这样做的权利。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top