快来,我悄悄的给你说几个HashCode的破事。 (4)

简介: 快来,我悄悄的给你说几个HashCode的破事。 (4)

实体类当做 key


上面的示例中,我们用的是 String 类型当做 HashMap 中的 key。


这个场景能覆盖我们开发场景中的百分之 95 了。


但是偶尔会有那么几次,可能会把实体类当做 key 放到 HashMap 中去。


注意啊,面试题又来了:在 HashMap 中可以用实体类当对象吗?


那必须的是可以的啊。但是有坑,注意别踩进去了。


我拿前段时间看到的一个新闻给大家举个例子吧:


image.png


假设我要收集学生的家庭信息,用 HashMap 存起来。


那么我的 key 是学生对象, value 是学生家庭信息对象。


他们分别是这样的:


public class HomeInfo {
    private String homeAddr;
    private String carName;
     //省略改造方法和toString方法
}
public class Student {
    private String name;
    private Integer age;
     //省略改造方法和toString方法
}


然后我们的测试用例如下:


public class HashMapTest {
    private static Map<Student, HomeInfo> hashMap = new HashMap<Student, HomeInfo>();
    static {
        Student student = new Student("why", 7);
        HomeInfo homeInfo = new HomeInfo("大南街", "自行车");
        hashMap.put(student, homeInfo);
    }
    public static void main(String[] args) {
        updateInfo("why", 7, "滨江路", "摩托");
        for (Map.Entry<Student, HomeInfo> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey()+"-"+entry.getValue());
        }
    }
    private static void updateInfo(String name, Integer age, String homeAddr, String carName) {
        Student student = new Student(name, age);
        HomeInfo homeInfo = hashMap.get(student);
        if (homeInfo == null) {
            hashMap.put(student, new HomeInfo(homeAddr, carName));
        }
    }
}


初始状态下,HashMap 中已经有一个名叫 why 的 7 岁小朋友了,他家住大南街,家里的交通工具是自行车。


然后,有一天他告诉老师,他搬家了,搬到了滨江路去,而且家里的自行车换成了摩托车。


于是老师就通过页面,修改了 why 小朋友的家庭信息。


最后调用到了 updateInfo 方法。


嘿,你猜怎么着?


我带你看一下输出:


image.png


更新完了之后,他们班上出现了两个叫 why 的 7 岁小朋友了,一个住在大南街,一个住在滨江路。


更新变新增了,你说神奇不神奇?


现象出来了,那么根据现象定位问题代码不是手到擒来的事儿?


很明显,问题就出在这个地方:


image.png


这里取出来的 homeInfo 为空了,所以才会新放一个数据进去。


那么我们看看为啥这里为空。


跟着 hashMap.get() 源码进去瞅一眼:


image.png


标号为 ① 的地方是计算 key ,也就是 student 对象的 hashCode。而我们 student 对象并没有重写 hashCode,所以调用的是默认的 hashCode 方法。


这里的 student 是 new 出来的:


image.png


所以,这个 student 的 hashCode 势必和之前在 HashMap 里面的 student 不是一样的。


因此,标号为 ③ 的地方,经过 hash 计算后得出的 tab 数组下标,对应的位置为 null。不会进入 if 判断,这里返回为 null。


那么解决方案也就呼之欲出了:重写对象的 hashCode 方法即可。


是吗?


等等,你回来,别拿着半截就跑。我话还没说完呢。


接着看源码:


image.png

目录
相关文章
|
4天前
|
JavaScript 前端开发 Java
万万没想到,'this'关键字的真正威力
万万没想到,'this'关键字的真正威力
19 1
|
7月前
|
Cloud Native Go Python
面试前夜:最后准备的小贴士
面试前夜:最后准备的小贴士
31 0
|
10月前
|
缓存 Java 程序员
肝到头秃!百度强推并发编程笔记我爱了,原来这才叫并发
随着Java程序员的大幅增长,人们对Java程序员的要求也是越来越严苛。从现在Java岗的招聘需求来看,并发编程已经是我们Java程序员避不开的坎了! 编写正确的程序并不容易,而编写正确的并发程序就更难了。与顺序执行的程序相比,并发程序中显然更容易出现错误。而且并发性错误通常并不会以某种确定的方式显现出来。
|
安全 Java 编译器
学妹不懂Java泛型,非让我写一篇给她看看(有图为证)
笔者有个学妹就遇到了相同的境遇,学弟被泛型搞得头晕目眩,搞不懂泛型是个啥玩意。天天用的泛型也不知道啥玩意(她可能都不知道她有没有用泛型)。立图为证!当然,笔者深度还欠缺,如果错误还请指正!
112 0
学妹不懂Java泛型,非让我写一篇给她看看(有图为证)
|
存储 算法 Java
难倒无数程序员的ThreadLocal原理,就这样被美团大牛轻松讲透彻
什么是ThreadLocal? ThreadLocal 是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰。 ThreadLocal怎么使用? ThreadLocl使用比较简单,主要有三个方法:get()、set()、remove()
171 0
难倒无数程序员的ThreadLocal原理,就这样被美团大牛轻松讲透彻
|
Java 测试技术
快来,我悄悄的给你说几个HashCode的破事。 (3)
快来,我悄悄的给你说几个HashCode的破事。 (3)
72 0
快来,我悄悄的给你说几个HashCode的破事。 (3)
|
算法 Java
快来,我悄悄的给你说几个HashCode的破事。 (1)
快来,我悄悄的给你说几个HashCode的破事。 (1)
102 0
快来,我悄悄的给你说几个HashCode的破事。 (1)
|
Java
快来,我悄悄的给你说几个HashCode的破事。 (5)
快来,我悄悄的给你说几个HashCode的破事。 (5)
89 0
快来,我悄悄的给你说几个HashCode的破事。 (5)
|
安全 Java
快来,我悄悄的给你说几个HashCode的破事。 (2)
快来,我悄悄的给你说几个HashCode的破事。 (2)
123 1
快来,我悄悄的给你说几个HashCode的破事。 (2)
|
存储 缓存 前端开发
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶