Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can final object be modified?

Tags:

java

final

I came across the following code in a code base I am working on:

public final class ConfigurationService {     private static final ConfigurationService INSTANCE = new ConfigurationService();     private List providers;      private ConfigurationService() {         providers = new ArrayList();     }      public static void addProvider(ConfigurationProvider provider) {         INSTANCE.providers.add(provider);     }      ... 

INSTANCE is declared as final. Why can objects be added to INSTANCE? Shouldn't that invalidate the use of final. (It doesn't).

I'm assuming the answer has to do something with pointers and memory but would like to know for sure.

like image 808
Matt McCormick Avatar asked Mar 12 '10 19:03

Matt McCormick


People also ask

Can a final int be modified?

Variables marked as final can't be reassigned.Once a final variable is initialized, it can't be altered.

Can you modify a final set in Java?

Final variable in Java cannot be changed. Once if we have assigned the final variable it can not be changed it is fixed. but if you have declare a blank final variable then you can assign value to it only in constructor. also using hiearchical instances can come handy.

Can we change final value?

The only difference between a normal variable and a final variable is that we can re-assign the value to a normal variable but we cannot change the value of a final variable once assigned.

What happens if a method has the final keyword as modifier?

The final keyword restricts the access of the user to modify the data. A variable that is declared as a final variable is a constant throughout the program and its value cannot be changed whatsoever. Method that is declared final cannot be overridden by any other subclasses.


2 Answers

final simply makes the object reference unchangeable. The object it points to is not immutable by doing this. INSTANCE can never refer to another object, but the object it refers to may change state.

like image 162
Sean Owen Avatar answered Sep 29 '22 10:09

Sean Owen


Being final is not the same as being immutable.

final != immutable

The final keyword is used to make sure the reference is not changed ( that is, the reference it has can't be substituted with a new one )

But, if the attribute is self is modifiable it is ok to do what you have just described.

For instance

class SomeHighLevelClass {     public final MutableObject someFinalObject = new MutableObject(); } 

If we instantiate this class, we won't be able to assign other value to the the attribute someFinalObject because it is final.

So this is not possible:

.... SomeHighLevelClass someObject = new SomeHighLevelClass(); MutableObject impostor  = new MutableObject(); someObject.someFinal = impostor; // not allowed because someFinal is .. well final 

But if the object it self is mutable like this:

class MutableObject {      private int n = 0;       public void incrementNumber() {          n++;      }      public String toString(){          return ""+n;      } }   

Then, the value contained by that mutable object may be changed.

SomeHighLevelClass someObject = new SomeHighLevelClass();  someObject.someFinal.incrementNumber(); someObject.someFinal.incrementNumber(); someObject.someFinal.incrementNumber();  System.out.println( someObject.someFinal ); // prints 3 

This has the same effect that your post:

public static void addProvider(ConfigurationProvider provider) {     INSTANCE.providers.add(provider); } 

Here you are not changing the value of INSTANCE, your are modifying its internal state ( via, providers.add method )

if you want to prevent that the class definition should be changed like this:

public final class ConfigurationService {     private static final ConfigurationService INSTANCE = new ConfigurationService();     private List providers;      private ConfigurationService() {         providers = new ArrayList();     }     // Avoid modifications           //public static void addProvider(ConfigurationProvider provider) {     //    INSTANCE.providers.add(provider);     //}     // No mutators allowed anymore :)  .... 

But, it might not make much sense :)

By the way, you also have to synchronize access to it basically for the same reason.

like image 39
OscarRyz Avatar answered Sep 29 '22 12:09

OscarRyz