请耐心等待我,因为我试图引入一个与许多活动线程直接矛盾的新概念。
在HashSet中插入对象的条件是什么?
查看源代码,它会显示为:
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
完整代码:HashSet.java
所以,这取决于
现在,我们知道如果obj1.equals(obj2)返回true,则两个对象的哈希码必须相同。基于这3个参数的相对值,我创建了下表:
看条件没有。 4.尽管equals()返回false,但对象被添加到HashSet中。在所有其他情况下,当且仅当equals()返回false时,才会添加对象。因此,可以说(忽略条件号4)是否将对象添加到HashSet的决定仅通过equals()方法。在被问到为什么我们使用hashCode()时,标准答案是它通过简单地比较整数来提高性能,因为短路操作符保存了equals()方法的执行。许多线程如Why do we check hash if we are going to check equals anyways?
讨论了这个论点但是,我发现这个论点是不正确的。如果equals()返回false并且==返回true,则Hashcode实际上决定采用。这是非常不可能的,因为同一个对象通常对equals()返回true,直到有人显式(违反equals()契约)覆盖equals方法,以便它为同一个对象返回不同的值。尽管如此,它有可能和java似乎在一些违约代码的情况下提供风险管理。你的服用!
答案 0 :(得分:4)
HashSet
要求传递给它的对象遵守hashCode
和equals
的合同 - 如果他们不遵守,那么垃圾进入垃圾场。 equals
的合同规定如果两个引用为==
,则它们必须相等。因此,您的上述条件4违反了平等合同,因此违反了HashSet
的合同,因此HashSet
没有义务在提出这样一套条件时采取有意义的行动。
条件5也违反了合同。
答案 1 :(得分:2)
equals()
如果两个引用相同或相同(==),则equals()
应返回true。
hashCode()
如果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& 5由于==
vs equals()
合同而无效。
答案 2 :(得分:1)
你的真相表不完整。它应该有八行,如下所示:
# HashCode Equals == add()
- -------- ------ ------ -----
1 same TRUE TRUE FALSE
2 same TRUE FALSE FALSE
3 same FALSE FALSE TRUE
4 diff FALSE FALSE TRUE
======= ILLEGAL ROWS =========
5 diff TRUE TRUE TRUE -- Breaks the contract of hashCode, which must
-- return the same value on multiple calls
6 diff TRUE FALSE TRUE -- Breaks the contract of hashCode
7 same FALSE TRUE FALSE -- Breaks the contract of equals
8 diff FALSE TRUE FALSE -- Breaks the contract of equals
第5行表示当hashCode
多次调用它时返回不同值的情况(这是一件非常糟糕的事情,但是当对象可变时偶尔会发生这种情况)。
第6行表示两个相同的项目具有不同hashCode
- 违反hashCode
合同的情况。
最后两行#7和#8是非法的,因为它们违反了equals()
要求自反的要求(即x.equals(x)
必须为所有非空返回true
x
)。
表中的第4行和第5行代表非法状态。 HashSet
永远不会发现,因为OR
的第一个条款仅仅是优化。由于短路,equals
评估为==
时无法调用true
,因此HashSet
有效地假定equals
的反身性,即使实施是错误的。
答案 3 :(得分:1)
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
e.hash == hash
出现在这种情况下是出于效率的原因,它是(在理智的情况下)最快的测试,用于在第一道障碍时折扣平等。在程序处于有效状态(不违反==
.equals()
.hashCode()
合同)的所有情况下,它对if语句的最终结果没有逻辑影响。
不考虑违反==
.equals()
.hashCode()
合同的条件,因为此类程序处于无效状态且未定义行为。合同破裂后的影响可能会从实施转变为实施,因此永远不应该依赖。
答案 4 :(得分:0)
您没有解决操作顺序。真实表将包括DC(即不关心),因为它们不会被评估。
如果我们添加以下内容为FALSE
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
然后
hash== && (key== || equals()) >> add?
---------------------------------------
T | T | DC || F
F | DC | DC || T
T | F | T || F <- Not possible with correct code
T | F | F || F <- Not possible with correct code
如果hash或equals函数不正确,那么这一切都不重要。
答案 5 :(得分:0)
您需要的只有有效条件,然后您可以直接进行此操作。
if(!Obj1.equals(Obj2)) add() ;
正如您所看到的,有8种情况可能,其中4种只有有效,请继续使用它们。
╔════════════╦══════════╦═══════╦═══════╗
║ hashCode() ║ equals() ║ == ║ add() ║
╠════════════╬══════════╬═══════╬═══════╣
║ not-same ║ false ║ false ║ true ║
║ same ║ false ║ false ║ true ║
║ same ║ true ║ false ║ false ║
║ same ║ true ║ true ║ false ║
╚════════════╩══════════╩═══════╩═══════╝
所以现在很明显我们只在equals()为false时添加。