use*_*553 10 java generics arraylist
在Java ArrayList<E>实现基础上的一个对象数组.
任何人都可以解释一下为什么ArrayList<E>使用数组Object[]实现数据存储而不是E[]?使用有什么好处Object[]?
在Java中,创建泛型类型的数组并不简单.
简单的方法不编译:
public class Container<E> {
E[] arr = new E[3]; // ERROR: Cannot create a generic array of E
}
Run Code Online (Sandbox Code Playgroud)
替换E为Object,一切都很好(以容器实现中其他地方增加的复杂性为代价).
有其他方法,但它们提供了一组不同的权衡.有关详细讨论,请参阅如何在Java中创建通用数组?
首先,要意识到数组对象的实际运行时类型必须是Object[].这是因为数组在运行时知道它们的组件类型(不同的数组类型在运行时实际上是不同的类型),因此您需要在创建数组时指定组件类型,但是ArrayList对象在运行时不知道它的类型参数.
也就是说,实例变量的编译时类型可以声明为Object[]或者E[],具有不同的优点和缺点:
如果它被声明为Object[]:
private Object[] arr;
// to create it:
arr = new Object[3];
// to get an element:
E get(int i) { return (E)arr[i]; }
Run Code Online (Sandbox Code Playgroud)
这样做的缺点是,E每次从中取出它时都必须将其强制转换,这意味着您基本上将它用作预先通用的容器.
如果它被声明为E[]:
private E[] arr;
// to create it:
arr = (E[])new Object[3];
// to get an element:
E get(int i) { return arr[i]; }
Run Code Online (Sandbox Code Playgroud)
这样做的好处是,当您从中获取内容时,您不再需要进行强制转换 - 它提供了arr类似于通用容器的使用类型检查.缺点是,从逻辑上讲,强制转换是谎言 - 我们知道我们创建了一个运行时类型为的对象Object[],因此它不是一个实例E[],除非E是Object.
但是,这样做没有直接问题,因为它E被删除到Object类的实例方法中.问题出现的唯一方法是,如果对象以某种方式暴露给类的外部(例如,在方法中返回,放入公共字段等),其容量使用其类型E[](不是):
// This would be bad. It would cause a class cast exception at the call site
E[] getArray() { return arr; }
Run Code Online (Sandbox Code Playgroud)
但是ArrayList,实际上任何设计合理的容器类都不会将实现细节(如内部数组)暴露给外部.除其他外,它会破坏抽象.因此,只要这个类的作者知道没有暴露这个数组,这样做是没有问题的(保存可能会让下一个看到代码并且不知道它的人感到困惑),并且可以自由地使用它这种方式带来的类型检查增加的优点.