我们收到此错误
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的原因。
答案 0 :(得分:8)
为什么你认为返回null而不是返回零长度数组是合法的?
List
的javadoc不允许这样做。因此,原因是所有其他JRE都做出了相同的假设。 Sun实现在我的Mac上发布的消息来源肯定会做出这样的假设。
答案 1 :(得分:1)
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。