此篇相关的类在 02 篇。
1. keys()
- 获取 key 值的迭代器
public Enumeration<K> keys() {
Node<K,V>[] t;
int f = (t = table) == null ? 0 : t.length;
return new KeyIterator<K,V>(t, f, 0, f, this);
}
2. keySet()、keySet(V mappedValue)
- 获取 key 值的视图
public KeySetView<K,V> keySet() {
KeySetView<K,V> ks;
return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
}
public KeySetView<K,V> keySet(V mappedValue) {
if (mappedValue == null)
throw new NullPointerException();
return new KeySetView<K,V>(this, mappedValue);
}
3. values()
- 获取 value 值的视图
public Collection<V> values() {
ValuesView<K,V> vs;
return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
}
4. elements()
- 获取 value 值的迭代器
public Enumeration<V> elements() {
Node<K,V>[] t;
int f = (t = table) == null ? 0 : t.length;
return new ValueIterator<K,V>(t, f, 0, f, this);
}
5. entrySet()
- 获取键值对的视图
public Set<Map.Entry<K,V>> entrySet() {
EntrySetView<K,V> es;
return(es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
}
6. 小总结
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap.KeySetView;
public class ConcurrentHashMapTest09 {
public static void main(String[] args) {
ConcurrentHashMap<Integer, Integer> concurrentHashMap = new ConcurrentHashMap<>();
for(int i = 1; i <= 20; i++) {
concurrentHashMap.put(i, i);
}
System.out.println("now concurrentHashMap: " + concurrentHashMap);
Enumeration<Integer> keys = concurrentHashMap.keys();
System.out.println("Enumeration --> keys: " + keys);
long start01 = System.currentTimeMillis();
System.out.print("Enumeration 遍历 keys 元素: ");
while (keys.hasMoreElements()) {
System.out.print(keys.nextElement() + "\t");
}
long end01 = System.currentTimeMillis();
System.out.println();
System.out.println("Enumeration 耗时: " + (end01 - start01) + "ms");
Iterator<Integer> iterator = concurrentHashMap.keySet().iterator();
long start02 = System.currentTimeMillis();
System.out.print("Iterator 遍历 keySet 元素: ");
while (iterator.hasNext()) {
System.out.print(iterator.next() + "\t");
}
System.out.println();
long end02 = System.currentTimeMillis();
System.out.println("Iterator 耗时: " + (end02 - start02) + "ms");
KeySetView<Integer, Integer> keySet1 = concurrentHashMap.keySet(5);
System.out.println("keySet1: " + keySet1);
Enumeration<Integer> elements = concurrentHashMap.elements();
System.out.println("Enumeration --> elements: " + elements);
Collection<Integer> values = concurrentHashMap.values();
System.out.println("values: " + values);
Set<Entry<Integer, Integer>> entries = concurrentHashMap.entrySet();
System.out.println("entries: " + entries);
}
}
具有 迭代器Iterator,肯定少不了 分解迭代器 Spliterator 的使用。
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap.KeySetView;
public class ConcurrentHashMapTest10 {
public static void main(String[] args) {
ConcurrentHashMap<Integer, Integer> concurrentHashMap = new ConcurrentHashMap<>();
for(int i = 1; i <= 20; i++) {
concurrentHashMap.put(i, i);
}
System.out.println("now concurrentHashMap: " + concurrentHashMap);
KeySetView<Integer, Integer> keySet = concurrentHashMap.keySet(5);
System.out.println("keySet: " + keySet);
Spliterator<Integer> keySpliterator = keySet.spliterator();
keySpliterator.tryAdvance((key)-> {
System.out.println("keySpliterator tryAdvance: " + key);
});
Spliterator<Integer> keySpliterator01 = keySpliterator.trySplit();
System.out.print("keySpliterator forEachRemaining: ");
keySpliterator.forEachRemaining((key) -> System.out.print(key + "\t"));
System.out.println();
System.out.print("keySpliterator01 forEachRemaining: ");
keySpliterator01.forEachRemaining((key) -> System.out.print(key + "\t"));
System.out.println();
System.out.println("===================================");
Collection<Integer> values = concurrentHashMap.values();
System.out.println("values: " + values);
Spliterator<Integer> valueSpliterator = values.spliterator();
valueSpliterator.tryAdvance((key)-> {
System.out.println("values tryAdvance: " + key);
});
Spliterator<Integer> valueSpliterator01 = valueSpliterator.trySplit();
System.out.print("valueSpliterator forEachRemaining: ");
valueSpliterator.forEachRemaining((key) -> System.out.print(key + "\t"));
System.out.println();
System.out.print("valueSpliterator01 forEachRemaining: ");
valueSpliterator01.forEachRemaining((key) -> System.out.print(key + "\t"));
System.out.println();
System.out.println("===================================");
Set<Entry<Integer, Integer>> entries = concurrentHashMap.entrySet();
System.out.println("entries: " + entries);
Spliterator<Entry<Integer, Integer>> entrySpliterator = entries.spliterator();
entrySpliterator.tryAdvance((entry)-> {
System.out.println("entries tryAdvance: " + entry);
});
Spliterator<Entry<Integer, Integer>> entrySpliterator01 = entrySpliterator.trySplit();
System.out.print("entrySpliterator forEachRemaining: ");
entrySpliterator.forEachRemaining((entry) -> System.out.print(entry + "\t"));
System.out.println();
System.out.print("entrySpliterator01 forEachRemaining: ");
entrySpliterator01.forEachRemaining((entry) -> System.out.print(entry + "\t"));
System.out.println();
}
}
- trySplit() 是剩下未遍历的桶位对半分。执行完 tryAdvance 后,剩下的桶位下标为 [2, 32),分割时 mid = (2 + 32) >> 1 = 17,则两个分解迭代器的下标分别为 [2,17),[17,32]。所以 Spliterator01 输出为 17 - 20。
7. newKeySet()
- 静态方法,初始化一个ConcurrentHashMap 值为 true 的 keySet 视图
public static <K> KeySetView<K,Boolean> newKeySet() {
return new KeySetView<K,Boolean>
(new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
}
/* initialCapacity:初始化容量 */
public static <K> KeySetView<K,Boolean> newKeySet(int initialCapacity) {
return new KeySetView<K,Boolean>
(new ConcurrentHashMap<K,Boolean>(initialCapacity), Boolean.TRUE);
}
- 代码演示
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap.KeySetView;
public class ConcurrentHashMapTest11 {
public static void main(String[] args) throws Exception {
/* 默认初始化容量为 DEFAULT_CAPACITY = 16 */
KeySetView<Object, Boolean> keySetView = ConcurrentHashMap.newKeySet();
/* 初始化容量计算公式 tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1)
* tableSizeFor(30 + 30 >> 1 + 1) = tableSizeFor(45) = 64 */
KeySetView<Object, Boolean> keySetView01 = ConcurrentHashMap.newKeySet(30);
for(int i = 1; i <= 10; i++) {
keySetView.add(i);
keySetView01.add(i);
}
Class<? extends KeySetView> keySetClass = keySetView.getClass();
Class<? extends KeySetView> keySetClass01 = keySetView01.getClass();
Field value = keySetClass.getDeclaredField("value");
Field value01 = keySetClass01.getDeclaredField("value");
value.setAccessible(true);
value01.setAccessible(true);
System.out.println("KeySetView 的 value 值" + value.get(keySetView));
System.out.println("KeySetView01 的 value 值" + value01.get(keySetView01));
Class<?> keySetClassSuperclassClass = keySetClass.getSuperclass();
Class<?> keySetClassSuperclassClass01 = keySetClass01.getSuperclass();
Field map = keySetClassSuperclassClass.getDeclaredField("map");
Field map01 = keySetClassSuperclassClass01.getDeclaredField("map");
map.setAccessible(true);
map01.setAccessible(true);
ConcurrentHashMap concurrentHashMap = (ConcurrentHashMap) map.get(keySetView);
ConcurrentHashMap concurrentHashMap01 = (ConcurrentHashMap) map01.get(keySetView01);
System.out.println("keySetClassSuperclassClass 的 map 值" + concurrentHashMap);
System.out.println("keySetClassSuperclassClass 的 map01 值" + concurrentHashMap01);
System.out.println("================ 以下代码体现初始化容量的差别 ===============");
Field table = concurrentHashMap.getClass().getDeclaredField("table");
Field table01 = concurrentHashMap01.getClass().getDeclaredField("table");
table.setAccessible(true);
table01.setAccessible(true);
Object[] objects = (Object[]) table.get(concurrentHashMap);
Object[] objects01 = (Object[]) table01.get(concurrentHashMap01);
System.out.println("keySetClassSuperclassClass 的 map 的 table.length(): " + objects.length);
System.out.println("keySetClassSuperclassClass 的 map01 的 table01.length(): " + objects01.length);
}
}