public interface Collection<E>{ // 集合改变返回 true,否则返回 false boolean add(); boolean addAll(); // 返回一个迭代器 Iterator<E> iterator(); int size(); boolean isEmpty(); // 集合中包含了和 obj 相等的对象,那么返回 true boolean contains(Object obj); // 如果集合中包含 other 集合中的所有元素,那么返回 true boolean containsAll(Collect<?> other); // 从这个集合中删除等于 obj 的对象,如果有匹配的对象,返回 true boolean remove(Object obj); // 从这个集合中删除 other 中存在的元素,如果这个调用改变了集合,那么返回 true boolean removeAll(Collect<?> other); void clear(); // 从这个集合中删除所有与 other 这个集合中的元素不同的元素,如果这个调用改变了集合,那么返回 true boolean retainAll(Collection<?> other); Object[] toArray(); <T> T[] toArray(T[] a); } 复制代码
public interface Iterator<E>{ // 反复调用,可以逐个访问集合中的每个元素(配合 hasNext() 这个方法) E next(); boolean hasNext(); // 删除上次调用 next() 返回的元素,没有调用 next() 方法,调用 remove() 则会报 IllegalStateException 异常 void remove(); } 复制代码
Collection<String> c = ....; Iterator<String> iterator = c.iterator(); while(iterator.hasNext()){ String element = iterator.next(); iterator.remove(); // todo something } 复制代码
Collection<String> c = ....; for(String element : c){ // todo something } 复制代码
“for each” 循环可以与任何实现了 Iterable 接口的对象一起工作
java.lang.Object ↳ java.util.AbstractCollection<E> ↳ java.util.AbstractList<E> ↳ java.util.ArrayList<E> public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {} 复制代码
// 将其包装成线程安全 List list = Collections.synchronizedList(new ArrayList()); 复制代码
JDK 1.6 及之前
int newCapacity = (oldCapacity * 3)/2 + 1; 复制代码
JDK 1.7 及之后
int newCapacity = oldCapacity + (oldCapacity >> 1); 复制代码
JDK 1.8
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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } 复制代码
Object[] toArray() <T> T[] toArray(T[] contents) 复制代码
// toArray(T[] contents)调用方式一 public static Integer[] vectorToArray1(ArrayList<Integer> v) { Integer[] newText = new Integer[v.size()]; v.toArray(newText); return newText; } // toArray(T[] contents)调用方式二。最常用! public static Integer[] vectorToArray2(ArrayList<Integer> v) { Integer[] newText = (Integer[])v.toArray(new Integer[0]); return newText; } // toArray(T[] contents)调用方式三 public static Integer[] vectorToArray3(ArrayList<Integer> v) { Integer[] newText = new Integer[v.size()]; Integer[] newStrings = (Integer[])v.toArray(newText); return newStrings; } 复制代码
一种可以在任意位置进行高效插入及删除的操作的有序序列
java.lang.Object ↳ java.util.AbstractCollection<E> ↳ java.util.AbstractList<E> ↳ java.util.AbstractSequentialList<E> ↳ java.util.LinkedList<E> public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable 复制代码
public static void useLinkedListAsLIFO() { System.out.println("/nuseLinkedListAsLIFO"); // 新建一个LinkedList LinkedList stack = new LinkedList(); // 将1,2,3,4添加到堆栈中 stack.push("1"); stack.push("2"); stack.push("3"); stack.push("4"); // 打印“栈” System.out.println("stack:"+stack); // 删除“栈顶元素” System.out.println("stack.pop():"+stack.pop()); // 取出“栈顶元素” System.out.println("stack.peek():"+stack.peek()); // 打印“栈” System.out.println("stack:"+stack); } 复制代码
public static void useLinkedListAsFIFO() { System.out.println("/nuseLinkedListAsFIFO"); // 新建一个LinkedList LinkedList queue = new LinkedList(); // 将10,20,30,40添加到队列。每次都是插入到末尾 queue.add("10"); queue.add("20"); queue.add("30"); queue.add("40"); // 打印“队列” System.out.println("queue:"+queue); // 删除(队列的第一个元素) System.out.println("queue.remove():"+queue.remove()); // 读取(队列的第一个元素) System.out.println("queue.element():"+queue.element()); // 打印“队列” System.out.println("queue:"+queue); } 复制代码
HashMap 它是基于 hash 表的 Map 接口实现,以 key-value 的形式存在的,HashMap 总是以 key-value 的形式存在的,系统会通过计算 key 的 hash 值来定位 key-value 的存储位置的,我们可以快速的通过 key 来存取 value;
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable 复制代码
关于 HashMap 的数据结构,底层的话还是数组的,只不过数组的每一项就是一个链表
构造函数的源码
public HashMap(int initialCapacity, float loadFactor) { //初始容量不能<0 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); //初始容量不能 > 最大容量值,HashMap的最大容量值为2^30 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; //负载因子不能 < 0 if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // 计算出大于 initialCapacity 的最小的 2 的 n 次方值。 int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; //设置HashMap的容量极限,当HashMap的容量达到该极限时就会进行扩容操作 threshold = (int) (capacity * loadFactor); //初始化table数组 table = new Entry[capacity]; init(); } 复制代码
Entry 的源码
static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; final int hash; /** * Creates new entry. */ Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; } ....... } 复制代码
Entry 是 HashMap 的内部类,其中包含了 key,value 和 下一个 Entry,以及 hash 值,正因为有这下才构成了数组的项为一个列表。
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 复制代码
DEFAULT_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR 复制代码
在关键字的 hash 地址上已经有了记录,那么这就是哈希冲突 复制代码
public V put(K key, V value) { //当key为null,调用putForNullKey方法,保存null与table第一个位置中,这是HashMap允许为null的原因 if (key == null) return putForNullKey(value); //计算key的hash值 int hash = hash(key.hashCode()); ------(1) //计算key hash 值在 table 数组中的位置 int i = indexFor(hash, table.length); ------(2) //从i出开始迭代 e,找到 key 保存的位置 for (Entry<K, V> e = table[i]; e != null; e = e.next) { Object k; //判断该条链上是否有hash值相同的(key相同) //若存在相同,则直接覆盖value,返回旧value if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; //旧值 = 新值 e.value = value; e.recordAccess(this); return oldValue; //返回旧值 } } //修改次数增加1 modCount++; //将 key、value 添加至i位置处 addEntry(hash, key, value, i); return null; } 复制代码
(1)处代码实现:技术 hash 值
static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } 复制代码
(2)处代码实现:根据 hash 值计算出 key 在 table 数组中所对应的位置
static int indexFor(int h, int length) { return h & (length-1); } 复制代码
(3)将节点插入表头
void addEntry(int hash, K key, V value, int bucketIndex) { //获取bucketIndex处的Entry Entry<K, V> e = table[bucketIndex]; //将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry table[bucketIndex] = new Entry<K, V>(hash, key, value, e); //若HashMap中元素的个数超过极限了,则容量扩大两倍 if (size++ >= threshold) resize(2 * table.length); } 复制代码
随着 HashMap 中的元素越来越多,发生 hash 冲突的概率越来越大,链表的长度越来越长,查找的效率就越来越低;这样我们就必须在 HashMap 的某个临界值进行扩容处理。扩容的方式:重新创建一个新的 table 数组,重新计算 key 的 hash 值,并放入新的 table 数组中,这样的操作是比较耗时的,如果我们能够预知 HashMap 中的大小时,我们可以指定 HashMap 中的元素个数。
public V get(Object key) { // 若为null,调用getForNullKey方法返回相对应的value if (key == null) return getForNullKey(); // 根据该 key 的 hashCode 值计算它的 hash 码 int hash = hash(key.hashCode()); // 取出 table 数组中指定索引处的值 for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; //若搜索的key与查找的key相同,则返回相对应的value if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; } 复制代码
HashMap 是线程不安全的,我们可以通过 Collections 的静态方法 SynchronizedMap 来获取线程安全的 HashMap
Map map = Collections.SynchronizedMap(new HashMap<>(); 复制代码
`` /** * HashMap.Node subclass for normal LinkedHashMap entries. */ static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> { LinkedHashMapEntry<K,V> before, after; LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } } ``` 复制代码
// Callbacks to allow LinkedHashMap post-actions // 访问元素之后 void afterNodeAccess(Node<K,V> p) { } // 插入节点之后 void afterNodeInsertion(boolean evict) { } // 删除节点之后 void afterNodeRemoval(Node<K,V> p) { } 复制代码
HashTable 和 HashMap 都实现了 Map 接口,他们的主要区别在于线程安全、速度。