Private final - some things you can't change!

Access ! Access !

For as long as I can remember writing programs in Java. I have used the access modifiers to control access to members of my classes. It is one of the topics in the Certification test in java (SCJP, OCJP).
The table below taken from the Oracle Java Tutorials summarizes how each access modifier can restrict or expose a member of your class.
Java Access Control
Access Levels
ModifierClassPackageSubclassWorld
publicYYYY
protectedYYYN
no modifierYYNN
privateYNNN


Don't worry it is a private final variable!

I can't change its value because it is private final member of the class. Well that is not really true. There is an API for that Java Reflection. The Java Reflection API will allow you to examine and modify runtime behavior of applications in the JVM. "Reflection is powerful, but should not be used indiscriminately". In relation to the access modifiers mentioned above you can disregard it all and do as you please.

The reason why the API exist is mainly for Java Tools (debuggers and tools). Java framework may use it as well like implementing dependency injection. How to do you think Spring inject resources and components to private member variables of the class ?

Now for some code!

Here is some code sample:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class TestModifiers
{
   public static void main(String [] args){
     Person p = new Person();
     p.name = "bar"; //This line will error out
     System.out.println(p.name); //As well as this one
   }

 
}

class Person {
    private final String name = "foo";
}

Obviously line 5 and line 6 will will throw out an error. (name has private access on Person)
Please see screen shot.


Now let us try some reflection code to change some private final variable and print it.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class TestModifiers
{
  public static void setValueForPrivateFinalVariable(Person person, String newName) throws NoSuchFieldException, IllegalAccessException{
      Class classModified = person.getClass();
        Field field = classModified.getDeclaredField("name");
        field.setAccessible(true);
        // remove final modifier from field
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(person, newName);
        System.out.println(field.get(person));
  }

  public static void main(String [] args){
     Person p = new Person();
     //p.name = "bar";
    try{
     setValueForPrivateFinalVariable(p,"bar");
    }catch(Exception e){
      System.out.println(e.getMessage());
    }
     //System.out.println(p.name);
   }

 
}

class Person {
    private final String name = "foo";
}

Line 6 to 16 is the reflection code I added to set and print the private final member name in the Class person.

I was able to change the value and print it. This is a lot of code just to change a field. Performance isn't one of the strong points of the reflection API in Java.

Some JVMs will not allow you to do the reflection on classes.

The Java Reflection API is a powerful tool so use it wisely. 






Comments

Popular posts from this blog

OAuth 1.0a Request Signing and Verification - HMAC-SHA1 - HMAC-SHA256

Spark DataFrame - Array[ByteBuffer] - IllegalAurmentException

Gensim Doc2Vec on Spark - a quest to get the right Vector