如何创建一个项目数组,其条目具有通用字段?

How can I create an array of items whose entries have generic fields?

我有这个代码:

import java.util.*;
import java.lang.*;
import java.io.*;

class Main{
    public static void main (String[] args){
        Foo<String> foo = new Foo<String>(1000);
    }
}

class Foo<Key extends Comparable<Key>>{
    private Entry[] a;
    private class Entry{
        Key key;
    }
    public Foo(int size){
        a = (Entry[])new Object[size]; // <- this is the problem
    }
}

当我编译它时,我得到一个错误,说:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LFoo$Entry;
at Foo.<init>(Main.java:17)
at Main.main(Main.java:7)

我试过了:

import java.util.*;
import java.lang.*;
import java.io.*;

class Main{
    public static void main (String[] args){
        Foo<String> foo = new Foo<String>(1000);
    }
}

class Foo<Key extends Comparable<Key>>{
    private Entry[] a;
    private class Entry{
        Key key;
    }
    public Foo(int size){
        a = new Entry[size];
    }
}

但后来我收到一条错误消息:

Main.java:17: error: generic array creation
        a = new Entry[size];
            ^

是否可以创建该数组?

因为Generics don't cope very well with arrays(在编译时)。

你应该使用一些 Collection,而不是:

class Foo<Key extends Comparable<Key>> {
    private List<Entry> a;

    private class Entry {
        Key key;
    }

    public Foo(int size) {
        a = new ArrayList<Entry>(size);
    }
}

其实你可以通过 reflection:

public class Main {
    public static void main(String[] args) {
        Foo<String> foo = new Foo<String>(1000);
        foo.a[0] = foo.new Entry();
        foo.a[0].key = "ss";
    }
}

class Foo<Key extends Comparable<Key>> {
    public Entry[] a;

    public class Entry {
        Key key;
    }

    public Foo(int size) {
        a = (Entry[]) java.lang.reflect.Array.newInstance(Entry.class, size);
    }
}

我同意 kocko 的观点,您应该使用一些 Collection 而不是数组。但具体到你的观点,这为我编译和运行。这只是将创建数组的责任推给了 Array.newInstance 方法。缺点是它强制转换

 class Foo<Key extends Comparable<Key>>{
     private Entry[] a;
     private class Entry{
       Key key;
     }
     public Foo(int size){
       a = (Entry[])Array.newInstance(Entry.class,size);
     }
}

作为内部 class,Entry 类型在封闭 class 中声明的类型参数 Key 的范围内。换句话说,Entry 也是通用的。

您可以使用

a = (Entry[]) new Foo<?>.Entry[size];

或原始的等价物(我不推荐)

a = (Entry[]) new Foo.Entry[size];

这种array creation在JLS

中有解释
ArrayCreationExpression:
    new ClassOrInterfaceType DimExprs [Dims]

陈述

It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type (§4.7).

其中 reifiable type

A type is reifiable if and only if one of the following holds:

  • It refers to a non-generic class or interface type declaration.
  • It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).
  • It is a raw type (§4.8).
  • It is a primitive type (§4.2).
  • It is an array type (§10.1) whose element type is reifiable.
  • It is a nested type where, for each type T separated by a ".", T itself is reifiable.

通过使用带通配符或原始类型的参数化,我们可以得到上面给出的数组创建表达式。