java常用集合

163 阅读5分钟

问题:

  • 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