Java Reference
In-Depth Information
#1 value = 101
#2 value = 207
The output shows that the
IntHolderWrapper
class is mutable. Two calls to its
getValue()
method return
different values. The culprit is its
getIntHolder()
method. It returns the instance variable
valueHolder
, which is a
reference variable. Note that the
valueHolder
instance variable represents an object of the
IntHolder
class, which
makes up the state of an
IntHolderWrapper
object. If the object that
valueHolder
reference variable references is
changed, the state of
IntHolderWrapper
is changed, too. Since the
IntHolder
object is mutable, you should not return
its reference to the client from the
getIntHolder()
method. The following two statements change the state of the
object from the client code:
IntHolder holder = ihw.getIntHolder(); /* Got hold of instance variable */
holder.setValue(207); /* Change the state by changing the instance variable's state */
Note that the designer of the
IntHolderWrapper
class missed the point when he returned the
valueHolder
reference, that even though there is no direct way to change the state of the
IntHolderWrapper
class, it can be
changed indirectly.
How do you correct the problem? The solution is easy. In the
getIntHolder()
method, make a copy of the
valueHolder
object and return the reference of the copy instead of the instance variable itself. This way, if the client
changes the value, it will be changed only in client's copy, not in the copy held by
IntHolderWrapper
object.
Listing 7-20 has the correct immutable version of the
IntHolderWrapper
class, which you call
IntHolderWrapper2
.
Listing 7-20.
A Modified, Immutable Version of the IntHolderWrapper Class
// IntHolderWrapper2.java
package com.jdojo.object;
public class IntHolderWrapper2 {
private final IntHolder valueHolder;
public IntHolderWrapper2(int value) {
this.valueHolder = new IntHolder(value);
}
public IntHolder getIntHolder() {
// Make a copy of valueHolder
int v = this.valueHolder.getValue();
IntHolder copy = new IntHolder(v);
// Return the copy instead of the original
return copy;
}
public int getValue() {
return this.valueHolder.getValue();
}
}