java怎么使用_Java Map的正确使用方式

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

恐怕还不行。

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

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

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

class Student implements Comparable {

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 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)));

输出为99、88、77,一切正常。

把HashMap改为TreeMap再测试:

Map map = new TreeMap<>();

输出为null、null、null!

怎么肥四?

说好的接口不变,实现类随便换现在不管用了?难道是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);

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值