0

I was going through this question Why would one declare an immutable class final in Java?

I understood this Answer but need a code example.

I wrote it but has some doubts and would appreciate if someone can help.

    public class Immutable {
            private final int value;

            public Immutable(int value) {
                this.value = value;
            }

            public int getValue() {
                return value;
            }

            public boolean equals(Object obj) { 
                return (obj instanceof Immutable 
                          && getValue() == ((Immutable) obj).getValue());
                }

            public int hashCode() { 
                  int hash = 1;
                  hash = hash * 31 + value;
                  return hash;
                }
        }

        public class Mutable extends Immutable {
            private int realValue;

            public Mutable(int value) {
                super(value);

                realValue = value;
            }

            public int getValue() {
                return realValue;
            }
            public void setValue(int newValue) {
                realValue = newValue;
            }
        }

// test class main()
   Mutable key = new Mutable(30);
   Hashtable<Immutable, String> ht = new Hashtable<Immutable,String>();

   ht.put(new Immutable(10), "10");
   ht.put(new Immutable(20), "20");
   ht.put(key, "30");

   System.out.println("Hashcode : "+key.hashCode()+", \tKey : "+key.getValue()+" => Value : "+ht.get(key));

   key.setValue(40);
   System.out.println("Hashcode : "+key.hashCode()+", \tKey : "+key.getValue()+" => Value : "+ht.get(key));

Output : 
Hashcode : 61,  Key : 30 => Value : 30
Hashcode : 61,  Key : 40 => Value : 30

I can't relate the Answer given with this Code.

Community
  • 1
  • 1
maddy man
  • 89
  • 4
  • 10

1 Answers1

0

Your code is working because your hashCode method is using the final field value from the Immutable class directly instead of using the getter for the field. This field is not changed when using the setValue method from Mutable as this method works on the realValue field only.

If you change hashCode to

public int hashCode() { 
    int hash = 1;
    hash = hash * 31 + getValue(); // use getter here
    return hash;
}

You will observe the undesired behavior as described in this answer.

It is important to note that your code is actually breaking the equals contract. As two instances of Mutable may be equal to each other but have different hashcodes...

Community
  • 1
  • 1
dpr
  • 10,591
  • 3
  • 41
  • 71
  • I updated the equals method as : `public boolean equals(Object obj) { return (obj instanceof Immutable && obj.hashCode() == this.hashCode() && getValue() == ((Immutable) obj).getValue()); }` – maddy man Jun 26 '16 at 12:48
  • This will fulfill the equals contract. However this is not really best practice. Consider reading [this question/answer](http://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java) on how to implement proper equals and hashcode methods. – dpr Jun 26 '16 at 18:48