標籤 : Java基礎html
Java集合由Collection
Map
兩個接口派生而出,Collection
表明序列式容器,Map
表明關聯式容器.java
Collection
做爲List
Queue
Set
等序列式容器的父接口, 提供了一些公共基礎方法:mysql
update相關方法:
boolean add(E e)
boolean addAll(Collection<? extends E> c)
void clear()
boolean remove(Object o)
boolean removeAll(Collection<?> c)
boolean retainAll(Collection<?> c)
(取交集)算法
select相關方法
boolean contains(Object o)
boolean containsAll(Collection<?> c)
Iterator<E> iterator()
Object[] toArray()
<T> T[] toArray(T[] a)
boolean isEmpty()
int size()
sql
詳細可參考JDK文檔編程
iterator()
方法返回一個迭代器Iterator
.與其餘容器主要用於存儲數據不一樣,Iterator
主要用於遍歷容器.
Iterator
隱藏了各種容器的底層實現細節,嚮應用程序提供了一個遍歷容器的統一接口:api
方法 | 釋義 |
---|---|
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). |
注意: 當遍歷
Collection
時不要使用Collection
自帶的remove
方法刪除數據,確實須要刪除時,須要使用Iterator
提供的remove
.數組
/** * @author jifang * @since 16/1/25 上午9:59. */
public class RemoveClient {
Collection<Integer> collection = new ArrayList<>();
@Before
public void setUp() {
Random random = new Random();
for (int i = 0; i < 10; ++i) {
collection.add(random.nextInt(i + 1));
}
}
@Test
public void client() {
System.out.print("before:");
for (Iterator<Integer> iterator = collection.iterator(); iterator.hasNext(); ) {
Integer integer = iterator.next();
System.out.printf(" %d", integer);
if (integer == 0) {
//collection.remove(i);
iterator.remove();
}
}
System.out.printf("%n after:");
for (Integer integer : collection) {
System.out.printf(" %d", integer);
}
}
}
Java 1.5提供foreach
循環使得代碼更加簡潔,但實際foreach
迭代容器元素底層也是用的Iterator
,這一點能夠在調試時看得很清楚.markdown
List
表明有序/可重複集合,所以List
在Collection
的基礎上添加了根據索引來操做元素的方法:數據結構
方法 | 描述 |
---|---|
void add(int index, E element) |
Inserts the specified element at the specified position in this list (optional operation). |
E get(int index) |
Returns the element at the specified position in this list. |
int indexOf(Object o) |
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. |
int lastIndexOf(Object o) |
Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element. |
E remove(int index) |
Removes the element at the specified position in this list (optional operation). |
E set(int index, E element) |
Replaces the element at the specified position in this list with the specified element (optional operation). |
List<E> subList(int fromIndex, int toIndex) |
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. |
List
判斷兩個元素是否相等是經過equals()
方法.
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;
}
List
增長了返回ListIterator
的方法:
方法 | 描述 |
---|---|
ListIterator<E> listIterator() |
Returns a list iterator over the elements in this list (in proper sequence). |
ListIterator<E> listIterator(int index) |
Returns a list iterator over the elements in this list (in proper sequence), starting at the specified position in the list. |
ListIterator
繼承自Iterator
,專門用於操做List
, 在Iterator
的基礎上增長了以下方法:
方法 | 描述 |
---|---|
void add(E e) |
Inserts the specified element into the list (optional operation). |
void set(E e) |
Replaces the last element returned by next() or previous() with the specified element (optional operation). |
boolean hasPrevious() |
Returns true if this list iterator has more elements when traversing the list in the reverse direction. |
E previous() |
Returns the previous element in the list and moves the cursor position backwards. |
int previousIndex() |
Returns the index of the element that would be returned by a subsequent call to previous(). |
int nextIndex() |
Returns the index of the element that would be returned by a subsequent call to next(). |
與Iterator
相比增長了前向迭代 獲取迭代元素index 以及add set的功能.
ArrayList
是List
基於數組的實現,它封裝了一個動態自增加/容許再分配的Object[]
數組:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
* DEFAULT_CAPACITY when the first element is added.
*/
private transient Object[] elementData;
ArrayList
可使用initialCapacity
參數來設置該數組的初始長度ArrayList(int initialCapacity)
,或者使用默認長度DEFAULT_CAPACITY = 10
; 當添加元素超過elementData
數組容量時,ArrayList
會從新分配數組, 以容納新元素:
/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */
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);
}
若是在建立時就知道ArrayList
的容量,最好同時指定initialCapacity
的大小,以免從新分配數組,耗費性能.
ArrayList
還提供以下方法來調整initialCapacity
大小:
方法 | 描述 |
---|---|
void ensureCapacity(int minCapacity) |
Increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument. |
void trimToSize() |
Trims the capacity of this ArrayList instance to be the list’s current size. |
工具類Arrays
還提供了一個static
方法List<T> asList(T... a)
, 該方法能夠把數組或N個對象轉換成一個List
集合, 這個List
集合並非普通的ArrayList
,而是Arrays
內部實現的一個Arrays.ArrayList
(一個固定長度的List
,不可對該集合作add/remove操做).
關於ArrayList
實現原理還能夠參考ArrayList源碼解析
LinkedList
是基於雙向鏈表實現的List,雖然能夠根據索引來訪問集合中的元素,但性能不高(平均時間複雜度爲O(N)
),但其插入/刪除操做很是迅速(尤爲是在頭尾,平均時間複雜度爲O(1)
);除此以外,LinkedList
還實現了Deque
接口,所以還能夠當成[雙端]隊列/棧來使用.
關於LinkedList
的實現原理還能夠參考 [1.LinkedList源碼解析, 2. 雙向循環鏈表的設計與實現]
/** * @author jifang * @since 16/1/23 下午9:07. */
public class ListClient {
private Random random = new Random();
@Test
public void client() {
List<Integer> list = new LinkedList<>();
for (int i = 0; i < 10; ++i) {
list.add(random.nextInt(i + 1));
}
for (ListIterator<Integer> i = list.listIterator(); i.hasNext(); ) {
if (i.next() == 0) {
i.set(188);
i.add(-1);
}
}
System.out.println(list);
}
}
Queue
用於模擬隊列,隊列是一種先進先出/FIFO容器,新元素插到隊尾(offer
), 訪問操做會返回隊首元素(poll
). 一般, 隊列不容許隨機訪問隊列中的元素:
方法 | 描述 |
---|---|
boolean add(E e) |
Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions, returning true upon success and throwing an IllegalStateException if no space is currently available. |
boolean offer(E e) |
Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions. |
E element() |
Retrieves, but does not remove, the head of this queue. |
E peek() |
Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty. |
E poll() |
Retrieves and removes the head of this queue, or returns null if this queue is empty. |
E remove() |
Retrieves and removes the head of this queue. |
Queue
有一個PriorityQueue
實現類,另外Queue
還有一個Deque
子接口,表明能夠從兩端存取數據的隊列(所以Deque
能夠當成Stack
使用),Java爲Deque
提供了ArrayDeque
和LinkedList
兩個實現類.
PriorityQueue
並非按照插入隊列順序進行排序,而是按照隊列元素的大小(權重)進行排序, 所以element/peek/poll/remove
返回的並非最先進入隊列的元素,而是隊列中[權重]最小的元素:
/** * @author jifang * @since 16/1/28 下午6:20. */
public class QueueClient {
@Test
public void clientPriorityQueue() {
Random random = new Random();
Queue<Integer> queue = new PriorityQueue<>();
for (int i = 0; i < 10; ++i) {
queue.add(random.nextInt(100));
}
// 無序
System.out.print("iterator:");
for (Integer i : queue) {
System.out.printf(" %d", i);
}
System.out.println();
// 有序
System.out.print("pool:");
while (!queue.isEmpty()) {
System.out.printf(" %d", queue.poll());
}
System.out.println();
}
}
能夠看到遍歷PriorityQueue
獲得的並非有序序列, 由於PriorityQueue
內部並非一個按照順序排序的數組, 而是一個二叉堆(詳細能夠參考[1. PriorityQueue源碼解析, 2. 堆與堆排序 ]).
因爲須要排序,
PriorityQueue
不容許插入null
;
PriorityQueue
的元素有兩種排序方式
Comparable
接口.PriorityQueue
時,傳入一個Comparator
實例,該對象負責對元素進行排序,採用定製排序時不要求隊列元素實現Comparable
接口.關於兩種排序的詳細內容能夠參考下面關於TreeMap
的討論.
Deque
接口表明一個雙端隊列,提供了以下方法從隊列的兩端存取數據:
Java爲Deque
提供了兩個實現類ArrayDeque
(基於數組)與LinkedList
(基於鏈表);因爲ArrayDeque
底層基於數組E[] elements
實現,所以建立時能夠指定一個numElements
參數設置elements
數組初始長度,若是不指定numElements
參數,默認數組長度爲16
(關於ArrayDeque
的實現原理可參考ArrayDeque源碼解析).
Deque
還能夠做爲棧stack
使用, 他提供了以下方法:
@Test
public void asStack() {
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < 10; ++i) {
stack.push(i);
}
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
此外,
LinkedList
也實現了Deque
接口,所以也能夠做爲Queue
/Deque
的實現類.
Map
用於保存具備映射關係的key-value
數據,key
和value
之間存在單向一對一關係,經過指定的key
,總能找到惟一肯定的value
.
update相關
V put(K key, V value)
void putAll(Map<? extends K,? extends V> m)
V remove(Object key)
void clear()
select相關
V get(Object key)
Set<K> keySet()
Collection<V> values()
Set<Map.Entry<K,V>> entrySet()
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
int size()
Map
內部定義一個Map.Entry<K,V>
接口,封裝key-value
對,Entry
提供以下方法:
方法 | 描述 |
---|---|
K getKey() |
Returns the key corresponding to this entry. |
V getValue() |
Returns the value corresponding to this entry. |
V setValue(V value) |
Replaces the value corresponding to this entry with the specified value (optional operation). |
HashMap
是基於hash
算法的Map
實現(用它代替Hashtable
),針對key-value
的插入/檢索,這種形式具備最穩定的性能(O(1)
),還可經過構造器對這一性能進行調整.
爲了成功在HashMap
中存取數據,key
對象必須實現hashCode()
與equals()
方法,HashMap
先經過key
的hashCode()
定位到元素所在桶,若是兩個元素在同一個桶,再用equals()
進行判斷是否相等.若是兩個對象的hashCode()
相同,但equals()
不一樣, 則將兩個對象放在同一個桶的不一樣鏈表位置(這樣會致使hash
效率降低).若是兩個對象經過equals()
返回true
, 但這hashCode()
不一樣,則很是有可能致使HashMap
將這兩個對象分配在不一樣桶中,從而使這兩個對象都添加成功,這就與Map
規則衝突了.(關於HashMap
詳細原理能夠參考: [1. 哈希表的設計與實現, 2.HashMap源碼解析]).
建議: 若是兩個對象經過
equals()
方法比較返回true
, 則兩個對象的hashCode()
值也相同.
hashCode()
重寫規則:
hashCode()
應具備相同返回值;equals()
比較返回true
時, hashCode()
應具備相同返回值;equals()
比較標準的實例變量, 都應該用於計算hashCode()
.hashCode()
重寫方法:
int
的
hashcode
值.
類型 | 計算方式 |
---|---|
boolean |
hashCode = (true ? 1 : 0); |
float |
hashCode = Float.floatToIntBits(f); |
double |
long value = Double.doubleToLongBits(f); |
hashCode = (int)(value^(value>>>32)); |
|
int /short /byte |
hashCode = (int)i; |
long |
hashCode = (int)(l^(l>>>32)); |
引用類型 | hashCode = object.hashCode(); |
hashcode
組合計算成一個最終的
hashcode
,爲了不直接相加產生偶然相等,能夠爲各個
hashcode
乘以任意一個質數再相加:
String
實現public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
String
的hashCode()
方法作了一些優化, 叫閃存散列碼, 詳見數據結構與算法分析 : Java語言描述
Bean
/** * @author jifang * @since 16/1/13下午7:50. */
public class Bean implements Serializable {
private static final long serialVersionUID = 2975296536292876992L;
private boolean isUsed;
private double rate;
private String name;
@Override
public int hashCode() {
long rateHash = Double.doubleToLongBits(rate);
int isUsedHash = isUsed ? 1 : 0;
int nameHash = name.hashCode();
return nameHash * 11 + (int) (rateHash ^ (rateHash >>> 32)) * 13 + isUsedHash;
}
// ..
}
HashMap
的主要實現邏輯:/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
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;
}
/**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);
}
/**
* Like addEntry except that this version is used when creating entries
* as part of Map construction or "pseudo-construction" (cloning,
* deserialization). This version needn't worry about resizing the table.
*
* Subclass overrides this to alter the behavior of HashMap(Map),
* clone, and readObject.
*/
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
注意
- 當向
Map
類容器(如HashMap
TreeMap
或後面的HashSet
TreeSet
)中添加可變對象時,必須十分當心,若是修改Map
中的key
,有可能致使該key
與集合中的其餘key
相等,從而致使沒法準確訪問該key-value
.所以儘可能不要使用可變對象做爲Map
的key
,或不要修改做爲key
的對象(Set
的value
於此類同)Map
還支持containsValue()
方法來判斷一個value
是否存在於Map
中, 但該方法會遍歷全部的桶查找這個值, 所以性能較差, 不推薦使用
public boolean containsValue(Object value) {
if (value == null)
return containsNullValue();
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (value.equals(e.value))
return true;
return false;
}
/** * Special-case code for containsValue with null argument */
private boolean containsNullValue() {
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (e.value == null)
return true;
return false;
}
LinkedHashMap
使用雙向鏈表來維護key-value
插入順序,所以性能略低於HashMap
,但在須要順序迭代Map
的場景下會有很是好的效率.
LinkedHashMap
提供的addEntry()
方法與HashMap
有所不一樣,當使用LinkedHashMap
的put()
時, 會從HashMap
調回到LinkedHashMap
的addEntry()
方法,將新元素添加到鏈表尾:
/** * This override alters behavior of superclass put method. It causes newly * allocated entry to get inserted at the end of the linked list and * removes the eldest entry if appropriate. */
void addEntry(int hash, K key, V value, int bucketIndex) {
super.addEntry(hash, key, value, bucketIndex);
// Remove eldest entry if instructed
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
}
}
/** * This override differs from addEntry in that it doesn't resize the * table or remove the eldest entry. */
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
}
LinkedHashMap
統計word出現次數/** * @author jifang * @since 16/1/28 上午10:33. */
public class MapClient {
private Random random = new Random();
@Test
public void clientLinkedHashMap() {
Map<String, Integer> map = new LinkedHashMap<>();
System.out.print("insert key:");
for (int i = 0; i < 20; ++i) {
String key = String.valueOf(random.nextInt(10));
System.out.printf(" %s", key);
if (map.get(key) == null) {
map.put(key, 1);
} else {
map.put(key, map.get(key) + 1);
}
}
System.out.printf("%n iterator:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.printf(" <%s -> %s>", entry.getKey(), entry.getValue());
}
}
}
WeakHashMap
與HashMap
的區別在於:HashMap
的key
保留了對實際對象的強引用, 這意味着只要該HashMap
不被銷燬,則Map
的全部key
所引用的對象不會被垃圾回收;但WeakHashMap
的key
只保留對實際對象的弱引用, 這意味着若是該key
所引用的對象沒有被其餘強引用變量引用,則該對象可能被垃圾回收,WeakHashMap
也會自動刪除這些key
對應的key-value
對.
@Test
public void clientWeakHashMap() {
Map<String, String> map = new WeakHashMap<>();
String key = "key";
map.put(key, "value");
map.put(new String("key1"), "value");
map.put(new String("key2"), "value");
System.out.printf("Before : %d%n", map.size());
System.gc();
System.runFinalization();
System.out.printf("After : %d ", map.size());
}
若是使用
WeakHashMap
來保留對象的弱引用,則不要讓該key
所引用的對象具備任何強引用, 不然將失去使用WeakHashMap
的意義.
與HashMap
不一樣,IdentityHashMap
判斷元素是否相等的標準是用==
而不是equals()
;
public boolean containsKey(Object key) {
Object k = maskNull(key);
Object[] tab = table;
int len = tab.length;
int i = hash(k, len);
while (true) {
Object item = tab[i];
if (item == k)
return true;
if (item == null)
return false;
i = nextKeyIndex(i, len);
}
}
Map
接口派生出SortedMap
接口表明根據key
排序的key-value
集合, TreeMap
做爲SortedMap
的實現類是一個紅黑樹結構,每一個key-value
做爲紅黑樹的一個節點.TreeMap
存儲key-value
時,根據key
值進行排序.所以TreeMap
能夠保證全部元素都處於有序狀態,所以SortedMap
在Map
的基礎上又添加了以下方法:
方法 | 描述 |
---|---|
Comparator<? super K> comparator() |
Returns the comparator used to order the keys in this map, or null if this map uses the natural ordering of its keys. |
K firstKey() |
Returns the first (lowest) key currently in this map. |
K lastKey() |
Returns the last (highest) key currently in this map. |
SortedMap<K,V> headMap(K toKey) |
Returns a view of the portion of this map whose keys are strictly less than toKey. |
SortedMap<K,V> tailMap(K fromKey) |
Returns a view of the portion of this map whose keys are greater than or equal to fromKey. |
SortedMap<K,V> subMap(K fromKey, K toKey) |
Returns a view of the portion of this map whose keys range from fromKey, inclusive, to toKey, exclusive. |
而TreeMap
又在SortedMap
的基礎上擴展了以下方法:
方法 | 描述 |
---|---|
Map.Entry<K,V> ceilingEntry(K key) |
Returns a key-value mapping associated with the least key greater than or equal to the given key, or null if there is no such key. |
K ceilingKey(K key) |
Returns the least key greater than or equal to the given key, or null if there is no such key. |
Map.Entry<K,V> floorEntry(K key) |
Returns a key-value mapping associated with the greatest key less than or equal to the given key, or null if there is no such key. |
K floorKey(K key) |
Returns the greatest key less than or equal to the given key, or null if there is no such key. |
Map.Entry<K,V> higherEntry(K key) |
Returns a key-value mapping associated with the least key strictly greater than the given key, or null if there is no such key. |
K higherKey(K key) |
Returns the least key strictly greater than the given key, or null if there is no such key. |
Map.Entry<K,V> lowerEntry(K key) |
Returns a key-value mapping associated with the greatest key strictly less than the given key, or null if there is no such key. |
K lowerKey(K key) |
Returns the greatest key strictly less than the given key, or null if there is no such key. |
Map.Entry<K,V> pollFirstEntry() |
Removes and returns a key-value mapping associated with the least key in this map, or null if the map is empty. |
Map.Entry<K,V> pollLastEntry() |
Removes and returns a key-value mapping associated with the greatest key in this map, or null if the map is empty. |
Map.Entry<K,V> firstEntry() |
Returns a key-value mapping associated with the least key in this map, or null if the map is empty. |
Map.Entry<K,V> lastEntry() |
Returns a key-value mapping associated with the greatest key in this map, or null if the map is empty. |
TreeMap
有兩種排序方式:
TreeMap
的全部key
必須實現Comparable
接口,TreeMap
會調用key
的int compareTo(T o);
方法來比較元素的大小,而後將集合元素升序排列.
/** * Compares two keys using the correct comparison method for this TreeMap. */
final int compare(Object k1, Object k2) {
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
: comparator.compare((K)k1, (K)k2);
}
Java提供的java.lang.Comparable
接口僅包含一個int compareTo(T o);
方法.大部分經常使用類都實現了該接口(如String
, Integer
等).
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
與
HashMap
不一樣,TreeMap
判斷兩個key
是否相等的惟一標準是:經過compareTo
方法比較返回值是否爲0.
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
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;
}
Comparable
/** * @author jifang * @since 16/1/13下午7:50. */
public class Bean implements Comparable<Bean> {
private boolean isUsed;
private double rate;
private String name;
public Bean(boolean isUsed, double rate, String name) {
this.isUsed = isUsed;
this.rate = rate;
this.name = name;
}
@Override
public int compareTo(Bean anotherBean) {
double another = (anotherBean.isUsed ? 1 : 0) +
anotherBean.rate + anotherBean.name.length();
double self = (isUsed ? 1 : 0) + rate + name.length();
return (int) (self - another);
}
@Override
public String toString() {
return "Bean{" +
"isUsed=" + isUsed +
", rate=" + rate +
", name='" + name + '\'' +
'}';
}
}
@Test
public void clientSortedMap() {
// value做爲指望的order
SortedMap<Bean, Integer> map = new TreeMap<>();
map.put(new Bean(true, 3.14, "true"), 1);
// 該對象與上面的bean compare會返回0
map.put(new Bean(false, 3.14, "false"), 1);
map.put(new Bean(true, 3.14, "false"), 2);
map.put(new Bean(false, 3.14, "true"), 0);
System.out.println(map);
Bean firstKey = map.firstKey();
System.out.printf("first: %s -> %d%n", firstKey, map.get(firstKey));
Bean lastKey = map.lastKey();
System.out.printf("last: %s -> %d%n", lastKey, map.get(lastKey));
map.remove(firstKey);
Map.Entry<Bean, Integer> firstEntry = ((TreeMap<Bean, Integer>) map).firstEntry();
System.out.printf("A first: %s -> %d%n", firstEntry.getKey(), firstEntry.getValue());
}
當執行了
remove
方法後,TreeMap
會對集合中的元素從新索引, 這一點能夠在調試時看到.
TreeMap
默認的是使用升序排序,若是須要自定義排序規則,須要爲其傳入一個Comparator
實例, 採用定製排序時不要求key
實現Comparable
.
public class MapClient {
private Comparator<Bean> comparator = new Comparator<Bean>() {
@Override
public int compare(Bean o1, Bean o2) {
// 返回正數: 說明o1 > o2
// 返回負數: 說明o1 < o2
return -o1.compareTo(o2);
}
};
@Test
public void clientSortedMap() {
SortedMap<Bean, Integer> map = new TreeMap<>(comparator);
// ...
}
}
因爲
TreeMap
是基於紅黑樹實現,所以相比HashMap
性能要慢一點(Hash平均O(1)
,Tree平均O(lgN)
詳細可參考[1. TreeMap源碼解析, 2.紅黑樹的設計與實現(上)]),但其中的key-value
已經是有序狀態,無需再有專門的排序操做.所以適用於key
有序的場景.
EnumMap
是一個須要與枚舉類一塊兒使用的Map
,其全部key
都必須是單個枚舉類的枚舉值.EnumMap
具備如下特徵:
EnumMap
內部以數組形式存儲,緊湊/高效,是Map
全部實現中性能最好的.EnumMap
根據key
的天然順序(枚舉值在枚舉類的定義順序)來維護key-value
順序.EnumMap
不容許key
爲null
, 但容許使用null
做爲value
./** * @author jifang * @since 16/1/27 下午4:01. */
public enum ShopListType {
BLACK_LIST(0, "黑名單"),
WHITE_LIST(1, "白名單"),
INVITE_LIST(2, "邀請名單"),
RECOMMEND_WHITE_LIST(3, "推薦白名單"),
RECOMMEND_BLACK_LIST(4, "推薦黑名單");
private int type;
private String description;
ShopListType(int type, String description) {
this.type = type;
this.description = description;
}
public int getValue() {
return type;
}
public String getDescription() {
return description;
}
}
@Test
public void clientEnumMap() {
EnumMap<ShopListType, String> map = new EnumMap<>(ShopListType.class);
map.put(ShopListType.BLACK_LIST, "黑名單");
map.put(ShopListType.WHITE_LIST, "白名單");
System.out.println(map);
}
Set
與Map
關係很是密切, 雖然Map
中存放的是key-value
, Set
中存放的是單個對象, 但從JDK源代碼看, Java是先實現了Map
,而後包裝一個空Object
來填充全部的value
來實現的Set
.
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
Set
繼承自Collection
, 沒有提供額外的方法;
HashSet
是Set
接口的典型實現,是Set
中用的最多的實現.因爲HashSet
是基於HashMap
實現的,所以具備以下特色:
HashSet
, 須要開發人員本身保證同步;null
;因爲LinkedHashSet
底層是基於LinkedHashMap
實現,所以Set
能夠記錄元素的插入順序,當遍歷LinkedHashSet
時,將會按照元素的添加順序來訪問集合中的元素:
/** * @author jifang * @since 16/1/26 下午2:09. */
public class SetClient {
@Test
public void clientLinkedHashSet() {
Set<Integer> set = new LinkedHashSet<>();
for (int i = 0; i < 10; ++i) {
set.add(i);
}
for (int i = 19; i >= 10; --i) {
set.add(i);
}
System.out.println(set);
}
}
LinkedHashSet
的優缺點與LinkedHashMap
相似.
SortedSet
接口繼承自Set
,Java爲SortedSet
提供了TreeSet
實現,因爲SortedSet
能夠確保集合元素能夠處於已排序狀態, 所以在Set
的基礎上又提供了以下方法:
類型 | 計算方式 |
---|---|
Comparator<? super E> comparator() |
Returns the comparator used to order the elements in this set, or null if this set uses the natural ordering of its elements. |
E first() |
Returns the first (lowest) element currently in this set. |
E last() |
Returns the last (highest) element currently in this set. |
SortedSet<E> tailSet(E fromElement) |
Returns a view of the portion of this set whose elements are greater than or equal to fromElement. |
SortedSet<E> headSet(E toElement) |
Returns a view of the portion of this set whose elements are strictly less than toElement. |
SortedSet<E> subSet(E fromElement, E toElement) |
Returns a view of the portion of this set whose elements range from fromElement, inclusive, to toElement, exclusive. |
TreeSet
相比於SortedSet
還提供了以下實用方法:
類型 | 計算方式 |
---|---|
E ceiling(E e) |
Returns the least element in this set greater than or equal to the given element, or null if there is no such element. |
E floor(E e) |
Returns the greatest element in this set less than or equal to the given element, or null if there is no such element. |
Iterator<E> descendingIterator() |
Returns an iterator over the elements in this set in descending order. |
NavigableSet<E> descendingSet() |
Returns a reverse order view of the elements contained in this set. |
E higher(E e) |
Returns the least element in this set strictly greater than the given element, or null if there is no such element. |
E lower(E e) |
Returns the greatest element in this set strictly less than the given element, or null if there is no such element. |
E pollFirst() |
Retrieves and removes the first (lowest) element, or returns null if this set is empty. |
E pollLast() |
Retrieves and removes the last (highest) element, or returns null if this set is empty. |
因爲
TreeSet
底層採用TreeMap
實現, 所以其性能特色以及排序規則能夠參考TreeMap
.
EnumSet
是專門爲枚舉設計的Set
,全部的元素必須是單一枚舉類的枚舉值.EnumSet
也是有序的,以枚舉值在Enum
類內定義的順序來排序;因爲EnumSet
沒有暴露任何構造器,所以須要經過他提供的以下static
方法來建立EnumSet
實例:
allOf(Class<E> elementType)
complementOf(EnumSet<E> s)
copyOf(Collection<E> c)
noneOf(Class<E> elementType)
of(E first, E... rest)
range(E from, E to)
@Test
public void clientEnumSet() {
EnumSet<ShopListType> set1 = EnumSet.allOf(ShopListType.class);
System.out.println(set1);
EnumSet<ShopListType> set2 = EnumSet.noneOf(ShopListType.class);
System.out.println(set2);
set2.add(ShopListType.BLACK_LIST);
System.out.println(set2);
}
EnumSet
的內部以位向量的形式存儲,緊湊/高效,所以EnumSet
佔用內存小,運行效率高,是Set
實現類中性能最好的. 尤爲是批量操做(containsAll()
,retainAll()
)時,若是參數也是EnumSet
, 則執行效率很是快(詳細可參考Java EnumSet工做原理初窺).
Java提供了一個操做List
Map
Set
等集合的工具類Collections
, 其提供了大量的工具方法對集合元素進行排序 查找 更新等操做:
排序相關
sort(List<T> list)
sort(List<T> list, Comparator<? super T> c)
shuffle(List<?> list)
swap(List<?> list, int i, int j)
reverse(List<?> list)
reverseOrder(Comparator<T> cmp)
rotate(List<?> list, int distance)
查找相關
binarySearch(List<? extends Comparable<? super T>> list, T key)
binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
indexOfSubList(List<?> source, List<?> target)
lastIndexOfSubList(List<?> source, List<?> target)
max(Collection<? extends T> coll)
max(Collection<? extends T> coll, Comparator<? super T> comp)
min(Collection<? extends T> coll)
min(Collection<? extends T> coll, Comparator<? super T> comp)
更新相關
addAll(Collection<? super T> c, T... elements)
fill(List<? super T> list, T obj)
nCopies(int n, T o)
不可變集合視圖
unmodifiableCollection(Collection<? extends T> c)
unmodifiableList(List<? extends T> list)
unmodifiableMap(Map<? extends K,? extends V> m)
unmodifiableSet(Set<? extends T> s)
unmodifiableSortedMap(SortedMap<K,? extends V> m)
unmodifiableSortedSet(SortedSet<T> s)
單元素集合
Set<T> singleton(T o)
singletonList(T o)
singletonMap(K key, V value)
空集合
emptyList()
emptyMap()
emptySet()
Collections
提供了三個靜態變量來表明一個空集合
static List EMPTY_LIST
static Map EMPTY_MAP
static Set EMPTY_SET
同步集合
詳見Java 併發基礎
Java還提供了一些集合工具:Hashtable
Vactor
Stack
Enumeration
StringTokenizer
(Enumeration
的一個實現類,其功能相似於String
的split()
,但不支持正則,實現將字符串進行分割, 而後迭代取出), 這些集合工具都是從Java 1.0開始就存在的, 但其實現要麼性能較低(須要保持線程同步), 要麼方法名繁瑣(如hasMoreElements()
), 如今已經不多使用,並且其使用方法也與前面的集合相似, 所以在此就不作過多介紹了. 若是在實際開發中會遇到還在使用這些工具的代碼(好比Dom4j),能夠參考JDK文檔.
Properties
是Hashtable
的子類,他能夠把Map
和屬性文件關聯起來,從而能夠把Map
對象中的key-value
寫入屬性文件, 也能夠將屬性文件中的」屬性名=屬性值」加載到Map
中,因爲屬性文件中的屬性名/屬性值都是String
,所以Properties
的key-value
都只能是String
.Properties
提供了以下方法來讀寫內存中的key-value
.
方法 | 描述 |
---|---|
String getProperty(String key) |
Searches for the property with the specified key in this property list. |
String getProperty(String key, String defaultValue) |
Searches for the property with the specified key in this property list. |
Object setProperty(String key, String value) |
Calls the Hashtable method put. |
Enumeration<?> propertyNames() |
Returns an enumeration of all the keys in this property list, including distinct keys in the default property list if a key of the same name has not already been found from the main properties list. |
Set<String> stringPropertyNames() |
Returns a set of keys in this property list where the key and its corresponding value are strings, including distinct keys in the default property list if a key of the same name has not already been found from the main properties list. |
Properties
還提供了讀寫屬性文件的方法:
方法 | 描述 |
---|---|
void list(PrintStream/PrintWriter out) |
Prints this property list out to the specified output stream/writer. |
void load(InputStream/Reader in) |
Reads a property list (key and element pairs) from the input byte/character stream. |
void store(OutputStream/Write out, String comments) |
Writes this property list (key and element pairs) in this Properties table to the output stream/write in a format suitable for loading into a Properties table using the load(InputStream/Reader) method. |
dubbo.version=1.0.0
## Data Source
mysql.driver.class=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://192.168.9.166:3306/common
mysql.user=admin
mysql.password=admin
@Test
public void clientProperties() throws IOException {
Properties properties = new Properties();
properties.load(ClassLoader.getSystemResourceAsStream("common.properties"));
System.out.println(properties.get("mysql.driver.class"));
properties.put("mysql.user", "root");
properties.put("mysql.password", "root");
properties.store(new FileOutputStream("common.properties"), "comment");
}
Properties
還能夠從XML中加載key-value
,也能夠以XML形式保存,其用法與普通.properties
文件相似.