java - 为什么我不应该将 equals 与继承一起使用?

标签 java oop equals

当我读一本 Java 书籍时,作者曾说过,在设计类时,使用继承的 equals() 通常是不安全的。例如:

public final class Date {
    public boolean equals(Object o) {
         // some code here
    }
}

在上面的类中,我们应该放置final,这样其他类就不能继承自它。我的问题是,为什么允许另一个类继承自它是不安全的?

最佳答案

因为很难(不可能?)让它正确,尤其是 symmetric property .

假设您有 Vehicle 类和 Car extends Vehicle 类。如果参数也是 Vehicle 并且具有相同的权重,则 Vehicle.equals() 产生 true。如果你想实现 Car.equals() 它应该只在参数也是汽车时产生 true ,除了重量,它还应该比较品牌,引擎等.

现在想象下面的代码:

Vehicle tank = new Vehicle();
Vehicle bus = new Car();
tank.equals(bus);  //can be true
bus.equals(tank);  //false

如果碰巧坦克和公共(public)汽车具有相同的重量,第一次比较可能会产生 true。但由于坦克不是汽车,将它与汽车进行比较总是会得出 false

您几乎没有解决方法:

  • strict:两个对象相等当且仅当它们具有完全相同的类型(并且所有属性都相等)。这很糟糕,例如当您几乎不添加一些行为或装饰原始类时。一些框架也在您不注意的情况下对您的类进行子类化(Hibernate、带有 CGLIB 代理的 Spring AOP...)

  • 松散:如果两个对象的类型“兼容”并且具有相同的内容(语义上),则这两个对象是相等的。例如。如果两个集合包含相同的元素,则它们是相等的,一个是 HashSet 另一个是 TreeSet 并不重要(感谢 @veer指出这一点)。

    这可能会产生误导。取两个 LinkedHashSet(其中插入顺序作为契约(Contract)的一部分很重要)。然而,由于 equals() 仅考虑原始 Set 契约(Contract),因此即使对于明显不同的对象,比较也会产生 true:

    Set<Integer> s1 = new LinkedHashSet<Integer>(Arrays.asList(1, 2, 3));
    Set<Integer> s2 = new LinkedHashSet<Integer>(Arrays.asList(3, 2, 1));
    System.out.println(s1.equals(s2));
    

关于java - 为什么我不应该将 equals 与继承一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12239344/

相关文章:

java - 是Throwable类的printStackTrace(),异步

java - W-shingling 实现 - 存储木瓦

java - 我想当用户单击 GUI 中的按钮时打开图像

Java 要求覆盖 jfilechooser

python - Python中继承的抽象类上的`__subclasshook__`?

Javascript:使用非连续键迭代数组

java - 为什么这个正则表达式不匹配

c++ - C++ 应用程序的登录应该在单独的线程中完成吗?

android - 两个相同的 String 不会等于 true

equals() 中的 Java 类型检查 : instanceof vs getClass()