Java集合框架04:Map集合
Map体系结构
Map父接口
存储一对数据(Key-Value),无序、无下标、键不可重复
put()、keySet()、get()、entrySet()、getKey()、getValue()、remove()
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()方法获得键值对(它是Map.Entry类型的对象)
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry);
//getKey()和getValue()方法单独获取键和值
System.out.println(entry.getKey() + " " + entry.getValue());
}
//containsKey()和containsValue()方法判断是否存在键和值
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("韩国"));
System.out.println(map.size());
//remove()方法根据键删除元素
map.remove("usa");
System.out.println(map);
}
}
HashMap实现类
运行效率快,线程不安全;允许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);
}
}
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右键,可以自动重写equals()和hashCode()方法
@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<>();}
TreeMap实现类
实现了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");
//重写了compareTo()方法,只要键相同就算重复。后面传入的值会覆盖原先的值
map.put(new Test("xm", 20), "Eu");
System.out.println(map.toString());
}
}
//有多个属性的类的对象作为元素时不能自动排序,可通过自然排序和比较器排序方法来自定义顺序,和TreeSet类似
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