问题
在父类中重写了equals方法,将父类对象添加进list中并且不存在子类对象时,调用list.contains(子类)返回true,反之亦然。
结论
重写equals时要考虑以下原则:
- 自反性:非空引用x,x.equals(x)应返回true
- 对称性:非空引用x,y,当且仅当x.equals(y)==true时,y.equals(x)==true
- 传递性:非空引用x,y,z,若x.equals(y)==true,y.equals(z)==true,则x.equals(z)==true。
- 一致性:若x,y引用对象没有改变,则反复调用x.equals(y)应返回相同值。
- 空引用:x.equals(null) 应返回false
上述问题是因为没考虑“对称性”原则,子类会继承父类equals方法,因此无论父类.equals(子类)还是子类.equals(父类)都是true。
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
class A {
public String obj;
public String name;
public A(String obj, String name) {
this.obj = obj;
this.name = name;
}
public int id = 1;
@Override
public boolean equals(Object o) {
if (this == o) return true; // 自反性
if (!(o instanceof A)) return false;
A a = (A) o;
return Objects.equals(obj, a.obj);
}
@Override
public int hashCode() {
return Objects.hash(name, id);
}
}
class B extends A{
public B(String obj, String name) {
super(obj, name);
}
}
public class Test {
public static void main(String[] args) {
A a1 = new A("a", "a");
A a2 = new B("a", "a");
List<A> list = new ArrayList<>();
list.add(a2);
System.out.println(list.contains(a1));
}
}
结果

修改思路
- 重写子类equals方法,使用
o instanceof 子类来与自身判断 - 父类中不使用instaceof,改为
if (o == null || getClass() != o.getClass()) return false;
当在Java中重写equals方法时,未遵循对称性原则可能导致集合contains方法返回异常结果。文章通过一个问题场景解释了这个问题,并指出解决此问题需要确保equals方法的自反性、对称性、传递性、一致性和空引用性质。解决方案是为子类单独实现equals方法,避免使用instanceof关键字。
454

被折叠的 条评论
为什么被折叠?



