[英]Difference between ArrayList<>() and ArrayList<>(){}
[英]Difference between an empty ArrayList and an ArrayList with null elements?
我正在为解析 JSON 的 REST 服务编写一些验证器,我发现了一些对我来说听起来很奇怪的东西(我根本不是JAVA 专家)。
考虑有两个ArrayLists :
ArrayList<Object> list1 = new ArrayList<Object>();
ArrayList<Object> list2 = new ArrayList<Object>();
这两个列表有一些共同点:它们完全是空的(或充满 null 个元素)。 但如果我这样做:
list1.add(null);
虽然两者都完全是空的,但它们的行为却完全不同。 并使某些方法的结果大不相同:
System.out.println(list1.contains(null)); //prints true!
System.out.println(list2.contains(null)); //prints false
System.out.println(CollectionUtils.isNotEmpty(list1)); //prints true
System.out.println(CollectionUtils.isNotEmpty(list2)); //prints false
System.out.println(list1.size()); //prints 1
System.out.println(list2.size()); //prints 0
做一些研究,看看这些方法中的每一个的实现,您可以确定这些差异的原因,但仍然不明白为什么区分这些列表是有效的或有用的。
提前致谢!!!
编辑:
我基本上同意答案,但我还没有完全相信。 这是方法 remove 的实现:
/**
* Removes the first occurrence of the specified element from this list,
* if it is present. If the list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
* <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
* (if such an element exists). Returns <tt>true</tt> if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
所以,现在如果我这样做:
ArrayList<Object> list = new ArrayList<Object>();
list.add(null);
System.out.println(list.contains(null)); //prints true!
list.remove(null);
System.out.println(list.contains(null)); //prints false!
我缺少什么?
包含null
的列表不为 空 。 它包含null
。 列表允许包含null,因此如果需要,可以将null放入其中。
幸运的是,您根本不必是Java专家或专家。
想到这一点的最佳方式就像一个停车场。 带有null元素的数组就像一个没有停放的停车场。 空阵列就像停车场的计划。
如果List
包含零元素,则List
为空。 这既是术语的自然含义,也是isEmpty()
方法执行的测试。
null
是任何ArrayList
可以包含的值作为元素。 显然,在这种情况下,列表至少有一个元素,因此不是空的。 无论List
的初始状态如何,如果该List
的add(null)
调用正常完成,则之后列表不为空。 类似地,列表中的每个null
元素都会影响其大小。
为什么
add(item)
不验证item!=null
?
问约书亚布洛赫 。 他设计了它。 大多数人认为他是一个非常聪明的人,并认为Collections API非常成功。
说真的, List
s可能包含null
元素是一种设计选择。 (允许实现拒绝空值,但ArrayList
作为通用实现接受它们)。
如果列表中充满空值,为什么包含(null)表示为false?
它没有。 不要只听我的话 - 你提出的数据也与你相矛盾。
整个混淆源于您创建的ArrayLists充满空值的错误初始假设。 它们不是,它们完全是空的 - 意味着它们没有元素 。 因此,如果对它们调用contains(null)
,则会得到false ,而当调用isEmpty()
时,则为true 。
一旦你向list1添加了null,它就不再是空的,并且确实包含一个null元素 - list2仍然是空的,但仍然不包含null 。
在上一个代码示例中,对Collections.isNotEmpty的第二次调用肯定不会返回true 。 该列表有一个null元素,你删除它,所以它再次为空。
这里的主要外卖是:
区别在于 List 的大小,而不是它的容量。 实例化 new ArrayList<>(5)
时,初始容量设置为5 ,但大小保持为 0 ,因为我们没有添加任何元素。 如果我们调用add(null)
,只有元素size()
会增加,并且遍历元素数组的所有函数将保持在 List 的大小之间,而不是capacity之间。
这样当我们需要快速添加新元素时,数组不会被复制到另一个大小为 + 1 的数组中,而是 Java 在大小等于它时将容量增加一半,以通过减少函数来提高性能执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.