Java 在HashSet中插入对象的条件?
请容忍我,因为我正试图引入一个与许多活动线程直接矛盾的新概念 在HashSet中插入对象的条件是什么 查看源代码,它的目标是:Java 在HashSet中插入对象的条件?,java,collections,hash,hashset,Java,Collections,Hash,Hashset,请容忍我,因为我正试图引入一个与许多活动线程直接矛盾的新概念 在HashSet中插入对象的条件是什么 查看源代码,它的目标是: if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 完整代码位于: 因此,这取决于 哈希码 等于 ==即,如果它们是相同的对象。 现在,我们知道如果obj1.equalsobj2返回true,两个对象的hashcode必须相同。根据这3个参数的相对值,我创建了下表: 看看第四种情况
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
完整代码位于:
因此,这取决于
哈希码
等于
==即,如果它们是相同的对象。
现在,我们知道如果obj1.equalsobj2返回true,两个对象的hashcode必须相同。根据这3个参数的相对值,我创建了下表:
看看第四种情况。尽管equals返回false,但对象将被添加到HashSet中。在所有其他情况下,当且仅当equals返回false时,才添加对象。因此,可以说忽略条件4,即是否将对象添加到HashSet的决定仅由equals方法决定。当被问及为什么要使用hashCode时,标准的回答是,它通过简单地比较整数来提高性能,因为短路运算符可以节省equals方法的执行。这个论点在许多线程中讨论过,比如
然而,我发现这个论点是不正确的。如果equals返回false,而==返回true,Hashcode实际上有一个决定要做。这是非常不可能的,因为同一个对象通常会为equals返回true,直到有人明确违反equals契约覆盖equals方法,从而使它为同一个对象返回不同的值。尽管如此,这还是有可能的,java似乎在某些违约代码的情况下提供了一种风险管理。拿你的 HashSet要求传递给它的对象遵守hashCode和equals的约定——如果不遵守,则垃圾输入垃圾输出。equals合同规定,如果两个引用为==,则它们必须相等。因此,上面的条件4违反了平等契约,因此违反了HashSet的契约,因此HashSet没有义务在呈现这样一组条件时采取有意义的行动
条件5也破坏了合同。您的真值表不完整。它应该有八行,如下所示:
# 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行表示两个相等的项具有不同哈希代码的情况,这违反了哈希代码契约
最后两行7和8是非法的,因为它们违反了等于是自反的要求,即x.equalsx必须为所有非空x返回true
表中的第4行和第5行表示非法状态。不过,HashSet永远不会发现,因为OR的第一个子句仅仅是一个优化。由于短路,当==的计算结果为true时,将不会调用equals,因此HashSet有效地假设equals的自反性,即使实现是错误的
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
e、 hash==出于效率的考虑,在这种情况下出现hash,它是在正常情况下执行的最快测试,用于在第一个关卡上对相等性进行折扣。在所有情况下,如果程序处于不违反==.equals.hashCode约定的有效状态,则对if语句的最终结果没有逻辑影响
不考虑因违反==.equals.hashCode契约而产生的条件,因为此类程序处于无效状态,并且未定义行为。违约合同下的影响可能会随着执行的不同而变化,因此不应依赖于执行。您没有说明操作顺序。实际表格将包括DC,即不关心,因为它们不会被评估 如果我们在以下情况为假时添加
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
然后
如果hash或equals函数不正确,那么这些都不重要。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 |
在问题表中;由于==vs等于合同,4号和5号合同无效。您需要的只是有效条件,然后您可以直接进行此操作
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时添加。@richardingle:很明显,如果你编写了一个伪equals/hashCode,那么你会得到伪结果。@qualtar是否有任何例子表明==.equals.hashCode契约没有被违反,其中。hashCode不仅仅是为了性能?因为在违反这种联系的地方,任何事情都可以做。这是为了效率,这是第一个条件
在if中,因为它最简单。事实上,如果你违反了合同,它会有第二种行为,这与此无关。当程序处于有效状态时,次级行为永远不会被看到,因此不被考虑。编辑不会做出决定。因此,基本上,您已经确定,如果程序完全被破坏,将出现虚假结果。你期待什么?它能正常工作吗?没有义务和没有义务不一样。这意味着您将任由实现细节摆布,这些细节可能会一时兴起而改变。@qualtar有效果!=具有有意义的效果。这只是一个坏系统发出的噪音我想到了整张桌子。行号1和行号2不是必需的,因为它们表明了一个明显的事实,即如果equals为true,hashcode就一定是相同的。@它们是qualtar,您可以编写一个无效的hashCode,这样如果equals为true,hashCode就不是same@RichardTingle:点…我还是忍不住忽略了第1行和第2行盲目地遵循相等。第4行也是无效的;如果两个对象相等,则hashCode值必须相同。好的……放手……因此,如果契约被破坏,则没有比较点,hashCode仅存在且仅用于性能……对吗???事实上,如果契约被破坏,则您将重写程序,因此它不是。我想一个有缺陷的程序是如何有缺陷的在学术层面上是很有趣的,但这样的程序永远不应该投入生产
╔════════════╦══════════╦═══════╦═══════╗
║ hashCode() ║ equals() ║ == ║ add() ║
╠════════════╬══════════╬═══════╬═══════╣
║ not-same ║ false ║ false ║ true ║
║ same ║ false ║ false ║ true ║
║ same ║ true ║ false ║ false ║
║ same ║ true ║ true ║ false ║
╚════════════╩══════════╩═══════╩═══════╝