Java中Map集合键(key)存放自定义数据类型出现的问题以及解决方案
Java中Map集合键(key)存放自定义数据类型出现的问题以及解决方案
问题阐述:
? 今日遇到一位Java学者,在学习 Map 集合通过键的值(key)取出相应的 值 时出现了 null 的问题,通常情况下使用 Map 集合时,我们将会使用 String 类型作为键的类型(为什么,我不多说,就是好用),但是这位学者把自己定义的引用数据类型(User)作为了 Map 的键的数据类型(key)进行了存放,在取出时遇到了问题。代码和运行结果如下:
自定义实体类
public class User implements Comparable {
private String name;
private int age;
// 无参、有参构造、set()、get()、toString()、equals()、hashCode() 方法省略
@Override
public int compareTo(User o) {
// compareTo 在比较关系下 存在 正大 负小 0相等 的逻辑应用 只是应用于 equals()比较时使用
// 比较地址是否相等
if (this == o) {
return 0;
}
// 比较信息是否相等
if (this.getName().equals(o.getName()) && this.getAge() == o.getAge()) {
// 相等的情况下返回 0
return 0;
} else {
// 信息不完全相等时 返回 非 0 的信息
return 1;
}
// return 0;
}
}
compareTo 在比较关系逻辑下 存在 正大 负小 0相等 的逻辑应用 只是应用于 equals()比较时使用
Map测试类
public static void main(String[] args) {
// 准备 map 集合容器 键的类型为 User 自定义类型 值 为字符串类型
Map map = new TreeMap<>();
// 准备四个自定义对象
User user = new User("孙悟空", 22);
User user2 = new User("唐三藏", 33);
User user3 = new User("猪八戒", 11);
// 制造重复信息的对象
User user4 = new User("孙悟空", 22);
// 存放到 Map 集合中
map.put(user, "孙悟空");
map.put(user4, "孙悟空");
map.put(user2, "唐三藏");
map.put(user3, "猪八戒");
// for循环打印信息
for (User u : users) {
// 首先打印 u 的信息 自动调用 User 的 toString() 方法
// 然后打印 map.get(u) 通过键值来获取 值的信息
System.out.println(u + "-----" + map.get(u));
}
}
运行结果
User{name='孙悟空', age=22}-----null
User{name='唐三藏', age=33}-----唐三藏
User{name='猪八戒', age=11}-----猪八戒
分析一波
? 通常我们在使用 Map 集合时,存放数据时,键的数据类型我们一般定义为 String 类型,根据 Map 集合的特性:键的值是唯一性,存在键重复时,后者的数据覆盖前者的数据,实例代码和运行结果如下:
public static void main(String[] args) {
Map map = new TreeMap<>();
User user = new User("孙悟空", 22);
User user2 = new User("唐三藏", 33);
User user3 = new User("猪八戒", 11);
User user4 = new User("孙悟空", 222222);
map.put("孙悟空", user);
map.put("孙悟空", user4);
map.put("唐三藏", user2);
map.put("猪八戒", user3);
Set keySet = map.keySet();
for (String s : keySet) System.out.println("键:" + s + "-----" + map.get(s));
}
键:唐三藏-----User{name='唐三藏', age=33}
键:孙悟空-----User{name='孙悟空', age=222222}
键:猪八戒-----User{name='猪八戒', age=11}
并不会取值的时候出现 null 值
阅读 String 的源码 String 中 compareTo() 重写的源码
? 源码中使用两者的字符串长度做减法获取正负数或者0(相等),Map在存储数据时,根据键的比较,当等于 0 时,判断为同一个键,则会后者覆盖前者,回忆学者的 compareTo() 的方法时 返回的结果只有 0 和 正数,进行代码修改。
@Override
public int compareTo(User o) {
// return this.getName().compareTo(o.getName()); // 使用 String 类中已经重写好的 compareTo
return this.getName().hashCode() - o.getName().hashCode();
}
User{name='唐三藏', age=33}-----唐三藏
User{name='孙悟空', age=22}-----孙悟空
User{name='猪八戒', age=11}-----猪八戒
问题解决
问题整体分析
- 在使用 Map 的键(key)存放自定义数据类型时,必须实现 Comparable 接口,以及重写 compareTo() 方法。
- Map 在 put 数据时,首先判断新存放的 键 是否存在,调用 键 所属的数据类型中的 compareTo() 方法比较,当我们自定义数据类型中 compareTo() 方法比较不清晰时,则会出现 Map 存放数据不正确的情况。
备注:初学者竟可能的规范开发,个性化开发遇到问题不要怕,前应后果找一找,想想规范开发下能跑通代码,自己的个性化开发为什么跑不通,阅读源码,查阅资料,锻炼自己,哈哈哈。