關(guān)于Collection接口下相關(guān)類接口的問題及分析
*List和*Set的異同
List和Set本身都是接口,他們都繼承了Collection接口,分別表示2種數(shù)據(jù)機(jī)構(gòu)。一種*List可以有重復(fù)的數(shù)據(jù),可以有多個(gè)NULL值;而另外一種*Set不能有重復(fù)數(shù)據(jù),最多只能有一個(gè)NULL值。在他們的源代碼上可以很清楚的發(fā)現(xiàn)這些差異。
可以打開ArrayList的add方法代碼如下:
public boolean
add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++]
= e; return true; } |
而HashSet的add方法代碼如下:
public boolean add(E e) { return map.put(e, PRESENT)==null; } |
一個(gè)是數(shù)組實(shí)現(xiàn),一個(gè)使用Map實(shí)現(xiàn),并且HashSet的元素作為map的key值,必然不能重復(fù)。
關(guān)于ArrayList和Vector的異同
ArrayList不是線程安全的,而Vector是的。具體可以看Vector的add方法和insertElementAt方法的代碼:
public void add(int index, E element) { insertElementAt(element, index); } 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關(guān)鍵字,說明進(jìn)行了線程同步。而ArrayList中的add方法沒有進(jìn)行同步,自然不是線程安全的。如果需要使用ArrayList且需要同步可以使用如下代碼:
List list = Collections.synchronizedList(new ArrayList()); |
ArrayList,Vector, LinkedList的存儲性能和特性
ArrayList和Vector都是使用數(shù)組方式存儲數(shù)據(jù),此數(shù)組元素?cái)?shù)大于實(shí)際存儲的數(shù)據(jù)以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數(shù)組元素移動等內(nèi)存操作,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢,Vector由于使用了synchronized方法(線程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實(shí)現(xiàn)存儲,按序號索引數(shù)據(jù)需要進(jìn)行前向或后向遍歷,但是插入數(shù)據(jù)時(shí)只需要記錄本項(xiàng)的前后項(xiàng)即可,所以插入速度較快。
關(guān)于Collections和Collection的區(qū)別
Collection是集合類的上級接口,繼承與他的接口主要有Set 和List。Collections是針對集合類的一個(gè)幫助類,他提供一系列靜態(tài)方法實(shí)現(xiàn)對各種集合的搜索、排序、線程安全化等操作。
關(guān)于HashMap和HashTable的異同
都是實(shí)現(xiàn)了Map接口,利用key和value對應(yīng)存取對象,都是基于Hash算法實(shí)現(xiàn)快速存取。但是HashTable是線程安全的,HashMap不是,在效率上因?yàn)橥降脑蛴兴町悺2⑶遥?/span>HashMap中的key可以有NULL但最多一個(gè),而HashTable不能有NULL的key值。
HashMap的put方法代碼如下:
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); 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; } |
而HashTable的put方法代碼如下:
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 = key.hashCode(); 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; index = (hash & 0x7FFFFFFF) %
tab.length; } // Creates the new entry. Entry<K,V> e = tab[index]; tab[index] = new Entry<K,V>(hash, key, value, e); count++; return null; } |