Java 中的泛型数组

2022-09-01 00:51:45

好吧,我一直在谷歌上搜索网络,我似乎找不到任何解决我的问题的方法。我发现了很多解决方案,只是没有任何合适的解决方案。

我需要创建一个泛型数组。但泛型类型本身扩展了Able。当我尝试以下操作时:

public class Hash<T extends Comparable<String>> {
    private T[] hashTable;
    private int tableSize;

    Hash(int records, double load) {
        tableSize = (int)(records / loadFactor);
        tableSize = findNextPrime(tableSize);
        hashTable = (T[])(new Object[tableSize]);  //Error: Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
    }
}

问题在于,不能将 Object 转换为扩展了可比较的泛型。有没有办法解决这个问题?


答案 1

泛型和数组基本上不会混合。简短的答案是,您可以解决此问题。更长的答案是你可能不应该,我会解释为什么。

你可以像这样使用 Array.newInstance():

private Comparable[] hashtable;

...

hashtable = (Comparable[])Array.newInstance(Comparable.class, tableSize);

不能创建参数化类型的数组。

数组是协变的。这意味着它们在运行时保留其元素的类型。Java的泛型不是。他们使用类型擦除来基本上掩盖正在进行的隐式转换。了解这一点很重要。

因此,当您创建对象数组时,您无法将其转换为可比较数组(或任何其他类型),因为这不正确。

举个例子。对于泛型,这是完全合法的:

List<String> list = new ArrayList<String>();
List<Integer> list2 = (List<Integer>)list;
list.add(3);

这也是你不能这样做的原因:

public <T> T newInstance(T t) {
  return new T(); // error!
}

即在运行时,不知道T的类。这就是为什么上面的代码更常写成:

public <T> T newInstance(T t, Class<T> clazz) {
  return clazz.newInstance();
}

因为泛型参数没有运行时类型。但是对于数组:

String arr[] = new String[10];
Integer arr2[] = (Integer[])arr; // error!

在这种情况下(恕我直言),您应该做的不是使用数组,而是使用.老实说,几乎没有理由在 a 上使用数组,泛型只是其中的一个例子。ArrayListArrayList

有关更好,更完整的解释,请参阅(优秀的)Java泛型常见问题解答

是否可以创建组件类型为具体参数化类型的数组?

否,因为它不是类型安全的。

数组是协变的,这意味着超类型引用的数组是子类型引用数组的超类型。也就是说,是 的超类型,并且可以通过 类型的引用变量访问字符串数组。Object[]String[]Object[]

...


答案 2

这里的其他答案通常都主张更好的方法(特别是建议使用ArrayList代替),但是在这个特定情况下,一个简单的答案可能是这样做:

hashTable = (T[])(new Comparable[tableSize]);

(即创建一个类型为 raw 的可比数组,而不是 Object)

如果您正确地将此数组的所有访问封装在Hash对象中,这应该可以工作,但是(正如其他答案所解释的那样),您可能会让自己容易受到攻击。