Java中的通用数组
好的,我一直在谷歌网上,我似乎无法find任何解决我的问题。 我find了很多解决scheme,但都没有。
我需要创build一个generics的数组。 但genericstypes本身扩展了Comparable。 当我尝试以下:
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; } }
问题是该对象不能被转换为扩展Comparable的generics。 有没有解决的办法?
generics和数组基本上不混合。 简单的答案是,你可以解决这个问题。 更长的答案是,你可能不应该,我会解释为什么。
你可以像这样使用Array.newInstance()
private Comparable[] hashtable; ... hashtable = (Comparable[])Array.newInstance(Comparable.class, tableSize);
但是你不能创build你的参数化types的数组。
数组是协变的 。 这意味着它们在运行时保留其元素的types。 Java的generics不是。 他们使用types擦除基本上掩盖正在进行的隐式转换。 理解这一点很重要。
所以当你创build一个Object数组时,你不能将它转换成一个Comparable数组(或者任何其他的types),因为这是不正确的。
给你举个例子。 随着generics这是完全合法的:
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(); }
因为它们的generics参数没有运行时types。 但是用数组:
String arr[] = new String[10]; Integer arr2[] = (Integer[])arr; // error!
在这种情况下你应该做什么(imho)不是使用数组,而是使用ArrayList
。 坦率地说,在ArrayList
上使用数组几乎没有什么理由,generics只是其中的一个例子。
要获得更好更完整的解释,请参阅(优秀) Javagenerics常见问题解答 :
我可以创build一个组件types是一个具体的参数化types的数组吗?
不,因为它不是types安全的。
数组是协变的,这意味着超types引用的数组是一个子types引用数组的超types。 也就是说,
Object[]
是String[]
的超types,可以通过Object[]
types的引用variables访问string数组。…
这里的其他答案一般都提倡更好的方法(特别是build议使用ArrayList),但是在这个特定情况下可以做一个简单的回答:
hashTable = (T[])(new Comparable[tableSize]);
(即创build一个types原始数组而不是对象)
如果你正确地封装了你的Hash对象中的这个数组的所有访问权限,这应该是可行的,但是(正如其他答案所解释的),你可能会让自己变得脆弱。
你正在尝试的演员
(T[])(new Object[tableSize]);
失败,因为数组中的项目是Object的实例。 对象不扩展Comparable<String>
,所以cast(T [])失败,因为T被定义为:
T extends Comparable<String>
为了解决这个问题:
- 实例化数组,使其项目是扩展了
Comparable<String>
的某个类的实例 - 将
hashTable
从一个Array(不是genericstypes)更改为generics集合types,例如List<T> hashTable = new ArrayList<T>(tableSize>)
当你需要实例化一个genericstypes的东西时,你经常遇到问题。 解决这个问题的最简单的方法是传递类的实际上将被存储在构造函数中。 这样你可以从实际的types构造。 尝试这样的事情:
public class Hash<T extends Comparable<String>> { Hash(int records, double load, Class<T> class) { tableSize = (int)(records / loadFactor); tableSize = findNextPrime(tableSize); hashTable = java.lang.reflect.Array.newInstance(class, tableSize); } private T[] hashTable; private int tableSize; }
其他人提出的强制转换对我来说并不起作用,抛出了非法铸造的例外。
但是,这种隐式转换工作正常:
Item<K>[] array = new Item[SIZE];
Item是我定义的包含成员的类:
private K value;
这样你得到一个Ktypes的数组(如果该项只有值)或者你想在类Item中定义的任何genericstypes。