【问题标题】:How to override the equals method of a subclass如何覆盖子类的equals方法
【发布时间】:2017-05-05 12:07:56
【问题描述】:

我正在尝试在两个不同位置之间同步用户,因此我将现有用户保留在一个列表中,因此以设定的时间间隔进行比较,以查看是否应该添加(新)用户或仅更新用户。

我有一个类 User,它是 Principal 的子类。

但是我在列表中的比较不起作用;我用谷歌搜索了一下,发现你必须重写 equals 方法,我这样做了 - 但该代码似乎没有被执行,它进入 ArrayList.class (原始)并在那里执行 contains 方法。

这是因为我的类已经扩展了超类 Principal 吗? 如果我想执行我在 User 类中定义的 equals,我有什么选择?

public class User extends Principal
{
    // some protected properties
    ...

        @Override
        public boolean equals(Object obj) {
            return (this.getAlias().equals(((User) obj).getAlias())
                && this.getEmailAddress().equals(((User) obj).getEmailAddress()) && this.getCellNumber().equals(((User) obj).getCellNumber()));
    } 
}

Principal 类没有重写equals方法,更重要的是,我检查相等性的属性,只包含在子类--User中。因此,在这里检查它是有意义的。

简而言之,我有一个用户数组列表,我想检查某个用户是否已经存在。我在列表上调用 compare ,但它总是失败,表明方法 equals 没有在我的代码中正确覆盖。 有什么建议吗?

【问题讨论】:

  • 你做的很好。
  • 我假设您的 ArrayList 包含 Principal 对象?
  • 请在列表中实际比较的地方添加代码。
  • 1.听起来这应该是线程安全的。 2. 出于性能原因,使用更好的数据结构来保存用户可能会更好,以便更快地检索和更新。例如地图。您只需要为您的用户创建一个密钥,痛苦就会消失。或者更好的是并发的 - ConcurrentHashMap
  • ArrayList 的类型是 User,而不是 Principal。

标签: java arraylist compare overriding equals


【解决方案1】:

您不应该在超类中实现equals()(和hashcode())。

原因是equals()返回truehashcode()必须返回相同

假设您有 Point2D 类和 Point3D 类扩展另一个类。

point2D 是否应该等于具有相同区域坐标的 point3D? 如果是这样,那么 point3D 必须返回与“相等”point2D 相同的哈希码,这意味着您不能存储多个相同的 point3d Hash 基集合中的区域坐标(例如:作为 HashMap 中的键)。

【讨论】:

    【解决方案2】:

    覆盖等于并不像看起来那么明显

    • 等于 null 必须返回 false
    • 由于对称性 a.equals(b) b.equals(a)
    • ,与不同类的对象相等必须返回 false

    java

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj == null || obj.getClass()!=getClass()) {
            return false;
        }
        return Object.equals(this.getAlias(),((User) obj).getAlias())
            && Object.equals(this.getEmailAddress(),((User) obj).getEmailAddress())
            && Object.equals(this.getCellNumber(),((User) obj).getCellNumber()));
    } 
    

    此外,如果在哈希集合中使用对象,则它必须覆盖 hashCode,以便两个相等的对象必须返回相同的 hashCode,反之则不然。

    【讨论】:

    • 我正在尝试这个选项 - 当预期的返回类型是布尔值时,不能返回 null...
    • 代码是作为示例给出的,但已修复:将 return null 更改为 return false
    • 需要注意的是,如果您要覆盖equals(),那么hashcode() 也应该被覆盖,以防止Collections 出现意外行为
    • @CraigR8806,我特别同意哈希容器,但从问题来看它是 ArrayList
    【解决方案3】:

    问题可能来自您实例化List<Person>。编译器无法知道 Person 的每个子类是否都覆盖了equals。要纠正此问题,您应该承诺您的编译器将覆盖此方法,您可以通过将 Person 类更改为抽象类来实现。

    public abstract class Person {
        @Override
        public abstract boolean equals(Object o);
    }
    
    public class User extends Person {
        // Some stuff...
        @Override
        public boolean equals(Object o) {
            if (o == null || ! (o instanceof User))
                return false;
            // etc
        }
    }
    

    【讨论】:

    • hashCode 仅用于散列容器 HashSet HashMap... 但在这种情况下它是一个 ArrayList
    • 我的评论来自hashCodes和equals的规范,如果equals方法返回true,hashcode返回true。这必须始终受到尊重,因此最好同时覆盖两者。
    【解决方案4】:

    根据 Effective Java 一书。如果你已经重写了 equals 方法,那么你必须重写 hashcode 方法。 重写 equals 方法时的一些建议: 1. 等于 null 返回 false。 2. !(obj instanceof this) 返回 false。 3.将obj强制转换为这个类,并比较obj和这个类中的参数。 最后返回结果

    【讨论】:

      【解决方案5】:

      你应该使用arrayList的contains方法

      https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

      【讨论】:

      • 如果他不覆盖他的equals和hashCode,那是行不通的。 contains 方法使用这些函数来检查元素是否已经在列表中。
      猜你喜欢
      • 1970-01-01
      • 2014-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多