Map集合接口具體實作類:LinkedHashMap以及TreeMap
- 1.LinkedHashMap的概述
- 2.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則重點掌握排序的兩種方式:自然排序與比較器排序。