-3

I am going through the java.lang.Object API which states the below the point on objects equality: https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

public boolean equals(Object obj):

It is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

Now to test the above theory on "equal objects must have equal hash codes", I have come up with the below simple code:

public class Product {

    private String name;

    public Product(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        //always returns true for all objects
        return true;
    }

    @Override
    public int hashCode() {
        //Different hascodes for different objects
        if(name.equals("PRODUCT1")) {
            return 10;
        } else {
            return 20;
        }
    }

    public static void main(String[] args) {
        Product p1 = new Product("PRODUCT1");
        Product p2 = new Product("PRODUCT2");

        if(p1.equals(p2)) {
            System.out.println(" p1 p2 are equal **** ");
        } else {
            System.out.println(" p1 p2 are NOT equal **** ");
        }

    HashSet<Product> set = new HashSet<>();
    set.add(p1);
    set.add(p2);
    System.out.println(" size :"+set.size());
    }
}

Output:

p1 p2 are equal ****

size : 2

So, isn't the above code violating/contradicting the API statement "equal objects must have equal hash codes" i.e., equal objects need NOT have same hashcodes?

I understand that the compiler can't validate this contract, but doesn't JVM at runtime complain any error/warning stating that equal objects should have different hashcodes?

Am I correct in understanding that the 'equal objects should have same hashcodes' is strictly followed only for performance improvements for huge/large sets of object comparisons and no JRE (no one) complains about the same (except losing performance)? If not, can you help with an example (using hashsets or hashmaps or any hash...) which throws an error by violating the contract along with the error message?

lospejos
  • 1,976
  • 3
  • 19
  • 35
Vasu
  • 21,832
  • 11
  • 51
  • 67
  • 6
    Obviously, you `equals()` method returns `true` all the time. What else you expect ? – ThisaruG Oct 09 '16 at 10:57
  • 9
    You wrote an implementation that violates the contract, so your implementation violates the contract. What do you want us to say? – Boris the Spider Oct 09 '16 at 10:57
  • You are writing about principle of relations between equals and hashcode. It is not compiler to be responsible for using this principle - it is a developer that has to stick to this. – bart.s Oct 09 '16 at 11:01
  • 1
    Try this code to confirm: HashSet hs = new HashSet(); hs.add(p1); hs.add(p2); System.out.println(hs.size()); – Kacper Oct 09 '16 at 11:01
  • Kacper: Nothing strange has happend when I tried to place 2 products in set, the size is 2 objects – Vasu Oct 09 '16 at 11:07
  • @BoristheSpider: My question is about what is the runtime error that I will see when I implement the contract wrongly which has not been addressed in the other question. – Vasu Oct 09 '16 at 11:24
  • @developer Undefined Behaviour TM. Might work fine; might cause an error; might destroy the universe. Don't do it. – Boris the Spider Oct 09 '16 at 11:25
  • @BoristheSpider: Can you read my question AGAIN please ? Unfortunately, there is NO straight answer to this question with a clear example explaining the error, but simply has been marked as duplicate – Vasu Oct 09 '16 at 11:35
  • I can reopen the question if you wish; but your question is ... unanswerable. You seem to know that there is a contract that you are violating, you further seem to know that violating the contract produces UB - now you want us to define the UB? Your edit, on the other hand, is ridiculous. It is not for performance reasons; obviously not! The contract is there so that `HasMap` and `HashSet` **any other code** that depends on this contract can work correctly. – Boris the Spider Oct 09 '16 at 12:00
  • For example; can engines are designed on the contract that the fuel put into them burns with certain properties (octane level, water content); you are asking what happens when this contract is violated - what happens if you fill your car with water? Fill your petrol car with diesel? Fill any car with nitroglycerin? **Nothing good**. What exactly happens? **Undefined Behaviour**. – Boris the Spider Oct 09 '16 at 12:04
  • Just remove `set.add(p2);` and see what `set.contains(p2)` returns. I wonder why you think that there would be an exeception. You're violating a contract, not any JLS rule, so if you think you know what you're doing, then you can do that. Neither the compiler or the JVM will stop you here. – Tom Oct 09 '16 at 12:14
  • @Tom it'll work fine as the `hashCode()` values are different - there's nothing in `p2`'s bucket - we don't get as far as `equals()`. When it comes to `HashMap` things are rarely that simple... – Boris the Spider Oct 09 '16 at 12:21

1 Answers1

4

Your code violates the contract, but this contract can't be verified by the compiler. This is why you don't get any compile time error message.

You might get incorrect behavior or runtime errors when inserting instances of this class in sets or maps.

Stefan Haustein
  • 18,427
  • 3
  • 36
  • 51
  • I know that this is THE contract, But, what/where will be the error/warning if I violate this like above ?Can you provide an example ? – Vasu Oct 09 '16 at 11:38
  • 2
    Example: If the hash code is different for two "equal" objects, they will get sorted into different buckets in a hash set, leading to inconsistencies between equals() and contains() – Stefan Haustein Oct 09 '16 at 17:27