当预期不可变对象时,可变子类对象如何导致问题的代码示例
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
的两个实例可能彼此相等但具有不同的哈希码...
我正在回答这个问题 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
的两个实例可能彼此相等但具有不同的哈希码...