繁体   English   中英

如果我的类在Java中实现可比性,我是否需要equals和Hashcode方法?

[英]Do I need a equals and Hashcode method if my class implements comparable in Java?

我发现这个注释可以将StringBuffer对象作为Java中TreeSet中的键吗?

“在Java中使用地图有两种识别策略(或多或少)。

散列:输入“Foo”被转换为尽可能最好的尝试,以生成唯一访问数组索引的数字。 (纯粹主义者,请不要虐待我,我故意简化)。 此索引是存储值的位置。 “Foo”和“Bar”实际上可能生成相同的索引值,这意味着它们都将映射到相同的数组位置。 显然这不起作用,所以这就是“equals()”方法的用武之地; 它用于消除歧义

比较:通过使用比较方法,您不需要这个额外的消歧步骤,因为比较首先不会产生这种碰撞。 “Foo”等于的唯一关键是“Foo”。 一个非常好的想法是,如果你可以将“equals()”定义为compareTo()== 0; 为了一致的缘故。 不是要求。“

我的问题如下:如果我的类实现了可比性,那么它是否意味着我不必重写equals和hashcode方法来将我的对象用作Hash集合中的键。 例如

class Person implements Comparable<Person> {
     int id;
     String name;

     public Person(int id, String name) {
        this.id=id;
        this.name=name;
     }

    public int compareTo(Person other) {
      return this.id-other.id;
    }
}

现在,我可以在Hashable集合中使用我的Person对象吗?

你通过的文章是在TreeSet上讨论的。 树集是一棵树,每个节点都有一个由它的值定义的位置,与树中已有的其他值相比较。

hashTable将键/值对存储在哈希表中。 使用Hashtable时,您可以指定用作键的对象,以及要链接到该键的值。 然后对密钥进行散列,并将得到的散列代码用作值存储在表中的索引。

HashableTreeSet之间的区别在于Hashable集不需要hashCode ,它只需要知道你是否需要在树中左右移动项目。 为此你可以使用比较而已。

在hashTable中,比较就足够了,因为它的构建方式不同,每个对象都通过对其进行散列来到达他的单元格,而不是通过将其与集合中已有的项目进行比较。

所以答案是否定的,你可以'使用compareTo Person in hashtable。 你必须覆盖hashCode()equals()

我还建议你阅读关于哈希表的这篇文章

HashTable确实使用equals和hashCode。 每个班级都有这些方法。 如果您不实现它们,则继承它们。

是否需要实现它们取决于继承的版本是否适合您的目的。 特别是,由于Person没有指定的超类,因此它继承了Object方法。 这意味着Person对象仅与其自身相等。

您是否需要将两个不同的Person对象视为与HashTable键相等?

如果我的类实现了可比性,那么它是否意味着我不必重写equals和hashcode方法来将我的对象用作Hash集合中的键。 例如

不,您仍然需要实现equals()hashCode() 这些方法执行非常不同的功能,不能被compareTo()替换。

  • equals()根据对象的相等性返回一个布尔值。 这通常是身份平等而不是字段平等。 这可能与用于比较compareTo(...)的对象的字段非常不同,尽管如果它对实体有意义,则equals()方法可以是:

     @Overrides public boolean equals(Object obj) { if (obj == null || obj.getClass() != getClass()) { return false; } else { return compareTo((Person)obj) == 0; } } 
  • hashCode()返回实例的一个整数值,该值在哈希表中用于计算它应该放入的存储桶。没有相同的方法可以从compareTo(...)获取该值。

TreeSet需要Comparable,以便在树的右侧或左侧添加值。 HashMap需要可从Object Class获得的equals()和Hashcode()方法,但您必须为了您的目的而重写它们。

如果一个类实现了Comparable ,那么表明该类的实例代表某种类型的值; 通常,当类封装值时,可能存在两个不同的实例,它们保持相同的值,因此应该被认为是等价的。 因为不同对象实例被认为是等价的唯一方法是它们覆盖equalshashCode ,这意味着实现Comparable东西应该覆盖equalshashCode 除非 compare操作的封装值将是全局唯一的(暗示不同)实例永远不应被认为是等价的)。

举个简单的例子,假设一个类包含一个long类型的CreationRank字段; 每次创建实例时,该成员都设置为从单个AtomicLong获取的值, Comparable使用该字段按创建顺序对对象进行排序。 没有两个不同的类实例会报告相同的CreationRank ; 因此, x.equals(y)应该为真的唯一方法是xy引用相同的对象实例 - 完全是默认equalshashCode工作的方式。

顺便说一句,让x.compare(y)返回零通常意味着x.equals(y)将返回true,反之亦然,但在某些情况下x.equals(y)可能为false但x.compare(y)仍应返回零。 当一个对象封装一些可以排序的属性而另一些不能排序时,可能就是这种情况。 例如,考虑一种低级FutureAction类型,它封装了DateTimeDoSomething接口的实现。 这些事情可以根据封装的日期和时间进行排名,但可能没有明智的方法来排列具有相同日期和时间但行动不同的两个项目。 equals报告为false而compare报告为零比假装明显不相等的项目应该被称为“相等”更有意义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM