JAVA集合类
来源:互联网 发布:淘宝企业店铺提现 编辑:程序博客网 时间:2024/06/05 14:43
目前中文博客中充斥着很多很多介绍Java集合类的文章,但大多人云也云,一眼就让人理解的不多。这边尝试重新介绍下,希望可以抛砖引玉。
集合类的族谱关系
两种图片分别出自:
http://www.wilsonmar.com/1arrays.htm
http://beginnersbook.com/java-collections-tutorials/
本文中也有相当一部分参考上面两篇文章。
图1 Java 比较详尽的集合继承关系图
图2 Java集合类简单的继承图
继承关系图比较难记,但图2的简单,图2记住了,再辅助以下文分析,图1也就清楚了
集合类collection接口
集合类的List, Set, Queue都实现Collection接口,并所有集合类的常用操作都在Collection接口中。
接口的源码如下,通过名字,我们也可知道这些接口的动作到底是什么。
public interface Collection<E> extends Iterable<E> { int size(); boolean isEmpty(); Iterator<E> iterator(); Object[] toArray(); <T> T[] toArray(T[] a); boolean add(E e); boolean remove(Object o); boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); boolean removeAll(Collection<?> c); boolean retainAll(Collection<?> c); void clear(); boolean equals(Object o); int hashCode();}
vector类
比较老的一个类。可以从源码看出,内部使用数组实现,所有改动的操作都以synclyzed关键字,可见是线程安全的一个集合类。
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{//内部使用数组作为vector的存储,既然是存储,删除,插入肯定是不方便的,当然随机访问肯定很方便 protected Object[] elementData; //数组有效元素 protected int elementCount; //数组满了的时候,每次扩容多少 protected int capacityIncrement; //初始化vector,同时给定容量和每次增量 public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; } //给定容量版 public Vector(int initialCapacity) { this(initialCapacity, 0); } //默认为10, 如果是大量使用的,必须一次给容量到位,不然每次都要重新申请拷贝 public Vector() { this(10); } //复制 public Vector(Collection<? extends E> c) { elementData = c.toArray(); elementCount = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, elementCount, Object[].class); }//剪掉,注意synchronized关键字,可知线程安全 public synchronized void trimToSize() { modCount++; int oldCapacity = elementData.length; if (elementCount < oldCapacity) { elementData = Arrays.copyOf(elementData, elementCount); } } //扩容 public synchronized void ensureCapacity(int minCapacity) { if (minCapacity > 0) { modCount++; ensureCapacityHelper(minCapacity); } } //当前容量,synchronized public synchronized int capacity() { return elementData.length; }//当前有效元素,存在的元素 public synchronized int size() { return elementCount; }//查找元素synchronized public synchronized E elementAt(int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } return elementData(index); } //改变元素,synchronized public synchronized void setElementAt(E obj, int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } elementData[index] = obj; } //删除元素,要大量拷贝。synchronized public synchronized void removeElementAt(int index) { modCount++; if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } else if (index < 0) { throw new ArrayIndexOutOfBoundsException(index); } int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } elementCount--; elementData[elementCount] = null; /* to let gc do its work */ } //增加元素,也要拷贝其他的,synchronized public synchronized void insertElementAt(E obj, int index) { modCount++; if (index > elementCount) { throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount); } ensureCapacityHelper(elementCount + 1); System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); elementData[index] = obj; elementCount++; } //末尾增加元素,超过容量要重新复制,不然直接加就可以, 这也是初始容量比较重要的原因synchronized public synchronized void addElement(E obj) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj; } //转换为数组,synchronized public synchronized Object[] toArray() { return Arrays.copyOf(elementData, elementCount); } //获得指定位置元素,这个效率比较高synchronized public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index); }}
ArrayList 类
看到ArrayList类,就简直看到了Vector的双胞胎兄弟。但有些也不尽相同,比如ArrayList对内部数组的操作没有synchronized,效率为变高,但也是线程不安全版本。
ArrayList的扩容策略也不一样,vector是固定数量的扩容,而ArrayList是每次扩容为1.5倍。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ //数组存储,相比于链表具有随机访问的优势,但删除和插入是劣势 private transient Object[] elementData; //大小 private int size; //构造函数,给定初始容量,为了提高效率,最好预估自己使用时候的容量 public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } //构造函数,默认容量为10 public ArrayList() { this(10); }//扩容,1.5倍的扩容,不是扩容固定个数的元素 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); } //从其他集合类拷贝 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } //去指定位置上的元素,没有synchronized public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }//加一个元素 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } //指定位置加一个元素,要拷贝了 public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }//删除元素 public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }}
LinkedList 类
双向链表实现的线程不安全集合类。相比于ArrayList 和Vector,插入和删除操作比较快,但是随机访问就没有优势了。同时也不需要设置初始化容量。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{ //内部类,指针节点,双向链表结构private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }//链表大小transient int size = 0;//头节点 transient Node<E> first;//末尾节点 transient Node<E> last; public LinkedList() { } //加其他集合 public LinkedList(Collection<? extends E> c) { this(); addAll(c); } //private 函数,向表头加一个节点 private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; } //向表尾加节点,final的使用使得新创建节点引用不能改变指向 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++; }//省略一些链表操作函数//获得第一个节点 public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; }//获得最后一个节点 public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } //删除第一个节点 public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); }//删除最后一个节点 public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); }//在表头加节点 public void addFirst(E e) { linkFirst(e); } //表末尾加节点 public void addLast(E e) { linkLast(e); }//在index处替换节点,而不是改变原有节点,因为已经final public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }//省略其他}
Stack类
stack类比较简单,继承自Vector。是线程安全的集合类。
publicclass Stack<E> extends Vector<E> { public Stack() { }//push操作 public E push(E item) { addElement(item); return item; } //pop操作 public synchronized E pop() { E obj; int len = size(); obj = peek(); removeElementAt(len - 1); return obj; } //peek操作 public synchronized E peek() { int len = size(); if (len == 0) throw new EmptyStackException(); return elementAt(len - 1); }}
PriorityQueue类
PriorityQueue为二叉堆的集合类实现,二叉堆的排序时间复杂度为O(logn), 对于大数据中取最小和最大几个元素效果比较好。
关于二叉堆的数据结构,请各位搜索之。
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable { private static final int DEFAULT_INITIAL_CAPACITY = 11;//存储二叉堆的数组 private transient Object[] queue; private int size = 0; //比较器 private final Comparator<? super E> comparator; /** * The number of times this priority queue has been * <i>structurally modified</i>. See AbstractList for gory details. */ private transient int modCount = 0; //构造函数 public PriorityQueue() { this(DEFAULT_INITIAL_CAPACITY, null); } //带容量的构造函数 public PriorityQueue(int initialCapacity) { this(initialCapacity, null); } //带容量和比较器的构造函数 public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) { // Note: This restriction of at least one is not actually needed, // but continues for 1.5 compatibility if (initialCapacity < 1) throw new IllegalArgumentException(); this.queue = new Object[initialCapacity]; this.comparator = comparator; } //从其他集合拷贝的构造函数 @SuppressWarnings("unchecked") public PriorityQueue(Collection<? extends E> c) { if (c instanceof SortedSet<?>) { SortedSet<? extends E> ss = (SortedSet<? extends E>) c; this.comparator = (Comparator<? super E>) ss.comparator(); initElementsFromCollection(ss); } else if (c instanceof PriorityQueue<?>) { PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c; this.comparator = (Comparator<? super E>) pq.comparator(); initFromPriorityQueue(pq); } else { this.comparator = null; initFromCollection(c); } }//private函数, 直接从其他PriorityQueue拷贝,直接拷贝数组和大小 private void initFromPriorityQueue(PriorityQueue<? extends E> c) { if (c.getClass() == PriorityQueue.class) { this.queue = c.toArray(); this.size = c.size(); } else { initFromCollection(c); } }//从collection中初始化元素,检查不准元素为Null private void initElementsFromCollection(Collection<? extends E> c) { Object[] a = c.toArray(); // If c.toArray incorrectly doesn't return Object[], copy it. if (a.getClass() != Object[].class) a = Arrays.copyOf(a, a.length, Object[].class); int len = a.length; if (len == 1 || this.comparator != null) for (int i = 0; i < len; i++) if (a[i] == null) throw new NullPointerException(); this.queue = a; this.size = a.length; } //增加容量,加一倍或一点五倍,64为界 private void grow(int minCapacity) { int oldCapacity = queue.length; // Double size if small; else grow by 50% int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1)); // overflow-conscious code if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); queue = Arrays.copyOf(queue, newCapacity); }//删除元素 private E removeAt(int i) { assert i >= 0 && i < size; modCount++; int s = --size; if (s == i) // removed last element queue[i] = null; else { E moved = (E) queue[s]; queue[s] = null; siftDown(i, moved); if (queue[i] == moved) { siftUp(i, moved); if (queue[i] != moved) return moved; } } return null; } //下面几个函数为二叉堆的上移下移操作,利用堆的q[n]的左右孩子为q[2n+2]和q[2n+1]的属性 private void siftUp(int k, E x) { if (comparator != null) siftUpUsingComparator(k, x); else siftUpComparable(k, x); } private void siftUpComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>) x; while (k > 0) { int parent = (k - 1) >>> 1; Object e = queue[parent]; if (key.compareTo((E) e) >= 0) break; queue[k] = e; k = parent; } queue[k] = key; } private void siftUpUsingComparator(int k, E x) { while (k > 0) { int parent = (k - 1) >>> 1; Object e = queue[parent]; if (comparator.compare(x, (E) e) >= 0) break; queue[k] = e; k = parent; } queue[k] = x; } /** * Inserts item x at position k, maintaining heap invariant by * demoting x down the tree repeatedly until it is less than or * equal to its children or is a leaf. * * @param k the position to fill * @param x the item to insert */ private void siftDown(int k, E x) { if (comparator != null) siftDownUsingComparator(k, x); else siftDownComparable(k, x); } private void siftDownComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>)x; int half = size >>> 1; // loop while a non-leaf while (k < half) { int child = (k << 1) + 1; // assume left child is least Object c = queue[child]; int right = child + 1; if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0) c = queue[child = right]; if (key.compareTo((E) c) <= 0) break; queue[k] = c; k = child; } queue[k] = key; } private void siftDownUsingComparator(int k, E x) { int half = size >>> 1; while (k < half) { int child = (k << 1) + 1; Object c = queue[child]; int right = child + 1; if (right < size && comparator.compare((E) c, (E) queue[right]) > 0) c = queue[child = right]; if (comparator.compare(x, (E) c) <= 0) break; queue[k] = c; k = child; } queue[k] = x; } //堆化操作 private void heapify() { for (int i = (size >>> 1) - 1; i >= 0; i--) siftDown(i, (E) queue[i]); }}
HashMap类
Hashmap类也是线程不安全的集合类,内部用数组作为存储。使用的时候需要注意,当元素快满,并且接近threshold的时候,会重新Hash,并且造成整个数组的拷贝。
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable{ //默认的容量,一定要2的倍数 static final int DEFAULT_INITIAL_CAPACITY = 16; //最大数量不超过2的32次方 static final int MAXIMUM_CAPACITY = 1 << 30; //重hash因子,比方说容量为64,到48的时候就重新hash排列 static final float DEFAULT_LOAD_FACTOR = 0.75f; //存储的key value 数组 transient Entry<K,V>[] table; //存储元素的多少 transient int size; //下一次调整大小的数值(capacity * load factor). * @serial * int threshold;//调整因子 final float loadFactor; //hash种子 transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this); //构造函数,容量要为2的倍数 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); //一直找到大于参数的第一个2的倍数 int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); table = new Entry[capacity]; useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); init(); }//计算hash码,为什么这么算?学数学的来解释下,不懂 final int hash(Object k) { int h = 0; if (useAltHashing) { if (k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h = hashSeed; } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } /** * Returns the number of key-value mappings in this map. * * @return the number of key-value mappings in this map */ public int size() { return size; }//真的null做单独处理,说明可以放null的键值 public V get(Object key) { if (key == null) return getForNullKey(); Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue(); } private V getForNullKey() { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null; }//get 元素 final Entry<K,V> getEntry(Object key) { int hash = (key == null) ? 0 : hash(key); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; }//插入元素,null键默认放在table[0] public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; } private V putForNullKey(V value) { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(0, null, value, 0); return null; } //当超过threshold的时候需要重新hash,因为Index和数组长度有关,这个对效率是致命的 void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] newTable = new Entry[newCapacity]; boolean oldAltHashing = useAltHashing; useAltHashing |= sun.misc.VM.isBooted() && (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); boolean rehash = oldAltHashing ^ useAltHashing; transfer(newTable, rehash); table = newTable; threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); } //重新hash void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }//删除key public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); }}
HashTable类
几乎和HashMap是双胞胎兄弟,但是HashTable是线程安全的,并且不接受null的key.并且实现自比较老的Dictionary,而不是Map.
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable { private transient Entry<K,V>[] table;//数组中的元素 private transient int count; //下次重新Hash的大小 private int threshold; //重载因子 private float loadFactor;//种子 transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);//hash函数 private int hash(Object k) { if (useAltHashing) { if (k.getClass() == String.class) { return sun.misc.Hashing.stringHash32((String) k); } else { int h = hashSeed ^ k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } } else { return k.hashCode(); } }//函数为synchronized public synchronized boolean contains(Object value) { if (value == null) { throw new NullPointerException(); } Entry tab[] = table; for (int i = tab.length ; i-- > 0 ;) { for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; }//get函数 public synchronized V get(Object key) { Entry tab[] = table; int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return e.value; } } return null; }//重新hash函数 protected void rehash() { int oldCapacity = table.length; Entry<K,V>[] oldMap = table; // overflow-conscious code int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) // Keep running with MAX_ARRAY_SIZE buckets return; newCapacity = MAX_ARRAY_SIZE; } Entry<K,V>[] newMap = new Entry[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); boolean currentAltHashing = useAltHashing; useAltHashing = sun.misc.VM.isBooted() && (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); boolean rehash = currentAltHashing ^ useAltHashing; table = newMap; for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; if (rehash) { e.hash = hash(e.key); } int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } } //put函数synchronized public 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 = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { V old = e.value; e.value = value; return old; } } modCount++; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; hash = hash(key); index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. Entry<K,V> e = tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; return null; }//remove函数 public synchronized V remove(Object key) { Entry tab[] = table; int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; }}
LinkedHashMap
LinkedHashMap 和HashMap 几乎一样,唯一的区别是,LinkedHashMap可以有序的访问。 既然是hash后放在数组中,那理论上数组肯定是无序的,那为什么可以有序访问呢?原因是LinkedHashMap改造了HashMap的元素,放入指针,用循环链表的方式连起来了。
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{ //放在链表中的头节点 private transient Entry<K,V> header; //true的时候,访问完一个元素,就放到最后,否则就严格按照插入时候的顺序 private final boolean accessOrder;//初始化容量和重构因子 public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } //复制构造函数 public LinkedHashMap(Map<? extends K, ? extends V> m) { super(m); accessOrder = false; } //可设置访问顺序的构造函数 public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; } //复制到其他hashmap,使用已有的顺序来 @Override void transfer(HashMap.Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K,V> e = header.after; e != header; e = e.after) { if (rehash) e.hash = (e.key == null) ? 0 : hash(e.key); int index = indexFor(e.hash, newCapacity); e.next = newTable[index]; newTable[index] = e; } }//get的时候,在recordAccess中把get的节点放在最后 public V get(Object key) { Entry<K,V> e = (Entry<K,V>)getEntry(key); if (e == null) return null; e.recordAccess(this); return e.value; } private static class Entry<K,V> extends HashMap.Entry<K,V> { //加入指针 Entry<K,V> before, after; Entry(int hash, K key, V value, HashMap.Entry<K,V> next) { super(hash, key, value, next); } private void addBefore(Entry<K,V> existingEntry) { after = existingEntry; before = existingEntry.before; before.after = this; after.before = this; } void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } }}
TreeMap 实现类
TreeMap使用二叉搜索树作为存储,确切地说应该是一个红黑树的结构。对应搜索性质的数据组合帮助较大。
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable{ //比较器,要使用其compare方法 private final Comparator<? super K> comparator;//树的root节点 private transient Entry<K,V> root = null;//节点数量 private transient int size = 0;//默认比较器为空 public TreeMap() { comparator = null; }//带比较器版本 public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; } //复制 public TreeMap(Map<? extends K, ? extends V> m) { comparator = null; putAll(m); } public TreeMap(SortedMap<K, ? extends V> m) { comparator = m.comparator(); try { buildFromSorted(m.size(), m.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } }//根据搜索树的性质查找对应键值 final Entry<K,V> getEntry(Object key) { // Offload comparator-based version for sake of performance if (comparator != null) return getEntryUsingComparator(key); if (key == null) throw new NullPointerException(); Comparable<? super K> k = (Comparable<? super K>) key; Entry<K,V> p = root; while (p != null) { int cmp = k.compareTo(p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } return null; }//加节点,标准的红黑树加节点算法 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(); 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; } // Red-black mechanics private static final boolean RED = false; private static final boolean BLACK = true; //红黑树的节点 static final class Entry<K,V> implements Map.Entry<K,V> { K key; V value; Entry<K,V> left = null; Entry<K,V> right = null; Entry<K,V> parent; boolean color = BLACK; /** * Make a new cell with given key, value, and parent, and with * {@code null} child links, and BLACK color. */ Entry(K key, V value, Entry<K,V> parent) { this.key = key; this.value = value; this.parent = parent; } /** * Returns the key. * * @return the key */ public K getKey() { return key; } /** * Returns the value associated with the key. * * @return the value associated with the key */ public V getValue() { return value; } /** * Replaces the value currently associated with the key with the given * value. * * @return the value associated with the key before this method was * called */ public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; return valEquals(key,e.getKey()) && valEquals(value,e.getValue()); } public int hashCode() { int keyHash = (key==null ? 0 : key.hashCode()); int valueHash = (value==null ? 0 : value.hashCode()); return keyHash ^ valueHash; } public String toString() { return key + "=" + value; } }}
Set类 HashSet ,LinkedHashSet,TreeSet
这三个类全部依赖于对应的Map来实现,看懂了Map, Set也就不再话下。利用的算法和组织结构一样,这边不展开说明。
小结
这边主要集合源码,来分析各种集合类的实现。重要的是算法和数据结构。理解这些就理解一切。
0 0
- Java集合:集合类详解
- Java集合-常用集合类
- JAVA【集合一】集合类
- JAVA中的集合类
- JAVA中的集合类
- JAVA中的集合类
- Java集合类(整理)
- java集合类
- JAVA中的集合类
- Java集合类笔记
- JAVA中的集合类
- java集合类
- java集合类总结
- JAVA中的集合类 - -
- JAVA中的集合类
- java集合类
- java 集合类
- java中的集合类
- SQL Update多表联合更新的方法
- iOS webView 远程html加载本地资源
- 第二周项目6-设计倒三角形
- IOS定位
- Git学习笔记(三)——Git远程版本库的搭建
- JAVA集合类
- 个人web项目——悦动web网站
- 随手记点-mapreduce1
- 经典算法——连续子数组最大和问题
- 半年总结
- 关于文件、网络传输以及内存存储的大小端问题
- 【Linux】一张图让你读懂Linux内核运行原理
- 回文判断
- PAT (Advanced Level) Practise 1045 Favorite Color Stripe (30)