0

Here is my first Class

  public class MainClass {

  public static void main(String args[])
   {
    java.util.Set s=new java.util.HashSet();
    s.add(new Integer(10));
    s.add(new Integer(1));
    s.add(new Integer(5));
    s.add(new Integer(3));
    s.add(new Integer(6));
    s.add(new Integer(9));
    s.add(new User("John",25));
    s.add(new User("John",25));
    java.util.Iterator it=s.iterator();
    while(it.hasNext())
    {
        System.out.println(it.next());
    }
   }

   }

Here is my second class

  public class User {

  String name;
  int age;

  public User(String name,int age)
  {
    System.out.println("I am in constructor");
    this.name=name;
   this.age=age;
   }

  @Override
  public boolean equals(Object obj)
   {
     System.out.println("I am in equals");
    User u=(User)obj;
    if(this.age==u.age)
    {
        return this.name.equals(u.name);
    }
    else
    {
        return false;
    }
      }

    @Override
    public int hashCode()
     {
    System.out.println("I am in hash code");
    return this.name.hashCode()+this.age;
    }

   @Override
   public String toString()
   {
     System.out.println("I am in to String");
    return String.format("Name: %s", this.name);
   }
   }

The output is

 I am in constructor
 I am in hash code
 I am in constructor
 I am in hash code
 I am in equals
 1
 I am in to String
 Name: John
 3
 5
 6
 9
 10

My question is how are these elements being compared?

TruePS
  • 493
  • 2
  • 12
  • 33
  • 1
    possible duplicate of [ordering a hashset example?](http://stackoverflow.com/questions/3380312/ordering-a-hashset-example) –  Apr 23 '14 at 11:16
  • 1
    [Have a read here](http://stackoverflow.com/a/21626965/2024761). – Rahul Apr 23 '14 at 11:16
  • Your equals method should really check before doing the cast. You are putting it in a set so it's pure luck that you don't get a class cast exception... – monocell Apr 23 '14 at 11:20
  • @monocell Could you plz explain how the above output is achieved? – TruePS Apr 23 '14 at 11:22
  • See the answer from Jakub Hr – monocell Apr 23 '14 at 11:25
  • @monocell when will i get class cast exception – TruePS Apr 23 '14 at 11:51
  • 1
    If you put a `User` object in a hash set and then an Integer which happen to have the same hashcode. `equals` should work for any object, not just object of the same type. – monocell Apr 23 '14 at 11:53
  • @monocell But this should happen only when the user class is taking integers as well because equals() compare only similar objects. – TruePS Apr 23 '14 at 11:59
  • No, as you can see in the type signature for equals it really takes any object. And given that you have a Set in which you put both User and Integer you may end up in a situation where a User and an Integer happens to have the same hashcode. In that case the hashset implementation will call one of the objects equal methods to determine if you try to add the same object twice or if there are two objects with the same hashcode. Your User.equals should be able to handle that. – monocell Apr 23 '14 at 12:03
  • @monocell but here equals method of User class is called for only User objects in general the equals method of Set will be called because we are storing values in Set. – TruePS Apr 23 '14 at 12:15
  • 1
    I'm feeling this is getting a bit of topic. I'll shut up, but please try to run the following code and see for yourself. https://gist.github.com/monocell/11213277 – monocell Apr 23 '14 at 12:29
  • @monocell I am officially confused so many people saying so many different things so I think I should just shut up – TruePS Apr 23 '14 at 13:03
  • We are all really saying the same thing. Or parts of the same thing at least, but nevermind. – monocell Apr 23 '14 at 13:04
  • @monocell but the thing is no one wanna chat with me and clear my doubts.I thought SO stands for clearing doubts and the best thing is there is no Chat room of Java users active now. – TruePS Apr 23 '14 at 13:06
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/51273/discussion-between-monocell-and-trueps) – monocell Apr 23 '14 at 13:07

2 Answers2

3

That's the order:

  1. First output is inside User constructor.
  2. Then hash is calculated to store your object inside HashSet structure, so you have an output from hashCode method
  3. It's the same as numer 1, but for the second user.
  4. It's the same as number 2, but for the second user.
  5. Because your hashCode method inside User is counted by age of the user, both users have the same hash, so equals method must be called to verify if the objects are the same. (it's because 2 objects in Java don't have to be the same even if they have the same hash code)
  6. Now you are printing all objects inside HashSet which doesn't contain any order, so you can get all the elements in random order. (keep in mind that objects inside any Set are unique)
  7. Because you overwritten toString method it prints content of the User object.

As a hint: it's not a very good idea to use raw type of any data structure in Java since 1.5 version. Have a look at generics.

Jakub H
  • 2,130
  • 9
  • 16
  • So what changes in the datatype(in above program) do you reckon? – TruePS Apr 23 '14 at 11:35
  • Regarding your fifth point in second point hashcode is calculated so why it is printing output from equals method in fifth point. – TruePS Apr 23 '14 at 11:39
  • If you really need to store 2 different objects inside HashSet, you should declare it as Set and HashSet – Jakub H Apr 23 '14 at 11:41
  • @TruePS about point numer 5: if you add any element to a hash based structure than hash code of this element is calculated, but if element with the same hash is already inside hash based structure than equals method is called to verify if you want to add the same object or different object, but with the same hash code. – Jakub H Apr 23 '14 at 11:43
  • just 1 last question I understood your answer but if I write Set and HashSet then how will I be able to store say integers,double,long etc. – TruePS Apr 23 '14 at 11:46
  • you have to declare it as Set where Object is java.lang.Object which is a base class of every object in Java. If you do it like that than you can store User, String, Integer and so on inside that kind of Set. – Jakub H Apr 23 '14 at 11:49
  • Sorry to disturb you again but if I simply write Set then what could go wrong and how? – TruePS Apr 23 '14 at 11:52
  • Have a look here: http://stackoverflow.com/questions/7885920/java-difference-between-list-and-listobject, the same things apply to the Set – Jakub H Apr 23 '14 at 12:01
  • you told me to use Set but above monocell is telling me not to use that. – TruePS Apr 23 '14 at 12:09
  • I'm not saying that. I'm saying that you should fix your equals implementation. – monocell Apr 23 '14 at 12:35
1

Every object inherits default implementations of hashCode() and equals() from java.lang.Object. That's why every object can be used in a hash-based collection.

The implementations of those two functions in Object are obviously very basic but ensure the contract of hashCode() and equals() is fulfilled, specifically the a.equals(b) ==> a.hashCode() == b.hashCode() statement.

JimmyB
  • 12,101
  • 2
  • 28
  • 44
  • @Hanoo could you plz expain how the above output is achieved? – TruePS Apr 23 '14 at 11:20
  • The order for any `HashSet` is undefined. Especially, it is not consistent. The order in which objects are put/removed, the capacity of the `HashSet`, and the distribution of hash values across the items will probably all affect the order. So there's no way to rely on any particular ordering. – JimmyB Apr 23 '14 at 11:23
  • If you're interested in all the gory details, have a look at the source code of `HashSet`. IIRC, it just uses an array of objects to store items, and, basically, the hash code of an object determines the index in the array where it should be stored/found. – JimmyB Apr 23 '14 at 11:27
  • I know that hashset doesn't return elements in a particular order I just wanna know when are hashcode and equals methods are called. – TruePS Apr 23 '14 at 11:29
  • 1
    I'm sorry, I misunderstood the point of your question. The answer however is pretty simple: First, the hash code for an object is determined, then this hash code is used to look up the approximate location where the object should be stored. If there's no object already stored at that location the new object will be put there. If there already is an object with a matching hash, the new and the old object are compared via `equals()` to determine if they are the same object. Lookup is basically the same: Hash code first, then `equals()` if necessary. – JimmyB Apr 23 '14 at 11:39
  • What do you mean by this `Lookup is basically the same: Hash code first, then equals() if necessary`.Does this means hashcode first then equals is not always the case. – TruePS Apr 23 '14 at 11:47
  • 1
    `HashCode()` is always called, and always called first. If there is no object with the same hash code already in the set then `equals()` will not be called; there's just no object to compare with. In this case `null` is returned without ever calling `equals()` on the object. It's an optimization/shortcut which works based on the contract of `hashCode()` and `equals()` I quoted above. If and only if an object with a matching hash code is already in the set, the `equals()` of the new object is called; possibly even more than once. – JimmyB Apr 23 '14 at 11:53
  • Just to correct you equals() method of the object is only called once.[Read this](http://stackoverflow.com/questions/21626823/when-hashset-call-equal-method/21626965#21626965) – TruePS Apr 23 '14 at 11:55
  • 1
    Sorry, that's not correct. What would happen if you already had two objects of equal hash code in the set and want to add a third one with the same hash code but which is not equal() to the other two? - How many times will `equals()` of the third object have to be called in this case? – JimmyB Apr 23 '14 at 11:59
  • Ok i agree with you I just have one last problem above Jakub is saying I should write Set and monocell is saying Set should not be taken.Could you plz tell me who is right? – TruePS Apr 23 '14 at 12:08
  • 1
    `Set x;` is marginally cleaner than just using `Set x;`. You should however use something like `Set` if you know that you will only be storing `MyObject`s in that set. Maybe more importantly, many/most implementations of `equals()` rely on objects of the same (super-)type to be compared and will throw a `ClassCastException` when compared to an unexpected object, which will break the use of `HashSet` and other collections. – JimmyB Apr 23 '14 at 12:16
  • You wrote in above comment `How many times will equals() of the third object have to be called in this case` but normally equals method of only Hashset will be called unless you override it?So when 3rd object with same hashcode enters then equals method of hashset will be called twice. – TruePS Apr 23 '14 at 12:19