java学习day7--双列集合
·
双列集合
每次添加一次性添加两个元素。键是不可重复的,值是可以重复的,键和值一一对应。一个键和值组合在一起称为键值对(也叫键值对对象,Entry对象)。
Map集合
map集合是双列结合的顶层接口.存取是无序的
Map集合常见API
put(),remove(),clear(),containsKey(),containsValue(),isEmpty().size().
package com.mymap1;
import java.util.HashMap;
import java.util.Map;
public class MyMapDemo1 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
//添加元素
//put方法可以添加元素,并且可以实现覆盖功能
//添加数据时键不存在,直接把键值对对象添加到集合
//添加数据时键存在,会把键值对对象覆盖,并返回被覆盖的值。
map.put("111","222");
map.put("333","444");
map.put("555","666");
System.out.println(map);
System.out.println("-------------");
//remove仅通过key删除时,会返回删除键的值
//通过键值删除时会返回布尔类型,表示删除成功或失败
String remove = map.remove("111");
System.out.println(remove);
// System.out.println(map.remove("111","222"));
System.out.println(map);
System.out.println("-------------");
//clear()方法
// map.clear();
// System.out.println(map);
}
}
除了put方法,其余方法都是简单可使用的。
Map集合遍历方式
1.键找值
将双列结合的键全部获取出来,组成一个单列结合,然后用遍历单列结合的方式,用get方法获得值。
package com.mymap1;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class MyMapDemo2 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("aaa","111");
map.put("bbb","222");
map.put("ccc","333");
//利用键找值方式遍历
Set<String> keys = map.keySet();//调用keySet()方法,将key存入到Set集合中
//用迭代器也可以
Iterator<String> iterator = keys.iterator();
while(iterator.hasNext()){
String next = iterator.next();
String s = map.get(next);
System.out.println(next + "=" + s);
}
System.out.println("-------------");
//增强for遍历单列集合
for (String key : keys) {
//System.out.println(key);
String s = map.get(key);
System.out.println(key + "=" + s);
}
System.out.println("-------------");
//使用匿名内部类及lambda表达式
// keys.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// String s1 = map.get(s);
// System.out.println(s + "=" + s1);
// }
// });
keys.forEach(s->{
String s1 = map.get(s);
System.out.println(s + "=" + s1);
});
}
}
2.键值对
依次获取每一个键值对对象。
package com.mymap1;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class MyMapDemo3 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("aaa","111");
map.put("bbb","222");
map.put("ccc","333");
//使用键值对对象遍历
//使用entrySet方法获得所有键值对对象,放入set集合中。
Set<Map.Entry<String, String>> entries = map.entrySet();
//迭代器
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
String key = next.getKey();
String value = next.getValue();
System.out.println(key + "=" + value);
}
System.out.println("-----------------");
//增强for
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
System.out.println("-----------------");
//匿名内部类
entries.forEach(new Consumer<Map.Entry<String, String>>() {
@Override
public void accept(Map.Entry<String, String> s) {
String key = s.getKey();
String value = s.getValue();
System.out.println(key + "=" + value);
}
});
System.out.println("-----------------");
//lambda表达式
entries.forEach(s->{
String key = s.getKey();
String value = s.getValue();
System.out.println(key + "=" + value);
});
}
}
3.lambda表达式
使用forEach(new biConsumer).
package com.mymap1;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class MyMapDemo4 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("aaa","111");
map.put("bbb","222");
map.put("ccc","333");
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key + "=" + value);
}
});
System.out.println("--------------------");
map.forEach(( key, value)-> System.out.println(key + "=" + value));
}
}
HashMap
无序、不重复、无索引
也是哈希表结构,与昨天学的HashSet一样,使用hahcode方法和equals方法保证数据不重复。
因为此处存入的是entry对象,但是比较时只计算键的哈希值,因此当键存储的是自定义对象时需要重写hasCode和entry方法。值存储自定义对象却不需要重写。
LinkedHashMap
有序,不重复,无索引。使用双链表实现了存取的有序。
TreeMap
可排序,不重复,无索引。使用键进行排序,默认从小到大。可以自己制定排序规则。
HashMap底层原理
底层会生成一个数组table,数组真正形成是在添加数据时。使用空参构造生成集合时只赋值了加载因子(也就是当数组长度达到数组长度*加载因子个数时,数字自动扩容为原先两倍)。看了源码。
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
TreeMap
//添加数据
private V put(K key, V value, boolean replaceOld) {
Entry<K,V> t = root;
if (t == null) {
addEntryToEmptyMap(key, value);
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else {
V oldValue = t.value;
if (replaceOld || oldValue == null) {
t.value = value;
}
return oldValue;
}
} while (t != null);
} else {
Objects.requireNonNull(key);
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else {
V oldValue = t.value;
if (replaceOld || oldValue == null) {
t.value = value;
}
return oldValue;
}
} while (t != null);
}
addEntry(key, value, parent, cmp < 0);
return null;
}
private void addEntry(K key, V value, Entry<K, V> parent, boolean addToLeft) {
Entry<K,V> e = new Entry<>(key, value, parent);
if (addToLeft)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
}
//红黑规则
private void fixAfterInsertion(Entry<K,V> x) {
x.color = RED;
while (x != null && x != root && x.parent.color == RED) {
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
Entry<K,V> y = rightOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
rotateLeft(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
} else {
Entry<K,V> y = leftOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == leftOf(parentOf(x))) {
x = parentOf(x);
rotateRight(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = BLACK;
}
注;
HashMap 默认情况下用这个,因为他的效率最高
LinkedHashMap 需要存取有序时使用
TreeMap 需要排序时使用。
更多推荐




所有评论(0)