Map集合接口具体实现类:LinkedHashMap以及TreeMap
前面我们学习了Map接口中最常用的实现类:HashMap,并且对HashMap的底层实现原理做了一定的深入探讨。下面我们将要了解的是Map接口中的另外两大实现类:LinkedHashMap与TreeMap。
1.LinkedHashMap的概述
LinkedHashMap实现了Map接口,而且继承自HashMap。
它的多种操作都是建立在HashMap的操作基础上的。
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
同HashMap不同的是,LinkedHashMap维护了一个Entry的双向链表,保证了插入Entry中的顺序。
如上图所示,加入顺序为key1,key2,key3,key4,就会维护上面红线所示的双向链表。
- 为实现双向链表,LinkedHashMap底层源码这样进行设置:
//LinkedHashMap中的node直接继承自HashMap中的Node。并且增加了双向的指针
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
由上面源码中设置可知,LinkedHashMap 键的数据结构是 链表和哈希表,链表保证了键有序,哈希表保证了键唯一。
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class MyTest {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<>();
//LinkedHashMap 键的数据结构是 链表和哈希表,链表保证了键有序,哈希表保证了键唯一
map.put("s001", "张三");
map.put("s001", "张三丰");
map.put("s002", "李四");
map.put("s003", "王五");
map.put("s004", "陈六");
//遍历LinkedHashMap方式一
Set<String> keySet = map.keySet();
for (String key : keySet) {
String value = map.get(key);
System.out.println(key+"======="+value);
}
System.out.println("============");
//遍历LinkedHashMap方式二
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"==="+value);
}
System.out.println("=============");
//遍历LinkedHashMap方式三
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key+"===="+value);
}
});
}
}
LinkedHashMap相对于HashMap而言,它继承了HashMap,仅仅重写了几个方法,以改变它迭代遍历时的顺序。
2.TreeMap概述
TreeMap的数据结构为红黑树,可以保证键的排序性和唯一性。排序分为自然排序与比较器排序。TreeMap线程不安全,并且效率比较高。
案例演示:TreeMap集合键是Integer,值是String类型
public class MyTest2 {
public static void main(String[] args) {
TreeMap<Integer, String> treemap = new TreeMap<>();
treemap.put(15,"张三");
treemap.put(10,"李四");
treemap.put(13,"王五");
treemap.put(14,"陈六");
treemap.put(11,"刘七");
treemap.put(12,"赵八");
System.out.println(treemap);
}
}
TreeMap是双列集合,双列集合的键需要保持唯一,在此例中Intege类中源码实现Compareable接口,重写了CompareTo()方法。
运行后的结果为:
案例演示2:TreeMap集合键是Student,值是String类型的案例,按照Student类中的属性年龄的大小进行排序。
- 方式一:自然排序
//自定义类:Student类
//自然排序,实现Compareable接口,重写CompareTo方法
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 stu) {
//比较年龄大小
int num = age-stu.age;
//如果年龄相同,比较姓名内容是否相同
int num1=num==0?name.compareTo(stu.name):num;
return num1;
}
}
//测试类
import java.util.TreeMap;
public class MyTest3 {
public static void main(String[] args) {
TreeMap<Student, String> treemap = new TreeMap<>();
treemap.put(new Student("张三",23),"s001");
treemap.put(new Student("李四",24),"s002");
treemap.put(new Student("王五",25),"s003");
treemap.put(new Student("陈六",23),"s004");
System.out.println(treemap);
}
}
运行后的结果为:
- 方案二:比较器排序
//自定义的Student类
public class 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 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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.util.Comparator;
import java.util.TreeMap;
public class MyTest {
public static void main(String[] args) {
TreeMap<Student, String> treemap = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//比较年龄大小
int num = s1.getAge() - s2.getAge();
//当年龄相同时,比较姓名内容是否相等
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return num2;
}
});
treemap.put(new Student("张三",23),"s001");
treemap.put(new Student("李四",24),"s002");
treemap.put(new Student("王五",25),"s003");
treemap.put(new Student("陈六",23),"s004");
System.out.println(treemap);
}
}
运行后的结果为:
总结
本节主要介绍了LinkedHashMap以及TreeMap的使用,其中需要了解LinkedHashMap与HashMap的区别:LinkedHashMap相对于HashMap而言,它继承了HashMap,仅仅重写了几个方法,以改变它迭代遍历时的顺序。TreeMap则重点掌握排序的两种方式:自然排序与比较器排序。