当它被 put() 到一个HaspMap并在 ge茂雄德田t() 期间产生另一个值时会产生一个 hashCode()值

摘要:这是一篇关于hashCode方法,可变对象和内存泄漏问题的文章。1. 重写 hashCode() 和 equals() 的契约每个 java 对象都有两个


当它被 put() 到一个HaspMap并在 ge茂雄德田t() 期间产生另一个值时会产生一个 hashCode()值



这是一篇关于hashCode方法,可变对象和内存泄漏问题的文章。

1. 重写 hashCode() 和 equals() 的契约

每个 JAVA 对象都有两个非常重要的方法,比如 hashCode() 和 equals() 方法。这些方法旨在根据其特定的一般规则进行重写。本文描述了为什么以及如何覆盖 hashCode() 方法,该方法在使用 HashMap , HashSet 或任何 Collection 时保留 HashCode 的契约。

1.1 hashCode 契约

hashCode 的契约就是:

如果两个对象相等,那么调用两个对象的 hashCode() 方法一定会返回相同的 hash 值。

现在你应该想到的问题是:上述陈述是否应该永远是真的?

考虑一下这样一个事实,当我们为我们的类提供了一个正确的 equals 实现,林私钟,那么如果我们不遵守上述规则会发生什么。

为了回答上面的问题,我们来考虑两个问题:

对象是相等的,但是返回了不同的 hashCode

对象不是相等的,但是它们却有相同的 hashCode

1.1.1 对象是相等的,但是返回了不同的 hashCode

当两个对象是相等的,但是返回了不同的 hashCode 会发生什么?你的代码会运行的很好。除非你没有将对象存储在像 HashSet 或 HashMap 这样的集合中,否则永远不会遇到麻烦。但是当你将你的对象存储到上面提到的那种集合中的时候,在运行的时候可能会发生一些奇怪的问题。

为了更好的理解这个问题,你必须理解集合类中像 hashMap , HashSet 这样的数据结构是如何工作的。这些集合类取决于您作为其中的键放置的对象,且必须遵守上述契约的事实。如果你没有遵循上面的契约, 并且尝试将对象存储在集合中,那么在运行期你将会得到一个奇怪并且不可预料的结果。

以 HashMap 为例子来说明。当你在 hashMap 中存储值的时候,这些值实际存储在一组桶中。每个桶都分配了一个用于识别它的号码。当你在 HashMap 中 put 一个值的时候,它就会在那些桶中存储数据。具体存储在哪个桶中,取决于你的对象所返回的 hashcode 。换句话说,如果一个对象调用 hashCode() 方法返回了49,那么它就会存储在 HashMap 编号为49的这个桶中。

随后,当你尝试通过调用 contains(element) 方法去检查集合中是否包含该元素。HashMap 首先会得到这个 element 的 hashCode, 然后,它将查看与 hashCode 对应的存储桶。如果存储桶为空,捧腹网每日动漫,则表示我们已完成,并且返回 false ,这意味着 HashMap 不包含该元素。

如果存储桶中有一个或多个对象,则它将使用您定义的 equals() 函数将 element 与该存储桶中的所有其他元素进行比较。

1.1.2 对象不是相等的,但是它们却有相同的 hashCode

hashCode 契约没有说明上述语句。因此,不同的对象可能返回相同的 hashCode 值, 但是如果不同的对象返回相同的 hashCode 值,则像 HashMap 这样的集合将无法正常使用。

1.2 为什么是存储桶?

您可以想象,如果放在 HashMap 中的所有对象都存储在一个大列表中,那么当您想要检查特定元素是否在 Map 中时, 您必须将输入与列表中的所有对象进行比较。通过使用存储桶,您现在只比较特定存储桶的元素, 并且任何存储桶通常只包含 HashMap 中所有元素的一小部分。

1.3 重写 hashCode 方法

编写一个好的 hashCode() 方法对于新类来说总是一项棘手的任务。

1.3.1 返回固定的值

您可以实现 hashCode() 方法,以便始终返回固定值,例如:

?

//bad performance @Override public int hashCode() { return 1; }

上述方法满足所有要求,并根据哈希码合同被认为是合法的,但效率不高。如果使用此方法,则所有对象将存储在同一个存储桶(即存储桶1)中,当您尝试确保特定对象是否存在于集合中时,它始终必须检查集合的整个内容。另一方面,如果为您的类重写 hashCode() 方法,并且该方法违反了契约,则调用 contains() 方法可能会对集合中存在但在另一个存储桶中的元素返回 false 。

1.3.2 Effective Java中的方法

Joshua Bloch 在 Effective Java 中提供了一个生成 hashCode() 值的指导方法:

存储一些常量非零值;比方说17,在一个名为 result 的 int 变量中。

对于对象中的每个重要字段 f ( equals() 考虑的每个字段),请执行以下操作:

a. 为字段 c 计算一个 int 类型的 hashCode ;

i. 如果值域是一个布尔类型值,计算 c=(f?1:0)

ii. 如果域是一个 byte , char , short , int ,计算 c=(int)f

iii.如果域是一个 long 类型,计算 c=(int)(f^(f>>>32)).

iv.如果域是一个 float 类型,计算 c=Float.floatToIntBits(f).

v.如果域是一个 double 类型,计算 long l = Double.doubleToLongBits(f) , c = (int)(l^(l>>>32))

vi.如果该字段是对象引用,则 equals() 为该字段调用 equals() 。计算 c = f.hashCode()

vii.如果域是一个数组,将其视为每个元素都是一个单独的字段。

也就是说,通过将上述规则应用于每个元素来为每个重要元素计算 hashCode。

b.将步骤2.a中计算的 hashCode c 组合到结果中,如下所示:result = 37 * result + c;

返回结果值

查看生成的 hashCode() 并确保相等的实例具有相同的哈希码。

以下是遵循上述准则的类的示例


本文地址:/wenhua/20190810/25302.html 转载请注明出处!
相关文章:
  1. [文化产业]而不是把相同重生之吴应熊传奇的代码写很多次
  2. [文化产业] 官方网站: 10.Apach田震英e Maven 上面曾提到过A
  3. [文化产业]它提供了一些有用的工逃出纳粹牢房具对数据进