Java集合类库将接口和实现分离。
Java集合类库的基本接口是Collection (java.util)
public interface Collection<E> extends Iterable<E>
public interface Iterator<E> (java.util)
Modifier and Type | Method and Description |
---|---|
boolean |
hasNext()
Returns
true if the iteration has more elements.
|
E |
next()
Returns the next element in the iteration.
|
void |
remove()
Removes from the underlying collection the last element returned by this iterator (optional operation).
|
但是,Java迭代器并不是这样运作的,查找操作与位置的变更是联系在一起的。查找一个元素的唯一操作就是next(),而执行该查找的同时会使迭代器的位置向前移动。
应该将Java迭代器看成是位于各个元素之间的:当调用next()的时候,迭代器便越过下一个元素,并且返回它刚刚越过的那个元素的引用;
方法1:调用next之前应该先执行hasNext()检测,防止next()抛出NoSuchElementException
Collection<String> c = ...; Iterator<String> iter = c.iterator(); while(iter.hasNext()){ String element = iter.next(); ... ... }
for (String element : c){ ... ... }
Iterator接口的remove方法会移除上次调用next()方法返回的元素。
i.e. 移除第一个位置上的元素:
Iterator<String> iter = c.iterator(); iter.next(); // skip over the first element iter.remove(); // now, remove it
List将元素维护在特定的序列中,并且允许重复的值。
List接口提供了名为ListIterator的迭代器。
List在数据结构中表现为数组、向量、链表、堆栈、队列等。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable (java.util)
public LinkedList() { header.next = header.previous = header; }
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable (java.util)
从JDK源码中可以看出,其带有两个属性:
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. */ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size;当存储空间不足时,重新分配空间:
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } }
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable (java.util)
/** * The array buffer into which the components of the vector are * stored. The capacity of the vector is the length of this array buffer, * and is at least large enough to contain all the vector's elements. * * <p>Any array elements following the last element in the Vector are null. * * @serial */ protected Object[] elementData; /** * The number of valid components in this {@code Vector} object. * Components {@code elementData[0]} through * {@code elementData[elementCount-1]} are the actual items. * * @serial */ protected int elementCount;
private void ensureCapacityHelper(int minCapacity) { int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object[] oldData = elementData; int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement) : (oldCapacity * 2); if (newCapacity < minCapacity) { newCapacity = minCapacity; } elementData = Arrays.copyOf(elementData, newCapacity); } }
public class Stack<E> extends Vector<E> (java.util)
public interface Set<E> extends Collection<E> (java.util)
Set集合和List集合都是存放的单个元素的序列,但是Set集合不允许有重复元素。
在Set接口中没有新增任何方法,所有方法均来自其父接口。它无法提供像List中按位存取的方法。在数学上一个集合有三个性质:确定性、互异性、无序性。
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable (java.util)
HashSet中存放的元素时无序的,底层是用HashMap实现的:
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
其中Key时要放入的元素,value是一个Object类型的名为PRESENT的敞亮。由于使用了散列函数,因此其存取速度是非常快的。
/** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * default initial capacity (16) and load factor (0.75). */ public HashSet() { map = new HashMap<E,Object>(); } /** * Constructs a new set containing the elements in the specified * collection. The <tt>HashMap</tt> is created with default load factor * (0.75) and an initial capacity sufficient to contain the elements in * the specified collection. * * @param c the collection whose elements are to be placed into this set * @throws NullPointerException if the specified collection is null */ public HashSet(Collection<? extends E> c) { map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }
当哈希值相同时,将存放在同一个位置,使用链表方式依次链接下去。
HashMap中的resize方法如下(HashSet是基于HashMap实现的):
/** * The table, resized as necessary. Length MUST Always be a power of two. */ transient Entry[] table; /** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ 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]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); } /** * Transfers all entries from current table to newTable. */ void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null) { src[j] = null; do { Entry<K,V> next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } }
HashSet是允许放空值的。
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable (java.util)
LinkedHashSet保证了按照插入顺序有序。
LinkedHashSet使用HashSet的构造函数:
HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor); }可以看出LinkedHashSet底层是使用LinkedHashMap实现的。
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable (java.util)
TreeSet中所放的元素是有序的,并且元素是不能重复的。
基于红黑树。
TreeSet底层使用TreeMap使用,和HashSet一样,将每个要放入的元素放到key的位置,value位置放的是一个Object类型的常量。
public interface Map<K,V>
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
HashMap基于hash数组实现,若key的hash值相同则使用链表方式进行保存,可参见HashSet中的说明。
/** * The table, resized as necessary. Length MUST Always be a power of two. */ transient Entry[] table;
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; }
/** * Returns index for hash code h. */ static int indexFor(int h, int length) { return h & (length-1); }
当元素超过threshold时,再哈希的过程参看HashSet。
HashMap的存取速度快。
HashMap的遍历:
public static void useWhileSentence(Map<Integer, String> m) { Set s = (Set<Integer>)m.keySet(); Iterator<Integer> it = s.iterator(); int Key; String value; while(it.hasNext()) { Key = it.next(); value = (String)m.get(Key); System.out.println(Key+":\t"+value); } } public static void useWhileSentence2(Map m) { Set s = m.entrySet(); Iterator<Map.Entry<Integer, String>> it = s.iterator(); Map.Entry<Integer, String> entry; int Key; String value; while(it.hasNext()) { entry = it.next(); Key = entry.getKey(); value = entry.getValue(); System.out.println(Key+":\t"+value); } } public static void useForSentence(Map<Integer, String> m) { int Key; String value; for(Map.Entry<Integer, String> entry : m.entrySet()) { Key = entry.getKey(); value = entry.getValue(); System.out.println(Key+":\t"+value); } }
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable (java.util)
HashTable实现Map接口,继承自Dictionary类。任何非空的(key - value)均可以放入其中。
HashTable的部分方法使用synchronized保证线程安全。
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
LinkedHashMap继承自HashMap实现了Map接口。和HashMap一样,LinkedHashMap允许key和value均为null。
LinkedHashMap与HashMap的不同之处在于:LinkedHashMap维护着运行于所有条目的双重连接列表,此链接列表可以时插入顺序或者访问顺序。
参见TreeSet
interface | 集合类 | 插入节点 | 删除节点 | 查找节点 | 遍历 | 存储方式 | 线程安全 | 其他 |
---|---|---|---|---|---|---|---|---|
List | ||||||||
Vector | 慢 | 慢 | 快 | 使用迭代器 | 数组 | 是 | ||
ArrayList | 慢 | 慢 | 快 | 使用迭代器 | 数组 | 否 | ||
LinkedList | 快 | 快 | 慢 | 使用迭代器 | 链表 | 否 | ||
Set | ||||||||
TreeSet | 使用迭代器 | 红黑树 | 否 | 继承TreeMap | ||||
HashSet | 使用迭代器 | 散列表 | 否 | 继承HashMap | ||||
LinkedHashSet | 使用迭代器 | 散列表 | 否 | 继承LinkedHashMap | ||||
Map | ||||||||
TreeMap | key set, EntrySet | 红黑树 | 否 | |||||
HashMap | key set, EntrySet | 散列表 | 否 | |||||
LinkedHashMap | key set, EntrySet | 散列表 | 否 | |||||
HashTable | key set, EntrySet | 散列表 | 是 |
(java.util)
public class Collections extends Object包含一系列的静态方法,操作或者返回一个集合类;
(java.util)
public class Arrays extends Object包含操纵数组的静态方法;
i.e. 删除ArrayList中特定的元素:
方法1:
for (int i = 0, len = list.size(); i < len; i++){ if (list.get(i) == XXX){ list.remove(i); --len; --i; } }
Iterator<String> sListIterator = list.iterator(); while(sListIterator.hasNext()){ String e = sListIterator.next(); if (e.equals("XXX")){ sListIterator.remove(); } }