当前位置: 首页 > 知识库问答 >
问题:

如何保证equals()和hashCode()是同步的?

呼延鸿畅
2023-03-14

我们正在编写一个类,它需要非常复杂的逻辑来计算equals()和hashCode()。类似于:

@Getters @Setters @FieldDefaults(level=AccessLevel.PRIVATE)
public class ExternalData {
  TypeEnum type;
  String data;
  List<ExternalData> children;
} 

共有1个答案

程冥夜
2023-03-14

如果遍历算法足够复杂,您希望避免重复,请将该算法隔离为equalshashcode都可以使用的方法。

我看到了两种选择,它们(这是经常发生的情况)在广泛适用和高效之间进行权衡。

第一种选择是编写一个相当通用的遍历方法,它接受一个函数接口,并在遍历的每个阶段回调它,因此您可以在遍历时向其中传递一个包含您希望执行的实际逻辑的lambda或实例;访客模式。该接口希望有一种方式来表示“停止遍历”(例如,因此equals可以在它知道答案是“not equal”时退出)。从概念上讲,这看起来类似于:

private boolean traverse(Visitor visitor) {
    while (/*still traversing*/) {
        if (!visitor.visitNode(thisNode)) {
            return false;
        }
        /*determine next node to visit and whether done*/
    }
    return true;
}

然而,问题是,使用它意味着分配一个实例(或者使用lambda,但您可能需要分配一些东西让lamba更新,以跟踪它在做什么),并进行大量的方法调用。也许这对你来说没问题;也许它是性能杀手,因为您的应用程序需要大量使用equals。:-)

...所以您可能需要编写特定于这种情况的东西,编写内置equalshashcode逻辑的东西。它将返回hashcode使用时的哈希代码,或equals的标志值(0=不相等,!0=相等)。不再是一般有用的,但它避免了创建一个访问者实例来传入/lambda开销/call开销。从概念上看,这可能类似于:

private int equalsHashCodeWorker(Object other, boolean forEquals) {
    int code = 0;

    if (forEquals && other == null) {
        // not equal
    } else {
        while (/*still traversing*/) {
            /*update `code` depending on the results for this node*/
        }
    }

    return code;    
}

再一次,细节将是,嗯,具体到你的案例,以及你的风格指南等等。有些人会通过让equals处理other==null大小写本身,并且只在该工作者具有非null对象时调用该工作者,从而使other参数有两个目的(标志和“other”对象)。我更愿意避免重复这种论点的意义,但你经常看到这种情况。

不管你走哪条路,如果你在一个有测试文化的商店里,你自然会想要为你已经看到失败的复杂案例以及你看到失败机会的其他案例构建测试

不管上面的情况,如果您希望hashcode会被调用很多,那么您可能会考虑将结果缓存到实例字段中。如果您使用的对象是可变的(听起来像是可变的),那么只要您改变对象的状态,就会使存储的hashcode无效。这样,如果对象没有更改,您就不必在后续调用hashcode时重复遍历。但是当然,如果您忘记了使您的mutator方法中的哈希代码无效...

 类似资料:
  • 问题内容: 当覆盖java.lang.Object的equals()函数时,javadocs建议, 通常,无论何时重写此方法,都必须重写hashCode方法,以维护hashCode方法的常规约定,该约定规定相等的对象必须具有相等的哈希码。 hashCode()方法必须为每个对象返回一个 唯一的整数 (当根据内存位置比较对象时,这很容易做到,只需返回对象的 唯一的整数 地址即可) 应该如何重写has

  • 我试图覆盖提到的方法为我的: MyObject: 如何重写hashcode(),equals()和compareTo()方法? 目前我有以下几点: 我读到通过id比较是不够的,这是对象是数据库的持久实体(见这里)。 此类型的所有对象的名称和编号不是唯一的。 那么我应该如何覆盖它呢? 我还需要比较它里面的hashMap吗? 我很困惑。该对象唯一独特的地方是map myMap,它将在生命周期的后期填充

  • 问题内容: 我应该如何实施和在Java下面的类? 问题答案: 在Eclipse中,右键单击->源->生成hashCode(),然后equals()给出以下信息: 我已选择代码作为唯一字段

  • 我在为自定义员工类实现hashmap时有问题。 > 我只重写了employee类的。所以,对于相同的对象,我得到相同的hashcode值。如果我不重写equals(),那就没问题了,对吧?因为object类的)比较了引用(在这里,我得到了相同的引用来表示相等的对象)。无论如何,根据我的逻辑,我永远不会为不同的emp对象得到相同的哈希值。所以,让

  • 问题内容: 有没有办法找出一个类是否已重写和? 问题答案: 您可以使用反射 如果将注释掉,如果没有注释,将打印。 将返回实现该对象的类的对象。 请注意 ,仅适用于方法。但是,在这种情况下,和必须。取决于其他算法,该算法将需要更改。

  • 问题内容: 建议和有时是必要的,即表示值(类 值类 )来覆盖,[和任选]的方法。这些方法返回的值取决于类及其超类的成员变量的全部或子集。为了实现它们正常,你必须了解理论的一点点 散列 和代数和集理论的一点点(不要太多,几乎一切都在explaind 的javadoc 这些方法和有效的Java形式乔希布洛赫。) 在大多数情况下,此方法的实现遵循一个模板,并且IDE(如Eclipse JDT)包括生成它