存储一对数据(Key-Value),无序、无下标、键不可重复
import java.util.HashMap; import java.util.Map; public class Hello{ public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); //put()方法添加键值对 map.put("cn", "中国"); map.put("usa", "美国"); map.put("uk", "英国"); System.out.println(map); //两种遍历集合的方式 //1.keySet()方法获得键 for (String key : map.keySet()){ //get()方法根据键获取值 System.out.println(key + " " + map.get(key)); } //2.entrySet()方法获得键值对 for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println(entry); //getKey()和getValue()方法单独获取键和值 System.out.println(entry.getKey() + " " + entry.getValue()); } System.out.println(map.containsKey("cn")); System.out.println(map.containsValue("韩国")); //remove()方法删除键值对 map.remove("usa"); System.out.println(map); } }
运行效率快,线程不安全;允许null作为键或值
存储结构:哈希表(数组+链表或数组+红黑树)
import java.util.HashMap; public class Hello{ public static void main(String[] args) { HashMap<Test, String> map = new HashMap<>(); Test a = new Test("xm", 20); Test b = new Test("xh", 21); Test c = new Test("xw", 22); map.put(a, "Asia"); map.put(b, "Eu"); map.put(c, "India"); //重写hashCode()和equals()方法以后,只要属性相同,就算重复 map.put(new Test("xm", 20), "Asia"); System.out.println(map.toString()); } } class Test{ String name; int age; public Test(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + "/" + age; } //IDEA右键,可以自动生成只判断属性的重写方法 @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Test)) return false; Test test = (Test) o; if (age != test.age) return false; return name != null ? name.equals(test.name) : test.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; } }
拓展:HashMap源码分析
//如果没有添加任何元素,容量为0;添加一个元素之后,数组长度变成16 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //当链表的长度大于8,且数组长度大于64时,链表转换为红黑树存储 static final int TREEIFY_THRESHOLD = 8; static final int MIN_TREEIFY_CAPACITY = 64; final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } //每次扩容,容量增大2倍 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold }
拓展:HashMap和HashSet的联系
//从源码看,HashSet调用的就是HashMap public HashSet() {map = new HashMap<>();}
实现了SortedMap接口,可以对键自动排序
存储结构:红黑树
import java.util.TreeMap; public class Hello{ public static void main(String[] args) { TreeMap<Test, String> map = new TreeMap<>(); Test a = new Test("xm", 20); Test b = new Test("xh", 21); Test c = new Test("xw", 22); map.put(a, "Asia"); map.put(b, "Eu"); map.put(c, "India"); //重写hashCode()和equals()方法以后,只要键相同,就算重复;后面传入的值会覆盖原先的值 map.put(new Test("xm", 20), "Eu"); System.out.println(map.toString()); } } //自定义类,不能自动排序,可以实现Comparab接口和重写compareTo()方法来自定义顺序 class Test implements Comparable<Test>{ String name; int age; public Test(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + "/" + age; } @Override public int compareTo(Test o) { int n1 = this.name.compareTo(o.name); int n2 = this.age - o.age; return n1 == 0 ? n2 : n1; } }
拓展:TreeMap和TreeSet的联系
TreeSet调用的就是TreeMap