开发者

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 ask开发者_StackOverflow社区ed 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.

Can anyone please explain why that is?

I think (not sure):

The java.lang.String class overrides the hashCode method from java.lang.Object. So the String objects with value "foo" will be treated as duplicates. 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.


In this case it's not about hashCode() but is about equals() method. HashSet is still Set, which has semantic of not allowing duplicates. Duplicates are checked for using equals() method which in case of String will return 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.

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. It's absolutely possible that for two objects this method will return same value while equals() will return false.

P.S. hashCode implementation of Object doesn't guarantee uniqueness of values. It's easy to check using simple loop.


Hashcode is used to narrow down the search result. 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. If two objects are same then HashMap will not add that key instead it will replace the old value by new one.


In fact, it is not about overriding the hashcode(), it is about equals method. 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. Hope it helps:

  • equals(), hashCode(), and toString() are public.
  • Override toString() so that System.out.println() or other methods can see something useful, like your object's state.
  • Use == to determine if two reference variables refer to the same object.
  • Use equals() to determine if two objects are meaningfully equivalent.
  • If you don't override equals(), your objects won't be useful hashing keys.
  • If you don't override equals(), different objects can't be considered equal.
  • Strings and wrappers override equals() and make good hashing keys.
  • When overriding equals(), use the instanceof operator to be sure you're evaluating an appropriate class.
  • When overriding equals(), compare the objects' significant attributes.
  • Highlights of the equals() contract:
    a. Reflexive: x.equals(x) is true.
    b. Symmetric: If x.equals(y) is true, then y.equals(x) must be true.
    c. Transitive: If x.equals(y) is true, and y.equals(z) is true, then z.equals(x) is true.
    d. Consistent: Multiple calls to x.equals(y) will return the same result.
    e. Null: If x is not null, then x.equals(null) is false.
    f. If x.equals(y) is true, then x.hashCode() == y.hashCode() is true.
  • If you override equals(), override hashCode().
  • HashMap, HashSet, Hashtable, LinkedHashMap, & LinkedHashSet use hashing.
  • An appropriate hashCode() override sticks to the hashCode() contract.
  • An efficient hashCode() override distributes keys evenly across its buckets.
  • An overridden equals() must be at least as precise as its hashCode() mate.
  • 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).

In addition if you implement equals and hashcode the transient fields (if any) must be treated properly.

The Commons have nice implementation for EqualsBuilder and HashcodeBuilder. They are available in Coomons Lang http://commons.apache.org/lang/

I use them whenevr I need to implement the equals and the hashcode.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜