深入剖析Java集合源码

服务器

  1 Java集合概览

  2 List接口下集合源码分析

  2.1 ArrayList

  (1)集合体系

  (2)基本使用

  //实例化

  ArrayList<Integer> list = new ArrayList<>(5);

  //添加元素

  list.add(1);

  list.add(2);

  //遍历元素

  for (Integer i : list) {

  System.out.print(i);

  }

  for (int i = 0; i < list.size(); i++) {

  System.out.print(list.get(i));

  }

  //删除元素

  System.out.println(list.remove(0));

  (3)源码剖析

  线程安全问题:线程不安全public boolean add(E e) {

  ensureCapacityInternal(size + 1); // Increments modCount!!

  elementData[size++] = e;

  return true;

  }理由:没有任何线程同步机制和分段锁等保护线程安全的措施扩容机制:当元素添加满时将数组大小扩大1.5倍//主要是调用grow方法进行扩容

  private void grow(int minCapacity) {

  // overflow-conscious code

  int oldCapacity = elementData.length;

  int newCapacity = oldCapacity + (oldCapacity >> 1);

  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);

  }元素是否可以为null:可以为nullpublic boolean add(E e) {

  ensureCapacityInternal(size + 1); // Increments modCount!!

  elementData[size++] = e;

  return true;

  }添加元素时并没有代码要求元素不能为null2.2 LinkedList

  (1)集合体系

  (2)基本使用

  //实例化

  LinkedList linkedList = new LinkedList();

  //添加元素

  linkedList.add(23);

  linkedList.add(44);

  linkedList.add(12);

  //删除元素,删除的是第一个结点

  linkedList.remove();

  //修改某个结点对象

  linkedList.set(1, 999);

  //获取链表的第二个对象

  Object o = linkedList.get(1);

  //遍历

  Iterator iterator = linkedList.iterator();

  while (iterator.hasNext()) {

  Object next = iterator.next();

  System.out.print(next);

  }

  for (Object o1 : linkedList) {

  System.out.print(o1);

  }

  for (int i = 0; i < linkedList.size(); i++) {

  System.out.print(linkedList.get(i));

  }

  (3)源码剖析

  是否需要扩容:不需要扩容,添加元素时直接放在队列的尾部,由上一个元素的next指针指该元素public boolean add(E e) {

  linkLast(e);

  return true;

  }

  void linkLast(E e) {

  final Node<E> l = last;

  final Node<E> newNode = new Node<>(l, e, null);

  last = newNode;

  if (l == null)

  first = newNode;

  else

  l.next = newNode;

  size++;

  modCount++;

  }删除元素过程:将被删除元素的上一个节点的next指针指向被删除元素的下一个节点public E remove(int index) {

  checkElementIndex(index);

  return unlink(node(index));

  }

  E unlink(Node<E> x) {

  // assert x != null;

  final E element = x.item;

  final Node<E> next = x.next;

  final Node<E> prev = x.prev;

  if (prev == null) {

  first = next;

  } else {

  prev.next = next;

  x.prev = null;

  }

  if (next == null) {

  last = prev;

  } else {

  next.prev = prev;

  x.next = null;

  }

  x.item = null;

  size--;

  modCount++;

  return element;

  }2.3 Vector

  (1)集合体系

  (2)基本使用

  //实例化

  Vector vector = new Vector(18);

  //添加元素

  vector.add(100);

  (3)源码剖析

  是否线程安全:线程安全,具有互斥锁synchronizedpublic synchronized boolean add(E e) {

  modCount++;

  ensureCapacityHelper(elementCount + 1);

  elementData[elementCount++] = e;

  return true;

  }扩容机制:当元素添加满时默认将数组大小扩大2倍,可以实例化时指定扩容的大小capacityIncrementprivate void grow(int minCapacity) {

  // overflow-conscious code

  int oldCapacity = elementData.length;

  int newCapacity = oldCapacity + ((capacityIncrement > 0) ?

  capacityIncrement : oldCapacity);

  if (newCapacity - minCapacity < 0)

  newCapacity = minCapacity;

  if (newCapacity - MAX_ARRAY_SIZE > 0)

  newCapacity = hugeCapacity(minCapacity);

  elementData = Arrays.copyOf(elementData, newCapacity);

  }3 Set接口下集合源码分析

  3.1 HashSet

  (1)集合体系

  (2)基本使用

  HashSet hashSet = new HashSet();

  hashSet.add(null);

  hashSet.add(null);

  hashSet.add("2");

  System.out.println("hashSet=" + hashSet);

  hashSet.forEach(s -> System.out.println(s));

  hashSet.remove(null);

  System.out.println(hashSet.contains("2"));

  System.out.println(hashSet.contains(null));

  (3)源码剖析

  底层:HashMappublic HashSet() {

  map = new HashMap<>();

  }add方法:将HashMap的减存放元素,将HashMap的值放入空对象PRESENT,然后直接调用HashMap的add方法// Dummy value to associate with an Object in the backing Map

  private static final Object PRESENT = new Object();

  public boolean add(E e) {

  return map.put(e, PRESENT)==null;

  }元素是否可以为null:可以3.2 TreeSet

  (1)集合体系

  (2)基本使用

  TreeSet treeSet = new TreeSet(new Comparator() {

  //排序规则

  @Override

  public int compare(Object o1, Object o2) {

  return ((String) o1).compareTo((String) o2);

  }

  });

  treeSet.add("zs");

  treeSet.add("ls");

  treeSet.add("ww");

  treeSet.add("zl");

  (3)源码剖析

  自定义元素排序规则:TreeSet treeSet = new TreeSet(new Comparator() {

  //排序规则 o1和o2代表先后元素的比较规则 (String) o1).compareTo((String) o2表示比较字符串的阿斯卡码 相同时不放入

  @Override

  public int compare(Object o1, Object o2) {

  return ((String) o1).compareTo((String) o2);

  }

  });add方法:底层调用了TreeMap的put方法 m.put(e, PRESENT)public V put(K key, V value) {

  Entry<K,V> t = root;

  if (t == null) {

  compare(key, key); // type (and possibly null) check

  root = new Entry<>(key, value, null);

  size = 1;

  modCount++;

  return null;

  }

  int cmp;

  Entry<K,V> parent;

  // split comparator and comparable paths

  Comparator<? super K> cpr = comparator;

  if (cpr != null) {

  do {

  parent = t;

  cmp = cpr.compare(key, t.key);

  if (cmp < 0)

  t = t.left;

  else if (cmp > 0)

  t = t.right;

  else

  return t.setValue(value);

  } while (t != null);

  }

  else {

  if (key == null)

  throw new NullPointerException();

  @SuppressWarnings("unchecked")

  Comparable<? super K> k = (Comparable<? super K>) key;

  do {

  parent = t;

  cmp = k.compareTo(t.key);

  if (cmp < 0)

  t = t.left;

  else if (cmp > 0)

  t = t.right;

  else

  return t.setValue(value);

  } while (t != null);

  }

  Entry<K,V> e = new Entry<>(key, value, parent);

  if (cmp < 0)

  parent.left = e;

  else

  parent.right = e;

  fixAfterInsertion(e);

  size++;

  modCount++;

  return null;

  }3.3 LinkedHashSet

  (1)集合体系

  (2)基本使用

  LinkedHashSet linkedHashSet = new LinkedHashSet();

  linkedHashSet.add(1);

  linkedHashSet.add(2);

  linkedHashSet.add(new Student(1));

  linkedHashSet.add(new Student(1));//只显示一个Student(1)

  (3)源码剖析

  略

  4 Map接口下集合源码分析

  4.1 HashMap

  (1)集合体系

  (2)基本使用

  //实例化

  HashMap<String, Object> map = new HashMap<>();

  //放入元素

  map.put("1", "zs");

  map.put("2", "ls");

  map.put("3", "ww");

  //获取元素

  Object o = map.get("1");

  //遍历

  map.forEach((k, v) -> {

  System.out.println(k+"-"+v);

  });

  (3)源码剖析

  哈希表默认大小和加载因子:默认大小16,加载因子0.75,加载因子表示哈希表使用了75%则进行扩容static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

  static final float DEFAULT_LOAD_FACTOR = 0.75f;

  public HashMap(int initialCapacity, float loadFactor) {

  if (initialCapacity < 0)

  throw new IllegalArgumentException("Illegal initial capacity: " +

  initialCapacity);

  if (initialCapacity > MAXIMUM_CAPACITY)

  initialCapacity = MAXIMUM_CAPACITY;

  if (loadFactor <= 0

   Float.isNaN(loadFactor))

  throw new IllegalArgumentException("Illegal load factor: " +

  loadFactor);

  this.loadFactor = loadFactor;

  this.threshold = tableSizeFor(initialCapacity);

  }

  public HashMap(int initialCapacity) {

  this(initialCapacity, DEFAULT_LOAD_FACTOR);

  }

  public HashMap() {

  this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted

  }put方法过程:执行put 调用 hash方法,计算 key的 hash值 (h = key.hashCode()) ^ (h >>> 16)public V put(K key, V value) {

  //调用putVal方法

  return putVal(hash(key), key, value, false, true);

  }

  //真正的put方法

  final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

  boolean evict) {

  Node<K,V>[] tab; Node<K,V> p; int n, i;

  //如果底层的table 数组为null, 或者 length =0 , 就扩容到16

  if ((tab = table) == null

   (n = tab.length) == 0)

  n = (tab = resize()).length;

  //取出hash值对应的table的索引位置的Node, 如果为null, 就直接把加入的k-v, 创建成一个 Node ,加入该位置即可

  if ((p = tab[i = (n - 1) & hash]) == null)

  tab[i] = newNode(hash, key, value, null);

  else {

  Node<K,V> e; K k;

  //如果table的索引位置的key的hash相同和新的key的hash值相同,并满足(table现有的结点的key和准备添加的key是同一个对象

  equals返回真)就认为不能加入新的k-v

  if (p.hash == hash &&

  ((k = p.key) == key

   (key != null && key.equals(k))))

  e = p;

  else if (p instanceof TreeNode)

  e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

  else {

  //如果找到的结点,后面是链表,就循环比较

  for (int binCount = 0; ; ++binCount) {

  if ((e = p.next) == null) {

  p.next = newNode(hash, key, value, null);

  if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

  //加入后,判断当前链表的个数,是否已经到8个,到8个,后就调用 treeifyBin 方法进行红黑树的转换

  treeifyBin(tab, hash);

  break;

  }

  if (e.hash == hash &&

  ((k = e.key) == key

   (key != null && key.equals(k))))

  break;

  p = e;

  }

  }

  if (e != null) { // existing mapping for key

  V oldValue = e.value;

  if (!onlyIfAbsent

   oldValue == null)

  e.value = value;

  afterNodeAccess(e);

  return oldValue;

  }

  }

  ++modCount;

  //如size > 临界值,就扩容

  if (++size > threshold)

  resize();

  afterNodeInsertion(evict);

  return null;

  }树化过程:final void treeifyBin(Node<K,V>[] tab, int hash) {

  int n, index; Node<K,V> e;

  //如果table 为null ,或者大小还没有到 64,暂时不树化,而是进行扩容.

  if (tab == null

   (n = tab.length) < MIN_TREEIFY_CAPACITY)

  resize();

  else if ((e = tab[index = (n - 1) & hash]) != null) {

  TreeNode<K,V> hd = null, tl = null;

  do {

  TreeNode<K,V> p = replacementTreeNode(e, null);

  if (tl == null)

  hd = p;

  else {

  p.prev = tl;

  tl.next = p;

  }

  tl = p;

  } while ((e = e.next) != null);

  if ((tab[index] = hd) != null)

  hd.treeify(tab);

  }

  }扩容机制:final Node<K,V>[] resize() {

  Node<K,V>[] oldTab = table;

  int oldCap = (oldTab == null) ? 0 : oldTab.length;

  int oldThr = threshold;

  int newCap, newThr = 0;

  if (oldCap > 0) {

  if (oldCap >= MAXIMUM_CAPACITY) {

  threshold = Integer.MAX_VALUE;

  return oldTab;

  }

  else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&

  oldCap >= DEFAULT_INITIAL_CAPACITY)

  newThr = oldThr << 1; // double threshold

  }

  else if (oldThr > 0) // initial capacity was placed in threshold

  newCap = oldThr;

  else { // zero initial threshold signifies using defaults

  newCap = DEFAULT_INITIAL_CAPACITY;

  newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);

  }

  if (newThr == 0) {

  float ft = (float)newCap * loadFactor;

  newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?

  (int)ft : Integer.MAX_VALUE);

  }

  threshold = newThr;

  @SuppressWarnings({"rawtypes","unchecked"})

  Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];

  table = newTab;

  if (oldTab != null) {

  for (int j = 0; j < oldCap; ++j) {

  Node<K,V> e;

  if ((e = oldTab[j]) != null) {

  oldTab[j] = null;

  if (e.next == null)

  newTab[e.hash & (newCap - 1)] = e;

  else if (e instanceof TreeNode)

  ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);

  else { // preserve order

  Node<K,V> loHead = null, loTail = null;

  Node<K,V> hiHead = null, hiTail = null;

  Node<K,V> next;

  do {

  next = e.next;

  if ((e.hash & oldCap) == 0) {

  if (loTail == null)

  loHead = e;

  else

  loTail.next = e;

  loTail = e;

  }

  else {

  if (hiTail == null)

  hiHead = e;

  else

  hiTail.next = e;

  hiTail = e;

  }

  } while ((e = next) != null);

  if (loTail != null) {

  loTail.next = null;

  newTab[j] = loHead;

  }

  if (hiTail != null) {

  hiTail.next = null;

  newTab[j + oldCap] = hiHead;

  }

  }

  }

  }

  }

  return newTab;

  }4.2 HashTable

  (1)集合体系

  (2)基本使用

  同HashMap

  (3)源码剖析

  是否线程安全:线程安全值是否可以为null:不可以为nullpublic synchronized V put(K key, V value) {

  // Make sure the value is not null

  if (value == null) {

  throw new NullPointerException();

  }

  // Makes sure the key is not already in the hashtable.

  Entry<?,?> tab[] = table;

  int hash = key.hashCode();

  int index = (hash & 0x7FFFFFFF) % tab.length;

  @SuppressWarnings("unchecked")

  Entry<K,V> entry = (Entry<K,V>)tab[index];

  for(; entry != null ; entry = entry.next) {

  if ((entry.hash == hash) && entry.key.equals(key)) {

  V old = entry.value;

  entry.value = value;

  return old;

  }

  }

  addEntry(hash, key, value, index);

  return null;

  }4.3 TreeMap

  (1)集合体系

  (2)基本使用

  TreeMap treeMap = new TreeMap(new Comparator() {

  @Override

  public int compare(Object o1, Object o2) {

  //按照Key的长度大小排序 相等时只插入一个

  return ((String) o2).length() - ((String) o1).length();

  }

  });

  treeMap.put("1", "zs");

  treeMap.put("11", "ls");

  treeMap.put("12", "ww");

  (3)源码剖析

  排序机制:构造方法中传入Comparator接口的匿名内部类public TreeMap(Comparator<? super K> comparator) {

  this.comparator = comparator;

  }public V put(K key, V value) {

  Entry<K,V> t = root;

  if (t == null) {

  compare(key, key); // type (and possibly null) check

  root = new Entry<>(key, value, null);

  size = 1;

  modCount++;

  return null;

  }

  int cmp;

  Entry<K,V> parent;

  // split comparator and comparable paths

  Comparator<? super K> cpr = comparator;

  if (cpr != null) {

  do {

  parent = t;

  cmp = cpr.compare(key, t.key);

  if (cmp < 0)

  t = t.left;

  else if (cmp > 0)

  t = t.right;

  else

  return t.setValue(value);

  } while (t != null);

  }

  else {

  if (key == null)

  throw new NullPointerException();

  @SuppressWarnings("unchecked")

  Comparable<? super K> k = (Comparable<? super K>) key;

  do {

  parent = t;

  cmp = k.compareTo(t.key);

  if (cmp < 0)

  t = t.left;

  else if (cmp > 0)

  t = t.right;

  else

  return t.setValue(value);

  } while (t != null);

  }

  Entry<K,V> e = new Entry<>(key, value, parent);

  if (cmp < 0)

  parent.left = e;

  else

  parent.right = e;

  fixAfterInsertion(e);

  size++;

  modCount++;

  return null;

  }4.4 Properties

  (1)集合体系

  (2)基本使用

  Properties properties = new Properties();

  properties.put("1", "zs");

  properties.put("2", "ls");

  properties.put("3", "ww");

  //通过key获取对应值

  properties.get("1");

  //删除

  properties.remove("2");

  (3)源码剖析

  略

  4.5 LinkedHashMap

  (1)集合体系

  (2)基本使用

  LinkedHashMap<String, Object> map = new LinkedHashMap<>();

  map.put("1","zs");

  map.put("2","ls");

  map.get("1");

  (3)源码剖析

  Entry结构:在HashMap的基础上将Entry像链表一样链接了起来private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {

  LinkedHashMap.Entry<K,V> last = tail;

  tail = p;

  if (last == null)

  head = p;

  else {

  p.before = last;

  last.after = p;

  }

  }

标签: 服务器