我正在构建一个通用的HashTable类,我们使用简单的Java .hashCode()方法将一个键转换为hash,以数组大小为模,并存储在结果的索引中。唯一的问题是,教授希望我们不仅存储价值,还存储我们散列的关键。为此,我创建了一个Data类,用于存储和获取两个值:
private class Data {
private K key;
private V value;
public Data(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
非常简单的东西。当我尝试创建数据项数组以保存散列值和创建它们的键时,会遇到困难。 K和V是HashTable类声明中指定的通用值:
public class HashTable<K,V> implements Table<K,V>
当我第一次创建类时,我只是在对象数组上使用强制转换来创建V的数组,但由于我们需要存储这两个值,所以我决定创建Data类并存储它们。但是当我用我的
尝试时hashArray = (Data[])new Object[arraySize];
它给了我错误
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lproject3.HashTable$Data;
这使我无法创建数据类型的数组。是否有另一种方法可以在不使用List的情况下存储它(因为这是分配的参数)?
答案 0 :(得分:4)
Object[]
不是Data[]
。该转换在运行时必然会失败。但由于那里已经知道了这种类型,为什么不直接创建Data[]
?没有必要创建Object[]
并尝试投射它。
现在回答你的另一个问题,下面的演员:
V[] arr = (V[]) new Object[arraySize];
有效,因为V
的类型在运行时是未知的。类型信息被删除。并且因为类型参数的擦除是最左边的边界,在这种情况下是Object
,所以在运行时上面的转换如下所示:
Object[] arr = (Object[]) new Object[arraySize];
好像很好,不是吗?但是,只要让数组转义类,这种方式也会失败,并将返回值分配给任何引用,如下所示:
HashTable<String, Integer> map = new HashTable<String, Integer>();
// suppose you have a getter to get the array stored
Integer[] arr = map.getValueArray();
上面第二行将在运行时抛出ClassCastException
,原因与上面发布的相同。因此,将Object[]
转换为V[]
将起作用,直到您不让数组逃脱该类。
现在,考虑另一种情况,你给V
绑定,说V extends Comparable<V>
,看看会发生什么;
public class MyClass<T extends Comparable<T>> {
T[] arr;
public MyClass() {
arr = (T[])new Object[0];
}
}
在这种情况下,类型参数T
的擦除为Comparable
,因此构造函数中的强制转换将被删除为:
arr = (Comparable[]) new Object[0];
这将再次抛出ClassCastException
,无论你是否让数组逃脱了类。
所以,重点是,在创建泛型类型数组时需要非常小心。
另见: