简体   繁体   English

Java hashCode有疑问

[英]Java hashCode doubt

I have this program: 我有这个程序:

import java.util.*;
public class test {
    private String s;
    public test(String s) { this.s = s; }
    public static void main(String[] args) {
        HashSet<Object> hs = new HashSet<Object>();
        test ws1 = new test("foo");
        test ws2 = new test("foo");
        String s1 = new String("foo");
        String s2 = new String("foo");
        hs.add(ws1); 
        hs.add(ws2); 
        hs.add(s1); 
        hs.add(s2); // removing this line also gives same output.
        System.out.println(hs.size()); 
    } 
}

Note that this is not a homework. 请注意,这不是作业。 We were asked this question on our quiz earlier today. 我们今天早些时候在测验中被问到了这个问题。 I know the answers but trying to understand why it is so. 我知道答案,但试图理解为什么会这样。

The above program gives 3 as output. 上面的程序给出3作为输出。

Can anyone please explain why that is? 任何人都可以解释为什么会这样吗?

I think (not sure): 我想(不确定):

The java.lang.String class overrides the hashCode method from java.lang.Object . 所述java.lang.String类覆盖hashCode从方法java.lang.Object So the String objects with value "foo" will be treated as duplicates. 因此,值为“foo”的String对象将被视为重复项。 The test class does not override the hashCode method and ends up using the java.lang.Object version and this version always returns a different hashcode for every object, so the two test objects being added are treated as different. 测试类不会覆盖hashCode方法并最终使用java.lang.Object版本,并且此版本始终为每个对象返回不同的哈希码,因此添加的两个测试对象将被视为不同。

In this case it's not about hashCode() but is about equals() method. 在这种情况下,它不是关于hashCode()而是关于equals()方法。 HashSet is still Set, which has semantic of not allowing duplicates. HashSet仍然是Set,其语义不允许重复。 Duplicates are checked for using equals() method which in case of String will return true 使用equals()方法检查重复项,如果是String,则返回true

However for your test class equals() method is not defined and it will use the default implementation from Object which will return true only when both references are to the same instance. 但是,对于您的test类,未定义equals()方法,它将使用Object的默认实现,只有当两个引用都属于同一实例时才会返回true。

Method hashCode() is used not to check if objects should be treated as same but as a way to distribute them in collections based on hash functions. 方法hashCode()用于不检查对象是否应该被视为相同,而是用于基于散列函数将它们分布在集合中的方式。 It's absolutely possible that for two objects this method will return same value while equals() will return false. 绝对有可能对于两个对象,此方法将返回相同的值,而equals()将返回false。

PS hashCode implementation of Object doesn't guarantee uniqueness of values. Object PS hashCode实现不保证值的唯一性。 It's easy to check using simple loop. 使用简单的循环检查很容易。

Hashcode is used to narrow down the search result. Hashcode用于缩小搜索结果范围。 When we try to insert any key in HashMap first it checks whether any other object present with same hashcode and if yes then it checks for the equals() method. 当我们首先尝试在HashMap插入任何键时,它会检查是否存在任何其他对象具有相同的哈希码,如果是,则检查equals()方法。 If two objects are same then HashMap will not add that key instead it will replace the old value by new one. 如果两个对象相同,那么HashMap将不会添加该键,而是将新值替换为旧值。

In fact, it is not about overriding the hashcode() , it is about equals method. 实际上,它不是覆盖hashcode() ,而是关于equals方法。 Set does not allow duplicates. 设置不允许重复。 A duplicate is the one where the objects are logically equal. 副本是对象在逻辑上相等的副本。

For verifying you can try with 为了验证您可以尝试

System.out.println(ws1.equals(ws2));
System.out.println(s1.equals(s2));

If the objects are equal, only one will be accepted by a set. 如果对象相等,则一组只接受一个。

Below are few (well quite many) bullets refarding the equals and hashcode from my preparations to SCJP. 下面是几个(很多很多)子弹从我准备到SCJP的平等和哈希码。 Hope it helps: 希望能帮助到你:

  • equals(), hashCode(), and toString() are public. equals(),hashCode()和toString()是公共的。
  • Override toString() so that System.out.println() or other methods can see something useful, like your object's state. 覆盖toString(),以便System.out.println()或其他方法可以看到有用的东西,比如对象的状态。
  • Use == to determine if two reference variables refer to the same object. 使用==确定两个引用变量是否引用同一个对象。
  • Use equals() to determine if two objects are meaningfully equivalent. 使用equals()确定两个对象是否有意义等效。
  • If you don't override equals(), your objects won't be useful hashing keys. 如果不重写equals(),则对象将不是有用的散列键。
  • If you don't override equals(), different objects can't be considered equal. 如果不重写equals(),则不能将不同的对象视为相等。
  • Strings and wrappers override equals() and make good hashing keys. 字符串和包装器重写equals()并制作好的哈希键。
  • When overriding equals(), use the instanceof operator to be sure you're evaluating an appropriate class. 覆盖equals()时,请使用instanceof运算符以确保您正在评估适当的类。
  • When overriding equals(), compare the objects' significant attributes. 覆盖equals()时,比较对象的重要属性。
  • Highlights of the equals() contract: 等号的亮点 ()合同:
    a. 一个。 Reflexive: x.equals(x) is true. 反身:x.equals(x)为真。
    b. Symmetric: If x.equals(y) is true, then y.equals(x) must be true. 对称:如果x.equals(y)为真,则y.equals(x)必须为真。
    c. C。 Transitive: If x.equals(y) is true, and y.equals(z) is true, then z.equals(x) is true. 传递:如果x.equals(y)为真,并且y.equals(z)为真,则z.equals(x)为真。
    d. d。 Consistent: Multiple calls to x.equals(y) will return the same result. 一致:多次调用x.equals(y)将返回相同的结果。
    e. Null: If x is not null, then x.equals(null) is false. Null:如果x不为null,则x.equals(null)为false。
    f. F。 If x.equals(y) is true, then x.hashCode() == y.hashCode() is true. 如果x.equals(y)为true,则x.hashCode()== y.hashCode()为true。
  • If you override equals(), override hashCode(). 如果重写equals(),则覆盖hashCode()。
  • HashMap, HashSet, Hashtable, LinkedHashMap, & LinkedHashSet use hashing. HashMap,HashSet,Hashtable,LinkedHashMap和LinkedHashSet使用散列。
  • An appropriate hashCode() override sticks to the hashCode() contract. 一个合适的hashCode()覆盖符合hashCode()契约。
  • An efficient hashCode() override distributes keys evenly across its buckets. 有效的hashCode()覆盖在其桶之间均匀分配密钥。
  • An overridden equals() must be at least as precise as its hashCode() mate. 重写的equals()必须至少与其hashCode()配合一样精确。
  • To reiterate: if two objects are equal, their hashcodes must be equal. 重申一下:如果两个对象相等,则它们的哈希码必须相等。
  • It's legal for a hashCode() method to return the same value for all instances (although in practice it's very inefficient). hashCode()方法为所有实例返回相同的值是合法的(尽管在实践中它的效率非常低)。

In addition if you implement equals and hashcode the transient fields (if any) must be treated properly. 此外,如果您实现equals和hashcode,则必须正确处理瞬态字段(如果有)。

The Commons have nice implementation for EqualsBuilder and HashcodeBuilder. Commons对EqualsBuilder和HashcodeBuilder有很好的实现。 They are available in Coomons Lang http://commons.apache.org/lang/ 它们可以在Coomons Lang中找到http://commons.apache.org/lang/

I use them whenevr I need to implement the equals and the hashcode. 我使用它们whenevr我需要实现equals和hashcode。

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

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