Sometimes, when a variable is declared final
, it is believed to be immutable. If the variable is a primitive type, declaring it final
means that its value cannot be subsequently changed. However, if the variable is a reference to a mutable object, the object's contained data that appears to be immutable, may actually be mutable. Consider for For example, a final
method parameter that is a reference to an object. The argument to this method uses pass-by-value to copy the reference but the referenced data remains mutable.
...
In this noncompliant code example, the values of instance fields a
and b
can be changed even after their initialization. When an object reference is declared final
, it only signifies that the reference cannot be changed, whereas the referenced contents that it refers to can still be.
Code Block | ||
---|---|---|
| ||
class FinalClass{
private int a;
private int b;
FinalClass(int a, int b){
this.a = a;
this.b = b;
}
void set_ab(int a, int b){
this.a = a;
this.b = b;
}
void print_ab(){
System.out.println("the value a is: "+ this.a);
System.out.println("the value b is: "+ this.b);
}
}
public class FinalCaller {
public static void main(String[] args) {
final FinalClass fc = new FinalClass(1,2);
fc.print_ab();
//now we change the value of a,b.
fc.set_ab(5, 6);
fc.print_ab();
}
}
|
...
If a
and b
have to be kept immutable after their initialization, the simplest approach is to declare them as final
. However, this requires the elimination of the setter method set_ab()
.
Code Block | ||
---|---|---|
| ||
private final int a; private final int b; void set_ab(int a, int b){ //But now the compiler complains about set_ab method this.a = a; this.b = b; } |
...
Compliant Solution
This compliant solution provides a clone()
method in the class and does not require the elimination of the setter method. The clone()
method can be used to get returns a copy of the original object. This new object can be freely used without affecting the original object. Using the clone()
method allows the class to remain mutable. (OBJ36-J. Provide mutable classes with a clone method to allow passing instances to untrusted code safely)
Code Block | ||
---|---|---|
| ||
final public class NewFinal implements Cloneable { private int a; private int b; NewFinal(int a, int b){ this.a = a; this.b = b; } void print_ab(){ System.out.println("the value a is: "+this.a); System.out.println("the value b is: "+this.b); } void set_ab(int a, int b){ this.a = a; this.b = b; } public NewFinal clone() throws CloneNotSupportedException{ NewFinal cloned = (NewFinal) super.clone(); return cloned; } } public class NewFinalCaller { public static void main(String[] args) { final NewFinal nf = new NewFinal(1,2); nf.print_ab(); //get the copy of original object try { NewFinal nf2 = nf.clone(); // change the value of a,b of the copy. nf2.set_ab(5, 6); // original value will not be changed nf.print_ab(); } catch (CloneNotSupportedException e) { /* Forward to handler */ } } } |
...
Another common mistake is to use a public static final
array. Clients can trivially modify the contents of the array (although they are unable to change the array itself, as it is final
).
Wiki Markup |
---|
WithIn this noncompliant code declaration, example, the elements of the {{SOMETHINGSitems\[1\]}} array, etc. can be modified by clients of the codeare modifiable. |
Code Block | ||
---|---|---|
| ||
public static final SomeType String[] SOMETHINGSitems = { ... }; |
Compliant Solution
This compliant solution first defines a private
array and then provides a public
method that returns a copy of the array.
Code Block | ||
---|---|---|
| ||
private static final SomeType String[] SOMETHINGSitems = { ... }; public static final SomeType String[] somethings() { return SOMETHINGSitems.clone(); } |
Now As a result, the original array values cannot be modified by a client.
...
An alternative approach is to have declare a private
array from which a public
immutable list is constructed:.
Code Block | ||
---|---|---|
| ||
private static final SomeType String[] THE_THINGSitems = { ... }; public static final List<SomeType> SOMETHINGSitemsList = Collections.unmodifiableList(Arrays.asList(THE_THINGSitems)); |
Now, neither Neither the original array values nor the public
list can be modified by any a client.
Risk Assessment
Using final
to declare the reference to a mutable object is a potential security risk potentially misleading because the contents of the object can still be changed.
...