Map
Map接口是将键映射到值的对象
特点
1.无序
2.键可以重复
3.值不可以重复
常用方法:
clear()
containsKey(Object key)
containsValue(Object value)
entrySet()【遍历时使用】【常用】
equals(Object o)
get(Object key)获取元素
hashCode()
isEmpty()
keySet()【遍历时使用】
put(K key, V value)添加元素,添加时,如果键重复,则后添加的值覆盖原先添加的值
putAll(Map<? extends K,? extends V> m)
remove(Object key)删除元素
size()
HashMap【常用】
存储方式:
以键值对的形式存储,键可以重复,值不能重复
允许存储null键,null值
排除重复:
根据自己的需求,重写存储对象的hashCode()和equals()方法
线程是否安全:
线程不安全
构造方法:
如果调用无参构造,那么默认长度是16
如果调用有参构造,初始化的长度,先看传入的参数是不是2的次方数
如果是,传入参数就是初始容量
如果不是,找到一个比传入的参数大的且是2的次方数的一个最小的数,即初始容量
添加方法(存储方法):
概述:根据hash值和HashSet的长度进行&(与运算,结果0 ~ HashSet的长度 - 1),得到存储位置
如果相同,则不存
如果不同,插入到存储位置的最后一个节点后面(尾插入),再判断是否满足转化为红黑树的条件
如果容量 >= 64并且链表长度 >= 8,转换为红黑树
如果不满足容量 >= 64并且链表长度 >= 8,则扩容
//计算hash值
static final int hash(Object key) {
int h; //四字节 32位
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
//h >>> 16 取出高16位 目的:散列更均匀
}
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)
//tab = 16 resize扩容
n = (tab = resize()).length; //n = 16
//计算位置 15 & hash 取hash的后四位进行与运算,结果0~15,
//如果扩容,容量变为32, 31的二进制11111,取后五位,在根据hash值计算新的位置,调整存储位置
if ((p = tab[i = (n - 1) & hash]) == null)
//第一次直接放进去 单向链表,只有next
//Node(int hash, K key, V value, Node<K,V> next) {
// this.hash = hash;
// this.key = key;
// this.value = value;
// this.next = next;
//}
tab[i] = newNode(hash, key, value, null);
else {
//计算hash值做完运算后,存储位置相同的元素,执行的代码
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);
//TREEIFY_THRESHOLD 8
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
//调整为红黑树,
//牵涉到扩容方法,如果容量>64,链表长度>8,调整为红黑树,否则扩容
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;
}
LinkedHashMap
特点:
有序,键不可重复,值可重复
存储结构:
哈希表 + 双重链接链表
HashTable
存储结构:
哈希表
但是不能存储null键,null值
线程是否安全:
线程安全
TreeMap
排序:
1.默认使用的是自然顺序
自然数,字母表的顺序
2.如果存储的是对象,需要自定义排序规则
1.创建对象时,让存储的对象遵从Comparable接口,重写compareTo方法
排重:
根据需要重写hashCode()和equals()方法
遍历
1.keySet方法与get方法结合
2.Map.Entry
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int compareTo(Student o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.getAge() - o.getAge();
return n1 == 0 ? n1 : n2;
}
}
HashMap<Student, String> hashMap = new HashMap<>();
Student student1 = new Student("张无忌", 27);
Student student2 = new Student("白眉鹰王", 65);
Student student3 = new Student("紫衫龙王", 44);
Student student4 = new Student("青翼蝠王", 50);
Student student5 = new Student("青翼蝠王", 50);
//Student student5 = new Student("金毛狮王", 57);
hashMap.put(student1, "北京");
hashMap.put(student2, "南京");
hashMap.put(student3, "东京");
hashMap.put(student4, "西京");
hashMap.put(student5, "花里胡哨京");
hashMap.remove(new Student("张无忌", 27));
//1.keySet方法与get方法结合
for (Student student : hashMap.keySet()) {
System.out.println(student + " = " + hashMap.get(student));
}
//Map.Entry
for (Map.Entry<Student, String> studentStringEntry : hashMap.entrySet()) {
System.out.println(studentStringEntry);
}