前言
jdk 版本 jdk1.8.0_161
集合实现:
通用实现:为日常使用而设计的
Interfaces | Hash table Implementations | Resizable array Implementations | Tree Implementations | Linked list Implementations | Hash table + Linked list Implementations |
---|---|---|---|---|---|
Set |
HashSet |
TreeSet |
LinkedHashSet |
||
List |
ArrayList |
LinkedList |
|||
Queue |
|||||
Deque |
ArrayDeque |
LinkedList |
|||
Map |
HashMap |
TreeMap |
LinkedHashMap |
概览
相关类接口 UML 图(idea 生成)
说明:
Iterable : 始于 1.5版本,实现该接口的类 可以使用 for-each 循环语句完成遍历。持有 迭代器对象 Iterator;
Collection: 基类;
AbstractCollection: Collection 接口的一个骨架实现,目的是减少后续实现类实现抽象方法的数量;
List: 有序集合(也被称为一个序列(sequence)),使用该接口可以精确的控制列表中每个元素的插入位置,可以通过索引快速访问、查询元素。list 允许重复元素,允许多个null 元素;
RandomAccess:标记接口(marker interface),用来表示 List 实现类 支持 快速随机访问。这个接口的目的是当 随机 或者 顺序 获取 list 时,允许 泛型算法 来改变 他们的行为 以 提供 好的性能;
AbstractList:List 接口的一个骨架实现;对于需要 随机存取的 数据类型需要继承该类,比如 ArrayList 的数组,该抽象类对 hashcode 方法 和 equals 方法 进行了重写
Cloneable:实现该接口 表示 ,对象支持 克隆,否则会抛出异常;
Serializable:实现该接口的类表示 开启 类的序列化;
ArrayList :
List 接口 可变数组的实现,和 Vector基本相同, 区别在于 ArrayList 是 非同步的,Vector 是 同步的 (线程安全的);
特点:有序的(元素的插入顺序有序);可以保存 null 值;允许重复值;
size,isEmpty,get,set,iterator,listIterator 操作花费是 常量时间;
add 操作 以 摊还常量时间( amortized constant time) 运行,即 添加 n个元素的时间花费 为 O(n);
其他操作是线性时间运行(粗略来说),常量因子比 LinkedList 的低;
每个 ArrayList 实例 有一个 capacity, capacity 是 存储 元素的数组的大小。默认为 10,当元素 被添加到 ArrayList 中,他的 capacity 会自动增长。
该实现类是非同步的,如果在多线程下使用,可以使用 Collections.synchronizedList() 静态方法实现。
通过 Iterator 类和 ListIterator 方法 返回的 iterators 是 快速失败(fail-fast):如果 在 iterator 被创建后,list 结构上被修改,这种修改不是通过 iterator 自己的 remove 和 add 方法实现的,那么 iterator 会抛出 一个 ConcurrentModificationException;如下示例将抛出异常:
@Test public void failFastTest() { List<String> names = this.createList(); for (Iterator iterator = names.iterator();iterator.hasNext();) { // iterator.next(); // iterator.remove(); names.remove(iterator.next()); } // LOGGER.debug("names size is {}", names.size()); // 0 } private List<String> createList() { List<String> names = new ArrayList<>(); names.add("小明"); names.add("小强"); names.add("小红"); names.add("小张"); return names; }
ArrayList 源码 解析
构造函数:
private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; /** * 构造一个空 list,当需要添加元素时,初始化容量,最小为10 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * 通过给定的初始容量值构造一个 空 list */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * 构造一个包含指定 collection 中元素 的 list, 顺序为 collection 对应 迭代器返回的顺序 * */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
扩容机制:向容器中添加元素时会进行容量确认
添加单个元素(添加多个元素 为 size + numNew):
public boolean add(E e) { ensureCapacityInternal(size + 1); //处理内部容量,size 为 容器中存储的元素个数,此时总元素个数为 size 加 1 elementData[size++] = e;//先在容器的 size 处添加元素,然后 size 加 1 return true; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } // 计算容量,是否为默认容量 private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {// == 比较地址,是否为默认容量 return Math.max(DEFAULT_CAPACITY, minCapacity);//取默认容量 和 传入 容量值中最大的一个 } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { modCount++;//AbstractList 中定义的字段,记录 list 结构上修改的次数,给迭代器使用 // 超出 数组长度,扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length;//原始容量 int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容后的容量,左移一位除以2,扩容 1.5倍 if (newCapacity - minCapacity < 0)//扩容后的容量仍然不能满足需求 newCapacity = minCapacity;//直接使用要求的容量 if (newCapacity - MAX_ARRAY_SIZE > 0)//扩容后的容量超出数组最大界定容量 newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);//构造新数组 } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); //三目运算符,请求容量 大于数组最大可分配容量的话,返回 整型最大值, //否则返回数组的可分配最大容量 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** * 数组可以分配的最大容量 * 一些 虚拟机会在数组中保留 一些 头信息 *如果尝试分配更大容量,则会导致 * OutOfMemoryError:请求数组大小超出 VM 限制 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
因为函数式接口的出现,jdk 1.8 新增了不少 方法:
forEach 方法:可以直接遍历 集合;重写 Iterable 接口中的默认方法;使用 Consumer 函数式接口
Iterable 接口中的默认方法:
default void forEach(Consumer<? super T> action) { // Consumer 接收一个参数,不返回任何值函数式接口 Objects.requireNonNull(action); for (T t : this) { action.accept(t); //调用 Consumer 中的方法 } }
ArrayList 类中重写的方法:
@Override public void forEach(Consumer<? super E> action) { Objects.requireNonNull(action); final int expectedModCount = modCount; @SuppressWarnings("unchecked") final E[] elementData = (E[]) this.elementData; final int size = this.size; for (int i=0; modCount == expectedModCount && i < size; i++) { //最原始的循环方法 action.accept(elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } }
spliterator 方法:Spliterator 是一个用于 遍历 和 分隔 源数据 的函数式接口 ;
@Override public Spliterator<E> spliterator() { return new ArrayListSpliterator<>(this, 0, -1, 0); }
removeIf 方法:移除符合条件的 元素;使用 Predicate 函数式接口
@Override public boolean removeIf(Predicate<? super E> filter) { // Predicate 断言一个 参数值 的 函数式接口,返回 true or false Objects.requireNonNull(filter); // figure out which elements are to be removed // any exception thrown from the filter predicate at this stage // will leave the collection unmodified int removeCount = 0; final BitSet removeSet = new BitSet(size); final int expectedModCount = modCount; final int size = this.size; for (int i=0; modCount == expectedModCount && i < size; i++) { @SuppressWarnings("unchecked") final E element = (E) elementData[i]; if (filter.test(element)) { removeSet.set(i); removeCount++; } } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } // shift surviving elements left over the spaces left by removed elements final boolean anyToRemove = removeCount > 0; if (anyToRemove) { final int newSize = size - removeCount; for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) { i = removeSet.nextClearBit(i); elementData[j] = elementData[i]; } for (int k=newSize; k < size; k++) { elementData[k] = null; // Let gc do its work } this.size = newSize; if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } modCount++; } return anyToRemove; }
replaceAll 方法: 替换指定的元素;使用 UnaryOperator 函数式接口
@Override @SuppressWarnings("unchecked") public void replaceAll(UnaryOperator<E> operator) {// UnaryOperator 对单个数的操作,返回和操作数类型相同的结果 Objects.requireNonNull(operator); final int expectedModCount = modCount; final int size = this.size; for (int i=0; modCount == expectedModCount && i < size; i++) { elementData[i] = operator.apply((E) elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } modCount++; }
sort 方法: 排序;使用 Comparator 函数式接口,
@Override @SuppressWarnings("unchecked") public void sort(Comparator<? super E> c) { final int expectedModCount = modCount; Arrays.sort((E[]) elementData, 0, size, c); if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } modCount++; }
代码展示:
@Test public void methodTest() { List<String> fruits = this.createFruit(); //forEach方法 的 lambda fruits.forEach(fruit -> { System.out.println(fruit); }); //forEach方法 的方法引用 fruits.forEach(System.out::println); // removeIf 方法 fruits.removeIf(s -> s.equals("orange")); // replaceAll 方法 fruits.replaceAll(s -> { if ("apple".equals(s)) { return "watermelon"; } return s; }); // 避免 lambda 体的 写法 fruits.replaceAll(this::unaryOperator); System.out.println(fruits); } private String unaryOperator(String s) { if ("apple".equals(s)) { return "watermelon"; } return s; } public List<String> createFruit() { List<String> fruits = new ArrayList<>(); fruits.add("apple"); fruits.add("orange"); return fruits; }