基于哈希表实现的Map接口
JDK1.2,线程不安全,运行效率高
允许null作为key或value
创建一个Person类
public class Person { private String name; private int age; public Person(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 "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
HashMap的使用
import java.util.HashMap; import java.util.Map; /** * HashMap * 存储结构:哈希表(数组+链表+红黑树) * hashcode和equals为判断重复的依据 */ public class Demo02 { public static void main(String[] args) { //创建集合 HashMap<Person, String> persons = new HashMap<>(); //添加 Person p1 = new Person("小王",20); Person p2 = new Person("小张",21); Person p3 = new Person("小李",22); persons.put(p1,"老师"); persons.put(p2,"老板"); persons.put(p3,"工程师"); System.out.println("元素个数:" + persons.size()); System.out.println(persons.toString()); //删除 persons.remove(p1); System.out.println("元素个数:" + persons.size()); //遍历 System.out.println("----增强for----"); for (Person key: persons.keySet()) { System.out.println(key.toString() + ":" + persons.get(key)); } System.out.println("----entrySet()----"); for (Map.Entry<Person, String> entry: persons.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } //判断 System.out.println(persons.containsKey(p1)); System.out.println(persons.containsKey(new Person("小李",22))); //没有重写HashCode和equals方法时返回false System.out.println(persons.isEmpty()); }
源码分析
public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted }
无参构造
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
put方法
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
默认初始容量16
static final int MAXIMUM_CAPACITY = 1 << 30;
最大容量大小2的30次方
static final float DEFAULT_LOAD_FACTOR = 0.75f;
默认加载因子,若元素个数大于75%则扩容
static final int TREEIFY_THRESHOLD = 8;
链表长度大于8,数组长度大于等于64,链表会调整为红黑树(JDK1.8)
static final int UNTREEIFY_THRESHOLD = 6;
链表长度小于6,则红黑树调整回链表(JDK1.8)
static final int MIN_TREEIFY_CAPACITY = 64;
最小容量大小64(JDK1.8)
transient Node<K,V>[] table;
创建hashmap后,保存的哈希表(数组+链表),创建hashmap后没有添加元素为null,添加第一个元素后容量大小为16
if (++size > threshold) resize();
添加第一个元素后,容量大小为16,继续添加,当元素个数大于16*0.75=12时,继续扩容
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
每次扩容变为原来的2倍(newCap = oldCap << 1)
transient int size;
元素个数,创建hashmap后没有添加元素为0
小结:
1.HashMap刚创建时,table是null,出于节省空间,添加第一个元素时,table容量16
2.添加第一个元素后,继续添加,当元素个数大于阈值(16*0.75=12)时,进行扩容,每次扩容,容量变为原来的2倍,以减少调整元素的个数
3.当链表长度大于8,且数组长度大于等于64时,会调整为红黑树,以提高执行效率
4.当链表长度小于6时,调整为链表
5.JDK1.8前,链表是头插入(后来者替换),JDK1.8后为尾插入(后来者尾随)
Hashtable
JDK1.0,线程安全,运行效率低,不允许null作为key或value
Properties
Hashtable的子类,key和value都是String,通常用于配置文件的读取
实现了SortedMap接口(Map的子接口),可以对key自动排序
import java.util.Comparator; import java.util.Map; import java.util.TreeMap; /** * TreeMap * 存储结构:红黑树 */ public class Demo03 { public static void main(String[] args) { //创建集合 TreeMap<Person, String> treeMap = new TreeMap<>(new Comparator<Person>() { //比较器 @Override public int compare(Person o1, Person o2) { int n1 = o1.getAge() - o2.getAge(); int n2 = o1.getName().compareTo(o2.getName()); return n1==0?n2:n1; } }); //添加 Person p1 = new Person("小王",20); Person p2 = new Person("小张",21); Person p3 = new Person("小李",22); treeMap.put(p1,"老师"); treeMap.put(p2,"老板"); treeMap.put(p3,"工程师"); //treeMap.put(new Person("小李",22),"厨师"); //以name和age System.out.println("元素个数:" + treeMap.size()); System.out.println(treeMap.toString()); //删除 treeMap.remove(p1); //treeMap.remove(new Person("小李",22)); System.out.println(treeMap.size()); //遍历 System.out.println("----keySet()----"); for (Person key: treeMap.keySet()) { System.out.println(key + ":" + treeMap.get(key)); } System.out.println("----entrySet()----"); for (Map.Entry<Person, String> entry: treeMap.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } //判断 System.out.println(treeMap.containsKey(new Person("小张",21))); System.out.println(treeMap.isEmpty()); } }