今天中午正在带着耳机遨游在代码的世界里,被运营在群里@
了,气冲冲的反问我最近有删生产的用户数据的吗?我确定客气的回答道没有呀?生产的数据我怎么能随随便即可以删除,这但是公司的红线,再说了我也没有数据库的删除权限啊,不过查询权限仍是有的。赶忙登上堡垒机,而后去生产数据库查一下数据,查了一下数据是还在的,吓死了,数据还在问题就不大了,无非就是应用程序出问题了,赶忙打开代码查看下,为何会少了一条用户数据,看了下代码貌似没啥问题就是比较简单的一个逻辑,直接从DB
经过分页查询数据给到前端,而后前端负责展现,没有啥复杂的逻辑。心想确定是前端的问题,确定是他少展现了数据,立马把问题也甩给了他,让他帮忙配合一块儿看看是不是前端的问题,而后本身也仔细看看代码,不到一分钟前端说他展现的数据没有问题,都是后端给到的,没有漏掉展现的。那就是后端的bug
了罗。肉眼望去以为可能出问题的就是分页致使的数据丢了。不过这个分页插件是全公司都在用,应该不至于出问题把,找不到问题只能让测试帮忙在测试环境试试,看看是否能够复现。前端
仔细看了一眼,竟然有个去重的方法,去重逻辑也比较简单就是把list
经过转为set去下重,看下来应该就是这个去重方法有问题了
大体写了单元测试模仿了下生产的数据,大体逻辑以下:java
public static void main(String[] args) { Set<UserDTO> userSet = new HashSet<>(); UserDTO userDTO = new UserDTO(); userDTO.setId(1); userDTO.setUserName("java金融"); UserDTO userDTO1 = new UserDTO(); userDTO1.setId(2); userDTO1.setUserName("java金融"); userSet.add(userDTO); userSet.add(userDTO1); System.out.println(userSet.size()); System.out.println(userDTO1.equals(userDTO)); } @Data static class UserDTO extends BaseDTO { private String userName; } @Data static class BaseDTO { private Integer id; }
咱们能够输出结果set
集合的长度是1,user1
和user2
是相等的,明明两个user
的ID
是不同的,为什么会相等,咱们知道set能够去重
是由于Set的操做,都是经过操做map来实现的,set
的add
其实就是调用map
的put
方法,map
的put
方法我相信你们应该都去看过其源码,这里就不详细再说了,大概流程就是经过key经过hash算法定位到数组的下标,先判断key
的hash
是否相等,若是相等再去判断key的value相等,若是都相等就会覆盖原来的值。咱们上面这个例子就是对象的hash
和value
都相等致使,可是咱们的两个对象user1
和user2
应该是不等的,由于ID不等,那为何会相等列?咱们仔细看下上面的代码,咱们使用了lombok
里面@Data
注解,咱们能够看看这个注解帮咱们生成了哪些方法
经过上面的对比咱们能够看出@Data
注解帮咱们生成了 注在类上,提供类的get、set、equals、hashCode、canEqual、toString
方法,这个注解确实比较方便。上面那个bug
就是由于它生成的equals方法有问题,咱们能够把上述代码编译下,而后把class
里面生成的equals
方法拷贝出来看看
面试
经过上述生成的代码咱们能够看出equals
方法只比较了userName
这个字段,也就是当前类的字段,并无去比较父类的字段,这就是致使两个对象相等的缘由,咱们既然找到问题了,那解决问题就比较简单。算法
equals
和hashCode
方法,这种方法确定是不推荐的,咱们既然用了lombok
就是为了解放咱们的双手,是代码变得更加简洁。@EqualsAndHashCode(callSuper = true) callSuper = true
会包含父类的equals
和 hashCode
方法@EqualsAndHashCode(callSuper = true)
和没有加上这个注解生成的equals
方法的代码差别。@EqualsAndHashCode(callSuper = true)
会去调用父类的equals
方法比较,因此这个注解也可以解决这个问题。lombok.config
的配置文件放在咱们项目的根目录下面,内容写上lombok.equalsAndHashCode.callSuper = call
效果等同于@EqualsAndHashCode(callSuper = true)
,这样的话咱们就不须要为每一个类都去加上这个注释了,至关于在这个项目下面只要用到了@Data
注解的类都会为其加上@EqualsAndHashCode(callSuper = true)
经过配置文件的方式就能够全局生效。咱们再来回顾下上面的问题,归根结底仍是因为对象的equals
方法使用不当引发的,因此咱们在若是在判断自定义对象业务判断相等的时候须要去重写下hashCode
和equals
方法,重写的时候咱们能够经过idea
来生成,生成后最好仍是去看一眼,看看生成的是否符合咱们的业务要求。数据库
咱们在工做中操做一些常见的容器类好比Set、Map等来实现一些咱们本身的业务,咱们仍是有必要去看看它们的源码的,就好比咱们经过Set来进行去重,若是咱们是使用的自定义对象的话,若是没有重写hashCode
和equals
方法的话,去重就会去不成功,咱们只有了解了它,才能真正的去用好它。在关于hashCode
和equals
阿里巴巴开发手册也有明确的说到
后端
lombok
用起来仍是挺爽的,可是仍是有一些细节须要稍微注意下。使用前能够大概的去看看它的官网提供的内容,否则出现莫名其妙的问题你都不知道如何下手。这个就有点相似于咱们使用SpringBoot
同样,用起来很是爽,可是若是遇到莫名其妙的bug
解决起来就比较头疼。数组
最后咱们再来回顾几道关于hashCode
和equals
的比较常见的面试题?其实若是咱们只要真正看过HashMap的源码的话,这下面几个面试题仍是很是简单的。
什么状况下须要咱们去重写 方法?
若是只重写equals
方法不重写HashCode
能够吗?
equals ,== 和hashcode()
的区别?ide
。单元测试