Map接口有两个实现类,一个是HashMap容器类,另一个是TreeMap容器类。TreeMap容器类的使用在API上于HashMap容器类没有太大的区别。它们的区别主要体现在两个方面,一个是底层实现方式上,HashMap是基于Hash算法来实现的吗,而TreeMap是基于红黑树来实现的;另一个区别体现在功能上,虽然HashMap容器类的效率比较高,但是它无法实现排序操作。相对的,TreeMap虽然在效率上比不上HashMap,但是它能够实现对双例集合中元素的key进行排序操作。值得注意的是,TreeMap只支持对双例集合中的键key进行排序操作,这个也好理解,因为双例集合中的key与value是一一对应的关系,对key进行排序就相当于也对value进行了排序。
由于TreeMap容器类和HashMap容器类在使用上没有多大的区别,因此我们只要掌握好TreeMap中的排序操作再与HashMap容器类进行对比学习就可以很好地掌握TreeMap容器类了。
TreeMap容器类对键key的排序操作和之前我们介绍的TreeSet容器类对元素的排序操作是相似的。在使用它们的时候都需要给定排序规则,而对于排序规则它们二者都有两种给定排序规则的方式,一种是通过元素自身来实现比较规则,这种方式就是按照元素内定义的规则来实现排序;另一种是通过编程者自定义的比较器来实现比较规则。接下来对TreeMap中的这两种方式进行一一介绍。
首先介绍通过元素自身来实现比较规则的方式。这种方式是按照元素内定义的规则来实现排序的。这里我们用一个例子来进行说明,我们TreeMapTest类中实例化了一个TreeMap容器类对象map,在map对象中我们将它的key设置为类User,value的类型仍然为String,其中User类的代码如下所示。可以发现在User类中我们重写了compareTo方法,这个方法中定义比较规则——按照对象的userAge这个变量的大小进行排序。这时我们在TreeMapTest类中实例化User对象u1,u2和u3,将几个对象作为key添加容器map中去。接下来我们只要遍历容器map中的元素就能发现,它的结果已经按照User中定义的比较规则进行排序了。此处要注意的是,当遇到比较规则中的变量值是相同的情况,则系统会取另一个变量来按照这个新的变量的默认排序规则进行排序。比如在演示代码中我们的对象u2和u3的userAge这个变量的值都是20,那么这个是就会取userName这个变量来进行排序。比较结果为u3在u2的前面,因为按照系统默认的比较规则,字母g在字母l的前面。
package com.container.demo;
import java.util.Objects;
public class User implements Comparable<User>{
private String usersName;
private int usersAge;
public String getUsersName() {
return usersName;
}
public void setUsersName(String usersName) {
this.usersName = usersName;
}
public int getUsersAge() {
return usersAge;
}
public void setUsersAge(int usersAge) {
this.usersAge = usersAge;
}
@Override
public String toString() {
return "User{" +
"usersName='" + usersName + '\'' +
", usersAge=" + usersAge +
'}';
}
public User(String usersName, int usersAge) {
this.usersName = usersName;
this.usersAge = usersAge;
}
public User() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return usersAge == user.usersAge && Objects.equals(usersName, user.usersName);
}
@Override
public int hashCode() {
return Objects.hash(usersName, usersAge);
}
//定义比较规则
//正数:大,负数:小,0:相等
@Override
public int compareTo(User o) {
if(this.usersAge > o.usersAge)
return 1;
if(this.usersAge == o.usersAge){
return this.usersName.compareTo(o.getUsersName());
}
return -1;
}
}
接下来介绍使用自定义的比较器来实现排序的方法。这里我们仍然以一个例子来进行说明。首先在TreeMapTest类中实例化一个TreeMap容器类对象map1。我们把类Student类作为容器map1中key的类型,Sudent类的代码如下所示。将Student类和上面个的User类进行比较能够发现,在Student类中并没有重写compareTo方法,因此这个类中并没有实现排序规则。和上面一样我们也实例化了3个Student对象,将其添加到容器map1中,这时因为我们没有定义比较器,Student类中也没有实现比较规则,所以如果我们运行程序,那么程序就会在运行时报错提醒我们没有定义key的排序规则。如下图所示:
所以我们需要定义一个比较器,并将它使用到容器map1中。这里我们定义比较器StudentComparator,它的实现代码如下所示。原理就是比较器StudentComparator实现了接口Comparator,然后在这个比较器中重写了compare方法。定义比较器之后我们就需要将比较器应用到map1容器中,应用的方法和TreeSet容器类中应用比较器到容器中是一样的。TreeMap容器类的构造方法中提供了一个有参构造,这个参数就是比较器。所以我们只需要在实例化容器的时候将比较器作为参数传入构造方法中就能应用比较器到容器中了。这里要注意传入参数的形式,因为比较器的实质是一个非静态类,因此在另一个类中使用时需要进行实例化操作,为了方便我们只需要在需要传入参数的地方进行new 操作即可,不需要对实例化的对象进行实际接收。
package com.container.demo;
//比较器
import java.util.Comparator;
public class StudentComparator implements Comparator<Student> {
//定义比较规则
@Override
public int compare(Student o1, Student o2) {
if(o1.getAge() >o2.getAge()){
return 1;
}
if(o1.getAge() == o2.getAge()){
return o1.getName().compareTo(o2.getName());
}
return -1;
}
}
import java.util.Objects;
public class Student {
private String name;
private int 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);
}
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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.container.demo;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
//实例化TreeMap容器
Map<User,String> map = new TreeMap<>();
User u1 = new User("linyi",18);
User u2 = new User("linling",20);
User u3 = new User("lingzi",20);
map.put(u1,"liyi");
map.put(u2,"linling");
map.put(u3,"lingzi");
Set<User> keys = map.keySet();
for (User key:keys
) {
System.out.println(key+"---"+map.get(key));
}
System.out.println("___________________________________");
Map<Student,String> map1 = new TreeMap<>(new StudentComparator());
Student s1 = new Student("linyi",18);
Student s2 = new Student("linling",20);
Student s3 = new Student("linger",20);
map1.put(s1,"linyi");
map1.put(s2,"linling");
map1.put(s3,"linger");
Set<Student> keys1 = map1.keySet();
for (Student key:keys1
) {
System.out.println(key+"--------"+map1.get(key));
}
}
}