TreeMap基本使用

1.TreeMap简单介绍

        TreeMap是一个有序的key-value集合,是非线程安全的,基于红黑树(Red-Black tree)实现。其映射根据键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

当自定义比较器时,需要自定义类实现java.lang.Comparable接口,并重写compareTo()方法。

2.TreeMap基本使用

根据键的自然顺序进行排序

public static void main(String[] args) {
    Map map = new TreeMap<>();

    map.put("name", "zzc");
    map.put("age", "18");
    map.put("sex", "m");
    map.put("name", "wzc");
    map.put("angle", "yhp");

    System.out.println(map);
}

如何排序呢?进入到TreeMap中的put(key, value)

cmp = k.compareTo(t.key);

通过Comparable中的compareTo()方法进行排序的。

这里的key是String类型的,String类实现了Comparable接口并且重写了compareTo()方法:

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;

    int k = 0;
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        if (c1 != c2) {
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

字符串比较大小就是通过比较字符串中的字符大小,这样就可以实现排序。

【注意】:如果TreeMap中存储的元素是自定义类并且没有实现Comparable接口会怎么样?下面就尝试一下:
自定义一个User类:

public class User {
    private Integer age;
    private String name;
    private String email;
    
    public User(Integer age, String name, String email) {
        this.age = age;
        this.name = name;
        this.email = email;
    }
}

测试类:

public class Test {

    public static void main(String[] args) {
        Map map = new TreeMap<>();

        User u1 = new User(19, "zzc", "[email protected]");
        User u2 = new User(15, "wac", "[email protected]");
        User u3 = new User(20, "zhangy", "[email protected]");
        map.put(u1, "1");
        map.put(u2, "2");
        map.put(u3, "3");

        System.out.println(map);
    }
}

测试结果:
在这里插入图片描述
抛出异常:java.lang.ClassCastException: com.zzc.test.User cannot be cast to java.lang.Comparable。
【注意】:这里的key是User对象
很显然,这里User类因未实现Comparable接口,因而无法比较对象大小,所以抛出运行时异常。

接下来使User类实现Comparable接口并重写compareTo()方法:
        这里我以age属性进行排序(当然,你也可以使用其他属性进行排序,比较大小逻辑直接写在compare()方法中即可)

扫描二维码关注公众号,回复: 9671256 查看本文章
public class User implements Comparable<User>{
	...

	@Override
    public int compareTo(User user) {
        return compare(this.age, user.getAge());
    }

    public static int compare(Integer age1, Integer age2) {
        return (age1 > age2 ? 1 : (age1 == age2) ? 0 : -1 );
    }
}

测试类Test:

public class Test {

    public static void main(String[] args) {
        Map map = new TreeMap<>();
        
        User u1 = new User(19, "zzc", "[email protected]");
        User u2 = new User(15, "wac", "[email protected]");
        User u3 = new User(20, "zhangy", "[email protected]");
        map.put(u1, "1");
        map.put(u2, "2");
        map.put(u3, "3");

        User key = null;
        Integer value = null;
        Iterator iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            key = (User) iterator.next();
            // 重写User类中的toString()方法
            System.out.println(key);
        }
    }
}

测试结果:
在这里插入图片描述
年龄从小到大排序。

我们再往测试类Test中的map添加一条数据,并且这次也把value打印出来:

User u4 = new User(19, "zzc", "[email protected]");

map.put(u4, "4");

这个u4对象和u1对象是一样的。

Test类:

public class Test {

    public static void main(String[] args) {
        Map map = new TreeMap<>();
        
        User u1 = new User(19, "zzc", "[email protected]");
        User u2 = new User(15, "wac", "[email protected]");
        User u3 = new User(20, "zhangy", "[email protected]");
        User u4 = new User(19, "zzc", "[email protected]");
        map.put(u1, "1");
        map.put(u2, "2");
        map.put(u3, "3");
        map.put(u4, "4");

        User key = null;
        String value = null;
        Iterator iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            key = (User) iterator.next();
            value = (String) map.get(key);
            System.out.println(key + "=====" + value);
        }

        System.out.println(u1.equals(u4));
    }
}

测试结果:
在这里插入图片描述
虽然也是三条数据,但很明显,u4对象把u1对象给覆盖了。也就是说key相同,value就会被覆盖。实际上,确实如此。TreeMap中的put()方法中:

parent = t;
cmp = k.compareTo(t.key);   // cmp == 0
 if (cmp < 0)
     t = t.left;
 else if (cmp > 0)
     t = t.right;
 else
     return t.setValue(value);

key一样,新值会覆盖原值。但是key真的是一样吗?那我们来测试下:
添加一条语句:

System.out.println(u1.equals(u4));

使用equals()方法来判断它们是否相同。

在这里插入图片描述
结果很意外,equals()方法返回false。但上面说对象u1和对象u4一样,但它们确实也一样啊,为何会返回false呢????

【注意】:那是因为User类没有重写equals()方法,当然,也要重写hashCode()方法,如果没有重写,那调用的就是父类Object类的equals()
Object中的equals()方法:

public boolean equals(Object obj) {
    return (this == obj);
}

是用来判断两个对象的内存地址是否一样。对象u1和u4都是new出来的,内存地址肯定不一样啊,所以equals()方法返回false

所以,应该要在User类中重写hashCode()和equals()方法。

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());

    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (null == obj) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }

    User u = (User) obj;
    if (this.getAge() != u.getAge()) {
        return false;
    }
    if (null == this.getName()) {
        if (u.getName() != null) {
            return false;
        }
    } else if (!this.getName().equals(u.getName())) {
        return false;
    }
    return true;
}

再次进行测试:
在这里插入图片描述
这样逻辑就说的通了。

使用自定义比较器进行排序

public class TmTest {

    public static void main(String[] args) {
        TreeMap<String, Integer> map = new TreeMap<>(new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });

        map.put("age", 23);
        map.put("lvo", 18);
        map.put("nou", 99);
        map.put("cao", 99);

        String key = null;
        Integer value = null;
        Iterator iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            key = (String) iterator.next();
            value = (Integer) map.get(key);
            System.out.println(key + "=====" + value);
        }
    }
}
发布了78 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Lucky_Boy_Luck/article/details/104483258