List.removeAll()无效解决方案
问题:
使用List.removeAll()方法去求 List list1 和 List list2 的差集时,会发现 list1.removeAll(list2)无效,list1的size并没有发生变化。
原因:
执行 removeAll() 方法流程如下图所示:
分析发现 自定义对象的equals()方法使用的是 Object的equals()方法,比较的是对象在JVM中的内存地址,而不是像String类一样只是比较值的相同(String类覆盖了equals()方法)。
String.equlas() :
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Object.equals():
public boolean equals(Object obj) {
return (this == obj);
}
那思路就很清晰了,我们只需要重写我们自定义对象的 equals()方法就可以解决该问题了,但是在equals()方法上有一大段注释就是在说明该方法遵循的规范,借鉴一下大佬翻译好的:
equals 方法实现的时候必须要满足的特性:
1.(reflexive)自反性:
对于任何非 null 的引用值 x,x.equals(x) 必须为 true;
2.(symmetric)对称性:
对于任何非 null 的引用值 x,y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 也要返回 true 。
3.(transitive)传递性:
对于任何非 null 的引用值 x,y,z, 如果 x.equals(y) 返回 true,y.equals(z) 返回 true,那么 x.equals(z) 一定要返回 true。
4.(consistent)一致性:
对于任何非 null 的引用值 x,y,只要 equals() 方法没有修改的前提下,多次调用 x.equals(y) 的返回结果一定是相同的。
5.(non-nullity)非空性
对于任何非 null 的引用值 x,x.equals(null) 必须返回 false。
由于
quals 方法实现的时候必须要满足的特性
需要去检查自己写的方法是否符合规范,很浪费时间,不仅如此,
覆盖 equals 时,一定要同时覆盖 hashCode()方法
这样做的目的是保证每一个 equals()返回 true 的两个对像,要有两个相同的 hashCode 。
解决方案:
使用Lombok 中 包含的注解 @EqualsAndHashCode来自动覆盖equals()和hashCode()方法。
在 IDEA > Setting > Plugins 中搜索 lombok 下载支持插件
使用Maven引入
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven</artifactId>
<version>1.16.20.0</version>
</dependency>
之后在需要覆盖重写equals()和hashCode()方法的类里 使用 @EqualsAndHashCode注解 就大功告成了