问题:
- 4.3 java常用集合:
- 4.3.1 数据结构有哪些,数组,链表,树,图,表
- 4.3.2 ArrayList 和 LinkedList 用的是哪一种?数组,链表
- 4.3.3 HashMap 的原理,散列列表
- 4.3.4 HashMap(5) 长度是多少?
- 4.3.5 为什么是 2 的幂次,各个版本之间的区别
- 4.4 缓存的淘汰策略 8M ,超过了怎么淘汰的? LruCache 的底层就是 LinkedHashMap (散列列表的双链回环) 前移编码, 最近最少使用原则
- ArrayList、LinkedList、HashMap(大小,个版本的区别)
Collection架构与源码分析 ArrayList和源码分析 LinkedList和源码分析 ArrayList和LinkedList的区别 fail-fast机制 Map架构与源码分析 HashMap和源码分析 HashTable和源码分析 TreeMap和源码分析(一) TreeMap和源码分析(二) HashMap和HashTable的区别
##Collection框架: collection是一个接口,同时实现collection接口的还有List接口和Set接口。List是有序的队列,可以存储重复的元素。Set则不能存储重复元素 1.AbstractCollection:实现了collection绝大部分方法,iterator()和size()之外。要想实现Collection接口,直接继承AbstractCollection就行。 2.AbstractList:继承AbstractCollection,实现List绝大部分方法,除了size()、get(int location)。要想实现List接口,直接继承AbstractList就行。 3.AbstractSet:继承AbstractCollection,实现Set绝大部分方法
通过Iterator来遍历集合。
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new RuntimeException("Stub!");
}
default void forEachRemaining(@NonNull Consumer<? super E> action) {
throw new RuntimeException("Stub!");
}
}
##ArrayList和源码分析:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}
**ArrayList:继承了AbstractList,同时实现了RandomAccess接口,因此除了Iterator遍历,还可以随机访问数据。实现了Cloneable接口,即覆盖了函数clone(),能被克隆。arrayList它是一个数组队列,相当于动态数组。**其中增加和删除数据时,会实时的把数据前移或后移,调用
//把elementData的从index开始数据从index+1向后移动
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//向左挪一位,index位置原来的数据已经被覆盖了
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData是Object[]类型的数组,它保存了添加到ArrayList中的元素。elementData数组的大小会根据ArrayList容量的增长而动态的增长。 size则是动态数组实际数量的大小。 这里只展示部分源码,查看全部在这里
//非线程安全
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//序列版本号
private static final long serialVersionUID = 8683452581122892189L;
//默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
//空数组,用来实例化不带容量大小的构造函数
private static final Object[] EMPTY_ELEMENTDATA = {};
//保存ArrayList中数据的数组
private transient Object[] elementData;
//ArrayList中实际数据的数量
private int size;
/******************************** Constructor ***********************************/
//ArrayList带容量大小的构造函数
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity]; //新建一个数组初始化elementData
}
//不带参数的构造函数
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;//使用空数组初始化elementData
}
//用Collection来初始化ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); //将Collection中的内容转换成数组初始化elementData
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
//给数组扩容,该方法是提供给外界调用的,是public的,真正扩容是在下面的private方法里
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureCapacityInternal(int minCapacity) {
//如果是个空数组
if (elementData == EMPTY_ELEMENTDATA) {
//取minCapacity和10的较大者
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//如果数组已经有数据了
ensureExplicitCapacity(minCapacity);
}
//确保数组容量大于ArrayList中元素个数
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //将“修改统计数”+1
//如果实际数据容量大于数组容量,就给数组扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//分配的最大数组空间
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//增大数组空间
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //在原来容量的基础上加上 oldCapacity/2
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity; //最少保证容量和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;
}
//将e添加到ArrayList中
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//将element添加到ArrayList的指定位置
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
//将index以及index之后的数据复制到index+1的位置往后,即从index开始向后挪了一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element; //然后在index处插入element
size++;
}
//删除ArrayList指定位置的元素
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
//向左挪一位,index位置原来的数据已经被覆盖了
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//多出来的最后一位删掉
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
##LinkedList和源码分析 lindedList和Collection关系:
ublic class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
}
LinkedList是一个继承AbatractSequentialList的双向链表。实现了List接口,能对它进行队列操作。实现了Deque接口,即能将LinkedList当作双端队列使用。
LinkedHashMap实现原理和缓存淘汰策略 LinkedHashMap 的实现原理 LruCache解析 如何用LinkedHashMap实现LRU