emptyList不需要占用内存,而ArrayList每次new都会在堆中开辟内存空间存放对象,我们先通过代码验证一下
public class ListTest { private static final int printCount = 10000; public static void main(String[] args) { long freeMemory = Runtime.getRuntime().freeMemory(); System.out.println("freeMemory: " + freeMemory); for (int i = 0; i < printCount; i++) { List newList = new ArrayList(); } long freeMemoryNew=Runtime.getRuntime().freeMemory(); System.out.println("freeMemory use: "+(freeMemory-freeMemoryNew)); for(int i = 0;i < printCount; i++){ List emptyList = Collections.emptyList(); } long freeMemoryEmpty = Runtime.getRuntime().freeMemory(); System.out.println("freeMemory use: "+(freeMemoryNew-freeMemoryEmpty)); } }此时我们看一下执行结果
Connected to the target VM, address: '127.0.0.1:63534', transport: 'socket' Disconnected from the target VM, address: '127.0.0.1:63534', transport: 'socket' freeMemory: 253398816 freeMemory use: 1430376 freeMemory use: 0我们可以看出new ArrayList执行一万次会消耗1430376KB内存,而Collections.emptyList不会消耗内存。
那有人会说emptyList不也是new EmptyList()吗?
其实我们再仔细看下源码就发现emptyList是一个static变量,只会初始化一次,所以后续使用不会再初始化对象。此时我们可以得出结论,emptyList不占用内存,但是无法执行add等方法,new ArrayList()占用内存,但是会初始化对象数组,可以执行add等方法。
这个空的集合是不能调用.add(),添加元素的。因为直接报异常。因为源码就是这么写的:直接抛异常。
Collections里面没这么写,但是EmptyList继承了AbstractList这个抽象类,里面简单实现了部分集合框架的方法。
这里面的add方法最后调用的方法体,就是直接抛异常。
throw new UnsupportedOperationException();这么解释add报异常就对啦。
下面简单看下这个源码:
/** * Collections 类里面的方法如下,一步步往下看就是啦 */ public static final <T> List<T> emptyList() { return (List<T>) EMPTY_LIST; } //。。。。。 /** * Collections 类里面的方法如下,一步步往下看就是啦 */ public static final List EMPTY_LIST = new EmptyList<>(); //。。。。。 /** * Collections里面的一个静态内部类 */ private static class EmptyList<E> extends AbstractList<E> implements RandomAccess, Serializable { private static final long serialVersionUID = 8842843931221139166L; public Iterator<E> iterator() { return emptyIterator(); } public ListIterator<E> listIterator() { return emptyListIterator(); } public int size() {return 0;} public boolean isEmpty() {return true;} public boolean contains(Object obj) {return false;} public boolean containsAll(Collection<?> c) { return c.isEmpty(); } public Object[] toArray() { return new Object[0]; } public <T> T[] toArray(T[] a) { if (a.length > 0) a[0] = null; return a; } public E get(int index) { throw new IndexOutOfBoundsException("Index: "+index); } public boolean equals(Object o) { return (o instanceof List) && ((List<?>)o).isEmpty(); } public int hashCode() { return 1; } // Preserves singleton property private Object readResolve() { return EMPTY_LIST; } }除了这个emptyList,之外,还有类似的,emptyMap,emptySet等等。具体看下图,都是一个套路。
参考:https://blog.csdn.net/m0_46309515/article/details/107161340