• Java Map的正确使用方式


    原文:https://www.liaoxuefeng.com/article/1256136507802816

    正确使用Map,只需要正确实现hashCode()equals()就行了吗?

    恐怕还不行。

    确切地说,如果使用的是HashMap,那么只需要正确实现hashCode()equals()就够了。

    但是,如果换成TreeMap,正确实现hashCode()equals(),结果并不一定正确。

    代码胜于雄辩。先看作为key的class定义:

    class Student implements Comparable<Student> {
        final String name;
        final int score;
    
        public Student(String name, int score) {
            this.name = name;
            this.score = score;
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, score);
        }
    
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Student) {
                Student o = (Student) obj;
                return Objects.equals(this.name, o.name) && this.score == o.score;
            }
            return false;
        }
    
        @Override
        public int compareTo(Student o) {
            return this.score < o.score ? -1 : 1;
        }
    }
    

    先用HashMap测试:

    Map<Student, Integer> map = new HashMap<>();
    map.put(new Student("Michael", 99), 99);
    map.put(new Student("Bob", 88), 88);
    map.put(new Student("Alice", 77), 77);
    System.out.println(map.get(new Student("Michael", 99)));
    System.out.println(map.get(new Student("Bob", 88)));
    System.out.println(map.get(new Student("Alice", 77)));
    

    输出为998877,一切正常。

    HashMap改为TreeMap再测试:

    Map<Student, Integer> map = new TreeMap<>();
    

    输出为nullnullnull

    怎么肥四?

    说好的接口不变,实现类随便换现在不管用了?难道是JDK的bug?

    遇到这种诡异的问题,首先在心里默念三遍:

    • JDK没有bug。
    • JDK没有bug。
    • JDK没有bug。

    然后开始从自己的代码找原因。

    先打开JDK的TreeMap文档,注意到这句话:

    This is so because the Map interface is defined in terms of the equals operation, but a sorted map performs all key comparisons using its compareTo (or compare) method

    意思是,Map接口定义了使用equals()判定key是否相等,但是SortedMap却使用compareTo()来判断key是否相等,而TreeMap是一种SortedMap

    所以,问题出在compareTo()方法上:

    @Override
    public int compareTo(Student o) {
        return this.score < o.score ? -1 : 1;
    }
    

    上面这个定义,用来排序是没问题的,但是,没法判断相等。TreeMap根据key.compareTo(anther)==0判断是否相等,而不是equals()

    所以,解决问题的关键是正确实现compareTo(),该相等的时候,必须返回0

    @Override
    public int compareTo(Student o) {
        int n = Integer.compare(this.score, o.score);
        return n != 0 ? n : this.name.compareTo(o.name);
    }
    

    修正代码后,再次运行,一切正常。

  • 相关阅读:
    c语言寒假大作战02
    C语言寒假大作战01
    C语言I作业12
    C语言I博客作业11
    C语言I博客作业10
    C语言ll作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
  • 原文地址:https://www.cnblogs.com/shihaiming/p/11395173.html
Copyright © 2020-2023  润新知