当预期不可变对象时,可变子类对象如何导致问题的代码示例

Code Example for how a Mutable subclass object can cause issue when Immutable object is expected

我正在回答这个问题 Why would one declare an immutable class final in Java?

我理解这个 Answer 但需要一个代码示例。

我写了它,但有一些疑问,如果有人能提供帮助,我将不胜感激。

    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

我无法将给出的答案与此代码联系起来。

您的代码可以正常工作,因为您的 hashCode 方法直接使用 Immutable class 的最终字段 value,而不是使用 getter场。使用 Mutable 中的 setValue 方法时不会更改此字段,因为此方法仅适用于 realValue 字段。

如果将 hashCode 更改为

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

您将观察到 this answer 中描述的不良行为。

请务必注意,您的代码实际上违反了平等契约。由于 Mutable 的两个实例可能彼此相等但具有不同的哈希码...