请耐心等待,因为我试图引入一个与许多活动线程直接矛盾的新概念。
在HashSet中插入对象的条件是什么?
查看源代码,它会关注:
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
完整代码位于:HashSet.java
所以,这取决于
看看条件4。尽管equals()返回false,但对象会被添加到HashSet。在所有其他情况下,当且仅当equals()返回false时,对象才会被添加。因此,可以说(忽略条件4),一个对象是否会添加到HashSet的决定只是由equals()方法做出的。当被问及为什么我们使用hashCode()时,标准答案是它通过简单地比较整数来提高性能,因为短路运算符保存了equals()方法的执行。这个论点在许多线程中讨论过,比如如果我们无论如何都要检查等于,为什么我们要检查哈希?
然而,我发现这个论点是不正确的。如果equals()返回false,==返回true,哈希码实际上有一个决定。这是极不可能的,因为同一个对象通常会为equals()返回true,除非有人明确地(违反了equals)约定)重写equals方法,以便它为同一对象返回不同的值。尽管如此,这是一种可能性,java似乎正在为某些违约代码提供风险管理。你来吧!
HashSet
要求传递给它的对象遵守 hashCode
的约定并等于
— 如果它们不这样做,那么垃圾输入垃圾。等于
的协定规定,如果两个引用是 ==,
则它们必须相等。因此,上面的条件 4 违反了相等契约,因此违反了 HashSet
的契约,因此 HashSet
在提出这样一组条件时没有义务采取有意义的行动。
条件5也会破坏合同。
如果两个引用相等或相同(==),那么< code>equals()应该返回true。
如果equals()
方法为两个对象返回true
,那么hashCode()
也需要为这两个对象返回相同的哈希值。
因此,让我们考虑8个场景的真值表,如下所示,只有4个有效场景。
| hashCode() | equals() | == | add() |
| not-same | false | false | true |
| not-same | false | true | - | - INVALID scenario (== vs equals)
| not-same | true | false | - | - INVALID scenario (hash vs equals)
| not-same | true | true | - | - INVALID scenario (hash vs equals)
| same | false | false | true |
| same | false | true | - | - INVALID scenario (== vs equals)
| same | true | false | false |
| same | true | true | false |
在问题表中;S. No 4
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
e.hash == 出于
效率原因,哈希在这种情况下存在,它是(在理智的情况下)执行的最快的测试,用于在第一个障碍时打折相等性。在程序处于有效状态的所有情况下(不违反 ==
.equals
() .hashCode()
合约),它对 if 语句的最终结果没有逻辑影响。
由于破坏==
. equals()
. hashCode()
契约而导致的条件不被考虑,因为这样的程序处于无效状态并且没有定义行为。违反契约下的效果可能会从实施变为实施,因此永远不应该依赖。