0

According to the hashCode/equals contract if two objects are equal the must have the same hashCode - at least it is how I know it. Consider the following implementation:

package Happy;

import java.time.LocalDate;

class MyClass
{
    private int id;

    public int getId()
    {
        return id;
    }

    public MyClass(int id)
    {
        this.id = id;
    }

    public int hashCode()
    {
        return LocalDate.now().getYear() + getId();
    }

    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        MyClass other = (MyClass) obj;
        if (hashCode() != other.hashCode())
            return false;
        return true;
    }
}

public class HappyNewYear
{
    public static void main(String[] args) {
        MyClass my = new MyClass(0);
        if (my.hashCode() != my.hashCode()) System.out.println("Happy New Year!");
    }
}

With little modifications we can get a less extreme variant:

public int hashCode()
{
    return return (int) (System.nanoTime() + getId());
}

I tested it (not with the getYear though), and the condition were true (the hashCodes were not equal).

Is it legal if the hashCode changes over time even if the object's fields are unmodified? I could not find any resources about this specific implementation. I know about the problem with collections, but my question is if the hashCode implementation is legal according to the contract/spec.

PS: It is a challenge question, I answered that it's not legal, but I am not sure since I at first look at the code, equals and hashCode are satisfiyng the simple contract.

David Szalai
  • 2,363
  • 28
  • 47
  • 1
    Yes. It is *valid / legal* but *incorrect / not-adviced*. You will get into all sorts of trouble with hash based datastructures with this approach – TheLostMind Nov 04 '15 at 10:46
  • how did you test it? since `System.nanoTime()` returns a long you are most likely creating an overflown `int`. – SomeJavaGuy Nov 04 '15 at 10:48

3 Answers3

2

It is legal (the compiler wont complain about it) but you shouldn't be doing it. HashCode should be consistent (returns the same integer value given the same key).

From the Java Docs of hashCode

the hashCode method must consistently return the same integer

Your hashCode is exactly the opposite of that.

Community
  • 1
  • 1
Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77
  • yeah, thats what I first thought, but it continues with "provided no information used in equals comparisons on the object is modified" – David Szalai Nov 04 '15 at 10:55
  • @PnDChameleon And what is with that part? It says, if a used field in the `equals` comparison changes, then the hashCode can be different. If this is not the case, then it need to remain the same. This might be true for your `equals` method, but only because it is already a bad implementation: http://stackoverflow.com/questions/7417668/java-use-hashcode-inside-of-equals-for-convenience – Tom Nov 04 '15 at 11:01
  • Oh, I misunderstood that part then. I interpreted the "provided no information" part as it is not only applies to fields, but all methods used in equals. But you're right. – David Szalai Nov 04 '15 at 11:04
  • Well, `equals` should only use fields (or their getters). Using `hashCode` there is not a good idea (discussed in the link I've posted). One generally uses each field for the hash code generation that is also used for the equality check. – Tom Nov 04 '15 at 11:07
  • @Sleiman Put in the entire statement, the way you put it here is only half the story. It will just confuse people. "Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, **provided no information used in equals comparisons on the object is modified**. This integer need not remain consistent from one execution of an application to another execution of the same application." – WalterM Nov 04 '15 at 11:15
  • @WalterM I hear u, but wanted to leave it short and reference the clear violation of the rules and a link for the docs was provided. Thx – Sleiman Jneidi Nov 04 '15 at 11:19
1

As the hashcode is used to place and then find objects that are stored in hashmaps, a class whose hashcode changes over time will make it impossible to use in a hashmap.

Breandán Dalton
  • 1,619
  • 15
  • 24
0

I think that if the .equals method fails, then the .hashcode should also fail.

That being said, it will most likely create more problem than it will ever solve if two object yesterday where considered to be equal but now they are not, because as far as the object is concerned, none of its fields where changed. (Think of systems which run for days, for instance).

I would recommend that you have the .hashcode() depend on the object itself rather than something which will change and is outside of the object. If this is not an option, you will need to document it heavily.

npinti
  • 51,780
  • 5
  • 72
  • 96