I have a question about final variables in java and I have written a short code to demonstrate the issue. The Language Specification of java8 states that:
Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. Language Specification
To investigate further I have tried out three things in a small example code. The first thing I tried out was to create an object of the type Integer
and assign non final reference to it. Then I assigned a final reference to it as well. In the second experiment I did the same with primitive int
. Both experiments lead to the same result of me not being allowed by the compiler to increment the final reference, but being allowed to increment the non final reference and in the Output only the non final variable got incremented.
In my third experiment I used a List and assigned, again, a non final and a final reference to the List. Here I was allowed to use the final and the non final reference to call add()
and in both references the size was updated.
My test-code:
public void testFunction () {
Integer nonFinalInteger = 4;
final Integer finalInteger = nonFinalInteger;
nonFinalInteger++;
//Compiler shows error
//finalInteger++;
System.out.println("nonFinal Integer: " + nonFinalInteger);
System.out.println("final Integer: " + finalInteger + "\n");
int nonFinalInt = 4;
final int finalInt = nonFinalInt;
nonFinalInt++;
//Compiler shows error
//finalInt++;
System.out.println("nonFinal primitive int: " + nonFinalInt);
System.out.println("final primitive int: " + finalInt + "\n");
List<String> nonFinalVar = new ArrayList<String>();
final List<String> finalVar = nonFinalVar;
finalVar.add("Hello");
//Compiler does not show error
nonFinalVar.add("World");
System.out.println("nonFinal List Size: " + nonFinalVar.size());
System.out.println("final List Size: " + finalVar.size() + "\n");
}
Output:
nonFinal Integer: 5
final Integer: 4
nonFinal primitive int: 5
final primitive int: 4
nonFinal List Size: 2
final List Size: 2
My question is now: Is there a way to protect the state of the object without having to change the code of its class? Lets say we stay in the context that there is a List
, where you should not be allowed to add or delete elements. Is it possible to mark the List in a way, so that the compiler would show an error (or at least some kind of warning)?
Edit:
It seems I have caused some confusion with using arrays in the example. My question should refer to any kind of objects, hence I did not put in List in the question or the tags. What I meant was not to tell the compiler that updating the reference is forbidden, I just wanted to know if there was a way of implicitly telling the compiler to reject the calling of functions that may change the state of the object.
Currently the idea with the wrapper class seems to be the most appealing one, even though it still lacks one thing for me: It would not stop me or other people to change the state of the object completely. Final variables always have this "do not touch" trait I am looking here for.