更新:这个回答得到了更多的关注和upvotes比我认为它应得的基本上复制粘贴的JDK源代码,所以我会尝试把它变成值得的东西。
Java泛型的设计看起来像是真实的,具体化的,多实例,C++ - 或C#泛型风格。这意味着对于像ArrayList<E>
这样的类型,我们预计ArrayList<String>
的行为与每个出现的E
已被替换为String
一样。换句话说,这样的:
private Object[] elementData = new Object[size];
public E get(int i) {
return (E) elementData[i];
}
String str = list.get(0);
应该成为这样的:
private Object[] elementData = new Object[size];
public String get(int i) {
return (String) elementData[i];
}
String str = list.get(0);
现在,你可能知道,那并不是他们如何工作。对于现在(大部分)很长时间后面的兼容性原因,Java泛型是通过类型擦除实现的,其中E
实际上被替换为Object
,并且铸造到String
被插入到中,并在需要时调用代码。这意味着该代码实际上变成是这样的:
private Object[] elementData = new Object[size];
public Object get(int i) {
return elementData[i];
}
String str = (String) list.get(0);
演员到(E)
已经消失,并在调用点又出现了。如果通话网站忽略了结果,剧组将完全消失!这就是为什么它给出了“未经检查”的警告。
现在想象一下,如果elementData
有型E[]
相反,你的建议。也就是说,代码如下所示:
private E[] elementData = (E[]) new Object[size];
public E get(int i) {
return elementData[i];
}
String str = list.get(0);
由于擦除,我们知道它被转换为与上述相同的东西。但是如果我们有具体化的泛型像我们希望我们所做的,它应该是这样的:
private String[] elementData = (String[]) new Object[size];
// ClassCastException: Object[] is not a String[]
本质上讲,我们已经写了一些代码,将会在运行时崩溃,它在所有工作的唯一原因是,Java的泛型实施假装比现在更好。我们向编译器撒谎以说服它接受脆弱的代码。
它很脆!我们碰巧避免了运行时崩溃,因为数组永远不会转义类。但是如果这样做的话,它会导致难以预测的地方出现ClassCastException
。如果Java 9引入了泛化的泛型呢?第一个实现会继续工作,但是这个会破坏。
这就是为什么大多数合理的Java编码规范要求非检查类型转换为类型正确的原因。 (E) elementData[i]
是类型正确的,因为ArrayList
确保只有E
s可以存储在elementData
中。 (E[]) new Object[size]
从来没有类型正确,除非E
是Object
。
还有其他的好处。在Java 8中,elementData
字段可以具有特殊的哨兵值:
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
您似乎认为“E”是真实的。这是你想象中的无花果牛顿。在ArrayList类被编译时,数组的类是固定的,回到Java代工中。 – 2014-09-05 22:59:23
@HotLicks“据我所知,编译器运行后,类型擦除将E []转换为Object []”..“如果使用它E [],下面的代码[它不是]必须[使用强制转换]” – user2864740 2014-09-05 23:00:04
声明E []可能会改进源代码,但最终的编译结果将是相同的。 – 2014-09-05 23:00:28