0

While an array reference can be declared as final, the elements of the array cannot.

Similarly, while an object reference may be declared as a final field, the object to which it refers may still be mutable. Why so?

raina77ow
  • 103,633
  • 15
  • 192
  • 229
Farhan stands with Palestine
  • 13,890
  • 13
  • 58
  • 105
  • What would you do if you really only wanted the variable to be immutable? – Sotirios Delimanolis Sep 27 '14 at 18:43
  • 1
    An answer giving "**THE** (undoubted) reason" will be hard to find here, unless you talk to the language designers. Considering the added language complexity and possible ambiguities (like an array that is stored as a "deeply final" array in one class, and as a "not-deeply final" array in another class), I'm glad that they accepted the reduced expressiveness of the language, and avoided the "const correctness hell" that we know from C++... – Marco13 Sep 27 '14 at 18:52

3 Answers3

1

Declaring an object as const, rather than the pointer has a dramatic impact. In order to ensure the immutability, it is not enough that the code containing the const declaration must not modify fields through this reference, it is not allowed to invoke any methods on that object which could modify the object. Therefore, every method must be marked as either, potentially modifying the this instance or guaranteed not to modify it.

Note that the const attribute is still not a property of the object itself. There may be code having a non-const reference to the same object being allowed to modify it. Such code may pass the non-const reference to code accessing the object through a reference with a const modifier but not vice versa.

So this implies that the const object must not be assigned to another variable which lacks the const modifier for the referenced object. This formal restriction applies not only to fields but to all local variables, parameters, and return types.

Now think of the beginning of the nineties when there was no Generics in Java. The Collection classes all simply store Objects. In that scenario, a support for a const modifier would imply that such const objects can never be stored in any collection as there can be no guaranty that the same object is not retrieved from that collection (as plain Object) and assigned to a non-const variable.

Starting with Java 8 you can annotate any type use, including the Generic element type of a Collection or the this reference an instance method receives. This allows to implement such a const feature as a @Const type annotation using an audit tool verifying the const correctness of the code using the annotation. But since it is unlikely that all the existing Java code’s methods suddenly become marked as const safe or unsafe, it is unlikely that such a feature becomes added to the standard today.

Holger
  • 285,553
  • 42
  • 434
  • 765
1

The reason that final only impacts the actual object instead of the object's properties likely ties back to the fact that Java is pass-by-value.

The definition of a final variable, per the Java Language Specification, gives us this tidbit, emphasis mine:

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.

This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.

The value of an object reference is the actual location in memory to it, analogous to a pointer. What final does is state that this pointer cannot* be changed through normal interactions of the program.

If you want immutable references, then use an immutable container. An array is not immutable (as you correctly observe, its values can be changed at will).

*: You can do a lot with reflection and Field#setAccessible() if you really wanted to, but this utterly defeats the purpose.

Community
  • 1
  • 1
Makoto
  • 104,088
  • 27
  • 192
  • 230
0

If final would have been a recursive modifier (which is what I think you mean), this would have been horibble. It means that every object pointed by a final object would be immutable, and so on, and you can end up with the entire memory unmodifyable...

If, for some reason, you want the fields of some instances of your class to be modifyable, while others to have immutable fields, your should probably consider declaring a subclass, or hide private fields with smart setters.

Elist
  • 5,313
  • 3
  • 35
  • 73