ArrayList的不同实现

时间:2010-01-06 12:10:23

标签: arraylist java openjdk

我们收到此错误

java.lang.NullPointerException
    at java.util.ArrayList.<init>(Unknown Source)
    at de.mystuff.ExtendedArrayList.<init>(ExtendedArrayList.java:38)

其中ExtendedArrayList:38是

new ArrayList(new ArrayCollection<E>(data));

简而言之:ArrayList构造函数有时似乎会阻碍我们自己开发的Collection实现ArrayCollection。

即使使用与我们客户分发的完全相同的版本,我也无法在我的计算机上重现它。

但我并非100%确定他们正在使用我们所包含的JRE。 所以,我搜索了一些ArrayList.java源代码,发现openJDK 6b17有这个

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

这是有道理的,因为如果没有数据,我们的 ArrayCollection.toArray()会返回 null 。对于我们正在使用的1.5.0_09 Sun JDK / JRE实现,这个构造函数看起来很安全(并且毫无例外地工作)。
但openJDK似乎只为unix世界发布。此代码是否也是Windows JRE的一部分?如果是这样,哪个版本?

注意:我知道我们必须修复我们的类,但我想确保我理解NullPointerException的原因。

4 个答案:

答案 0 :(得分:8)

为什么你认为返回null而不是返回零长度数组是合法的?

List的javadoc不允许这样做。因此,原因是所有其他JRE都做出了相同的假设。 Sun实现在我的Mac上发布的消息来源肯定会做出这样的假设。

答案 1 :(得分:1)

根据J2SE 5.0 API Documentation

  

ArrayList public   ArrayList(集合c)   构造一个包含的列表   指定集合的​​元素,   按照它们返回的顺序   集合的迭代器。 ArrayList   实例的初始容量为   110%的指定大小   采集。

     

参数:c - 其集合的集合   元素将被放入其中   名单。

     

抛出:
NullPointerException - 如果指定的集合为null。

所以

new ArrayList(new ArrayCollection<E>(data));
如果NullPointerException为空,则

抛出new ArrayCollection<E>(data)

编辑:

140     /**
141      * Constructs a list containing the elements of the specified
142      * collection, in the order they are returned by the collection's
143      * iterator.
144      *
145      * @param c the collection whose elements are to be placed into this list
146      * @throws NullPointerException if the specified collection is null
147      */
148     public ArrayList(Collection<? extends E> c) {
149     elementData = c.toArray();
150     size = elementData.length;
151     // c.toArray might (incorrectly) not return Object[] (see 6260652)
152     if (elementData.getClass() != Object[].class)
153         elementData = Arrays.copyOf(elementData, size, Object[].class);
154     }

OpenJDK在ArrayList构造函数中有这些行。根据这个构造函数的文档:     146 * @throws NullPointerException如果指定的集合为空

如果collection为null,它只应抛出异常。

这些行:

149     elementData = c.toArray();
150     size = elementData.length;
调用

Collection.toArray().length方法。

在您的实现中Collection.toArray()为null,因此会抛出NullPointerException。

根据J2SE Collection.toArray文档

  

toArray Object [] toArray()返回一个   包含所有元素的数组   在这个集合中。如果收藏   对什么订单做出任何保证   它的元素由它返回   迭代器,这个方法必须返回   元素顺序相同。

     

返回的数组将是“安全的”   没有引用它   由此系列维护。 (在   换句话说,这种方法必须分配   一个新的数组,即使这个集合是   由数组支持)。来电者是   因此可以自由修改返回的   阵列。

     

这种方法充当了它之间的桥梁   基于数组和基于集合的API。

     

返回:包含所有的数组   这个集合中的元素

所以它不应该返回null。 它应该返回一个空数组。所以.length将返回0并且没有问题。

答案 2 :(得分:1)

List#toArray方法永远不应该返回null。您的ArrayCollection实现可能覆盖了toArray方法,并且可能为空集合而不是新的空数组返回null。

是的,不同的JRE可能表现不同。有些人可能会容忍null而不是数组而其他人则不会。

我将启动Java decompiler并查看此ArrayList构造函数的实际实现。

答案 3 :(得分:1)

我认为您没有准确指定您正在使用哪个JRE版本/供应商,但这里是Sun JDK 1.6.0_17的相关构造函数的源代码(如果您还不知道,大多数类的来源)在java命名空间附带JDK):

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
         elementData = Arrays.copyOf(elementData, size, Object[].class);
}

(评论是作者的,不是我的)

这应该非常清楚地显示此构造函数中NPE的潜在原因:如果c为null或(在您的情况下)c.toArray()返回null。