【问题标题】:Why can't I create generic array in Java?为什么我不能在 Java 中创建泛型数组?
【发布时间】:2022-01-03 23:26:24
【问题描述】:

我在创建一些数组时遇到了问题。

这里是代码

Predicate<Integer[]>[] endOfLine = {
    curPoint -> curPoint[0]==r2,
    curPoint -> curPoint[0]==c2,
    curPoint -> curPoint[0]==r1,
    curPoint -> curPoint[0]==c1
};
Consumer<Integer[]>[] move = {
    curPoint -> { curPoint[0]++; },
    curPoint -> { curPoint[1]++; },
    curPoint -> { curPoint[0]--; },
    curPoint -> { curPoint[1]--; }            
};

和eclipse(也许是编译器?)说:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Cannot create a generic array of Predicate<Integer[]>

我google了一下,发现泛型类型参数数组不能用Java制作。

我阅读了有关编译时间和运行时的信息,我认为这可能不是我的问题。

我看到了一些编译编译的代码:

List<Integer>[] arrayOfLists = new ArrayList[2];
ArrayList<Integer[]> lists =new ArrayList<>();
ArrayList<Consumer []> [] lists = new ArrayList[5];
        
Predicate<Integer[]>[] p = new Predicate[5];
p[0] = a -> a[0] == 0;

Predicate<Integer[]>[] pp = { a -> a[0] == 0 }; //cant be compile

我阅读了 oracle 文档并发现了这个:

“无法创建参数化类型的数组”

我总结了我的快捷语法,{} 是问题所在。快捷语法创建具有参数化类型的代码。这是正确的吗?

【问题讨论】:

    标签: java generics


    【解决方案1】:

    您不能在 Java 中创建泛型数组。数组是可具体化的类型,在运行时携带它们的类型信息,而泛型是不可具体化的,并且它们的类型信息在编译时间后由于擦除而被擦除。这是由于 java 中类型系统的实现,即使这会导致一些粗糙的边缘和极端情况,它也可以简化代码向泛型的演变。由于泛型类型信息已被删除,因此您在运行时没有它们,这就是您无法在 java 中创建泛型数组的原因。

    有两种解决方案可以规避您所面临的问题。您可以创建一个 Object 数组并将其转换为您需要的泛型类型。

    final T[] arr = (T[]) new Object[n]
    

    否则

    final Object[] arr = new Object[]
    

    当你像这样从这个数组中获取项目时,你可以进行强制转换

    T itm = (T) arr[1];
    

    如果您不返回此内部数组,上述两种方法都有效。

    但是,如果您要返回内部数组,则需要以反射方式创建它,因为您需要维护正确的可具体化类型。

    static <T> T[] createArr(Class<T> clz) {
        return (T[]) Array.newInstance(clz, 5);
    }
    

    【讨论】:

    • Java 泛型是假的,简单明了。与 c# 相比,这一切都很糟糕。
    • 每种方法都有自己的长处和短处。泛型的 Java 实现与 C++ 的不同。最初的实现者更关心向后兼容性。因此,Java 实现比 C# 实现向后兼容。
    • @Nyerguds “Java 泛型是假的,简单明了。” ...使用强判断性语言来描述 Java 的类型系统没有帮助。 Java 中泛型的实现主要是仅在编译时出现的现象,为开发人员提供了泛型抽象的许多好处,同时保持与遗留系统的运行时兼容性……纯粹而简单。如果您当时要在 Java 中实现泛型同时实现相同的目标,我怀疑您可以做得更好。
    • 泛型类是参数化类型,例如Collection&lt;T&gt;Predicate&lt;T&gt;,因此上述所有规则都适用。如果您需要更多地了解泛型,我建议您阅读这本书:amazon.com/Java-Generics-Collections-Development-Process/dp/…
    • "您可以创建一个 Object 数组并将其转换为您需要的泛型类型" 它必须是 T 的擦除数组。如果T 的擦除是Object,那就没问题了。但是如果说T&lt;T extends Comparable&lt;T&gt;&gt;,那么(T[]) new Object[n] 就会失败。您将需要(T[]) new Comparable[n],因为ComparableT 的擦除。在 OP 的情况下,他们想要创建一个参数化类型的数组。参数化类型的擦除只是原始类型。他们应该使用(Predicate&lt;Integer[]&gt;[])new Predicate[n](Consumer&lt;Integer[]&gt;[])new Consumer[n]
    猜你喜欢
    • 2012-07-23
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多