【Java基礎】集合
0.
Java集合類庫將介面和實現分離。
Java集合類庫的基本介面是Collection (java.util)
public interface Collection<E> extends Iterable<E>
迭代器Iterator
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();
... ...
}
方法2:for each
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
如果呼叫remove()方法之前沒有呼叫next(),或者在上一次呼叫next()方法之後已經呼叫過一次remove(),則此時呼叫remove()會丟擲IllegalStateException;
Java集合類庫框架(部分)
集合類庫 - List介面
List將元素維護在特定的序列中,並且允許重複的值。
List介面提供了名為ListIterator的迭代器。
List在資料結構中表現為陣列、向量、連結串列、堆疊、佇列等。
LinkedList
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable (java.util)
LinkedList的特點
LinkedList是基於連結串列的集合(java中的連結串列都是迴圈雙重連線的,forward/backward node):public LinkedList() {
header.next = header.previous = header;
}
LinkedList的實現機制
LinkedList的使用
ArrayList
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable (java.util)
ArrayList的特點
ArrayList的實現機制
從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);
}
}
ArrayList的使用
Vector
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable (java.util)
Vector的特點
/**
* 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;
Vector的實現機制
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);
}
}
Vector中大部分方法都使用synchronized修飾,是執行緒安全的。
Vector的使用
ArrayList V.S. Vector
- Vector的所有方法都是同步的;ArrayList的方法不是同步的;
- 在不需要同步時,建議使用ArrayList;
Stack
public class Stack<E> extends Vector<E> (java.util)
Stack的特點
Stack的實現機制
Stack的使用
集合類庫 - Set介面
public interface Set<E> extends Collection<E> (java.util)
Set集合和List集合都是存放的單個元素的序列,但是Set集合不允許有重複元素。
在Set介面中沒有新增任何方法,所有方法均來自其父介面。它無法提供像List中按位存取的方法。在數學上一個集合有三個性質:確定性、互異性、無序性。
HashSet
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable (java.util)
HashSet的特點
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的敞亮。由於使用了雜湊函式,因此其存取速度是非常快的。
HashSet的實現機制
/**
* 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);
}
在HashSet中有一個負載因子Load Factor。在HashSet的預設實現中,初始容量為16,負載因子為0.75,也就是說當有75%的空間以被使用,將會在進行一次再雜湊,之前的雜湊表(陣列)將被刪除,新增加的雜湊表是之前雜湊表長度的2倍,最大值為Integer.MAX_VALUE。
- 負載因子越高,記憶體使用率越大,元素的尋找時間越長;
- 負載因子越低,記憶體使用率越小,元素的尋找時間越短;
當雜湊值相同時,將存放在同一個位置,使用連結串列方式依次連結下去。
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的使用
HashSet是允許放空值的。
LinkedHashSet
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable (java.util)
LinkedHashSet的特點
LinkedHashSet保證了按照插入順序有序。
LinkedHashSet的實現機制
LinkedHashSet使用HashSet的建構函式:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
可以看出LinkedHashSet底層是使用LinkedHashMap實現的。LinkedHashSet繼承自HashSet,並沒有提供額外的供使用的方法,所以在使用時與HashSet基本相同。
LinkedHashSet的使用
TreeSet
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable (java.util)
TreeSet的特點
TreeSet中所放的元素是有序的,並且元素是不能重複的。
基於紅黑樹。
TreeSet的實現機制
TreeSet底層使用TreeMap使用,和HashSet一樣,將每個要放入的元素放到key的位置,value位置放的是一個Object型別的常量。
TreeSet的使用
集合類庫 - Map介面
public interface Map<K,V>
Map中的每個成員方法由一個關鍵字key和一個值value構成。Map介面不直接繼承自Collection介面,因為它包裝的是一組成對的“鍵-值”物件的集合,而且在Map介面的集合中也不能有重複的key出現,因為每個鍵只能與一個成員元素相對應。
HashMap
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
- HashMap是未同步的;
- 允許null key 和 null value;
- 方法public V get(Object key)返回null時,即表示hashmap中沒有該key,也表示該key所對應的value是null;因此使用containsKey來判斷是否存在某個key;
- HashMap利用key的hashCode重新計算hash值;
HashMap的特點
HashMap的實現機制
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;
}
Entry是一個節點,它持有下一個元素的引用,這樣就構成了一個連結串列。
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
這個方法根據hashCode記當前table的長度得到該元素應該存放的位置,即在table中的索引。
當元素超過threshold時,再雜湊的過程參看HashSet。
HashMap的使用
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);
}
}
HashTable
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable (java.util)
- HashTable是同步的;
- key或value均不能為null object;
- HashTable直接使用做為key物件的hashCode方法,因此作為key的物件必須實現hashCode和equals方法;
HashTable的特點
HashTable實現Map介面,繼承自Dictionary類。任何非空的(key - value)均可以放入其中。
HashTable的實現機制
HashTable的部分方法使用synchronized保證執行緒安全。
HashTable的使用
HashTable V.S. HashMap
- 如果不考慮執行緒安全,建議使用HashMap代替HashTable;如果需要執行緒安全,建議使用ConcurrentHashMap代替HashTable;
LinkedHashMap
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
LinkedHashMap的特點
LinkedHashMap繼承自HashMap實現了Map介面。和HashMap一樣,LinkedHashMap允許key和value均為null。
LinkedHashMap的實現機制
LinkedHashMap與HashMap的不同之處在於:LinkedHashMap維護著執行於所有條目的雙重連線列表,此連結列表可以時插入順序或者訪問順序。
LinkedHashMap的使用
TreeMap
參見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 | 雜湊表 | 是 |
集合類庫Utils
Collections(集合類包裝器)
(java.util)
public class Collections extends Object
包含一系列的靜態方法,操作或者返回一個集合類;
Arrays
(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;
}
}
方法2:
Iterator<String> sListIterator = list.iterator();
while(sListIterator.hasNext()){
String e = sListIterator.next();
if (e.equals("XXX")){
sListIterator.remove();
}
}
推薦使用方法2.
相關文章
- Java基礎 —— 集合(二)Java
- Java基礎-集合框架Java框架
- java基礎詳解-集合Java
- Java程式設計基礎17——集合(List集合)Java程式設計
- Java基礎之淺談集合Java
- Map集合(Java基礎、skycto JEEditor)Java
- 【JAVA】【面試】【基礎篇】- 集合Java面試
- java集合框架基礎總結Java框架
- Java基礎集合簡單總結Java
- Java 基礎 - 各項集合實現Java
- Android基礎之Java集合框架CollectionAndroidJava框架
- 【Java基礎知識】Java陣列與集合Java陣列
- 基礎篇:JAVA集合,面試專用Java面試
- 基礎-JAVA集合型別主要區別Java型別
- java基礎使用的集合大總結Java
- Java基礎之去除List集合中的重複元素Java
- Java集合原始碼分析之基礎(二):雜湊表Java原始碼
- Pyspark資料基礎操作集合Spark
- Python基礎知識之集合Python
- corejava基礎知識(5)-集合Java
- Java基礎 韓順平老師的 集合 的部分筆記Java筆記
- JAVA基礎 練習-13-ArrayList集合學生物件遍歷Java物件
- 傳智黑馬java基礎學習——day20(集合Map)Java
- Java集合原始碼分析之基礎(六):紅黑樹(RB Tree)Java原始碼
- android基礎學習-java篇day8-step3-第四節:java集合AndroidJava
- 傳智黑馬java基礎學習——day19(集合list、Set)Java
- Java集合原始碼分析之基礎(一):陣列與連結串列Java原始碼陣列
- 教程:Laravel 集合(Collection)的基礎用法Laravel
- Java基礎-語法基礎Java
- java基礎Java
- [Java基礎]Java
- JAVA 基礎Java
- Java 基礎02Java程式設計基礎Java程式設計
- Java集合原始碼分析之基礎(五):平衡二叉樹(AVL Tree)Java原始碼二叉樹
- Java基礎-物件導向基礎Java物件
- Python - 基礎資料型別 set 集合Python資料型別
- 學習python的基礎語法集合Python
- 豬行天下之Python基礎——3.4 集合Python
- Java基礎 —— 反射Java反射