What does comparison being consistent with equals mean ? What can possibly happen if my class doesn't follow this principle?

后端 未结 4 1364
臣服心动
臣服心动 2020-11-30 04:24

From the JavaDoc of TreeMap :

Note that the ordering maintained by a sorted map (whether or not an explicit comparator is provided) must be consiste

4条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-11-30 04:45

    Say we have this simple Student class implementing Comparable but not overriding equals()/hashCode(). Of course equals() is not consistent with compareTo() - two different students with the same age aren't equal:

    class Student implements Comparable {
    
        private final int age;
    
        Student(int age) {
            this.age = age;
        }
    
        @Override
        public int compareTo(Student o) {
            return this.age - o.age;
        }
    
        @Override
        public String toString() {
            return "Student(" + age + ")";
        }
    }
    

    We can safely use it in TreeMap:

    Map students = new TreeMap();
    students.put(new Student(25), "twenty five");
    students.put(new Student(22), "twenty two");
    students.put(new Student(26), "twenty six");
    for (Map.Entry entry : students.entrySet()) {
        System.out.println(entry);
    }
    System.out.println(students.get(new Student(22)));
    

    The results are easy to predict: students are nicely sorted according to their age (despite being inserted in different order) and fetching student using new Student(22) key works as well and returns "twenty two". This means we can safely use Student class in TreeMap.

    However change students to HashMap and things go bad:

    Map students = new HashMap();
    

    Obviously the enumeration of items returns "random" order due to hashing - that's fine, it doesn't violate any Map contract. But the last statement is completely broken. Because HashMap uses equals()/hashCode() to compare instances, fetching value by new Student(22) key fails and returns null!

    This is what the JavaDoc tries to explain: such classes will work with TreeMap but might fail to work with other Map implementations. Note that Map operations are documented and defined in terms of equals()/hashCode(), e.g. containsKey():

    [...] returns true if and only if this map contains a mapping for a key k such that (key==null ? k==null : key.equals(k))

    Thus I don't believe there are any standard JDK classes that implemente Comparable but fail to implement equals()/hashCode() pair.

提交回复
热议问题