Can the value of a Java static final class variable be retrieved through reflection?
4 Answers
I would guess that it depends on the type and the compiler (on second thought, it had sure better not!). Sun's compiler inlines primitive constants, but I don't know if they remove the entry from the class entirely. I'll find out.
Edit: Yes, you can still access them even if they are inlined. Test class:
public class ReflectionConstantTest {
private static final int CONST_INT = 100;
private static final String CONST_STRING = "String";
private static final Object CONST_OBJECT = new StringBuilder("xyz");
public static void main(String[] args) throws Exception {
int testInt = CONST_INT;
String testString = CONST_STRING;
Object testObj = CONST_OBJECT;
for (Field f : ReflectionConstantTest.class.getDeclaredFields()) {
f.setAccessible(true);
System.out.println(f.getName() + ": " + f.get(null));
}
}
}
Output:
CONST_INT: 100 CONST_STRING: String CONST_OBJECT: xyz
javap -c
output:
Compiled from "ReflectionConstantTest.java" public class scratch.ReflectionConstantTest extends java.lang.Object{ public scratch.ReflectionConstantTest(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]) throws java.lang.Exception; Code: 0: bipush 100 2: istore_1 3: ldc #2; //String String 5: astore_2 6: getstatic #3; //Field CONST_OBJECT:Ljava/lang/Object; 9: astore_3 10: ldc_w #4; //class scratch/ReflectionConstantTest 13: invokevirtual #5; //Method java/lang/Class.getDeclaredFields:()[Ljava/lang/reflect/Field; 16: astore 4 18: aload 4 20: arraylength 21: istore 5 23: iconst_0 24: istore 6 26: iload 6 28: iload 5 30: if_icmpge 90 33: aload 4 35: iload 6 37: aaload 38: astore 7 40: aload 7 42: iconst_1 43: invokevirtual #6; //Method java/lang/reflect/Field.setAccessible:(Z)V 46: getstatic #7; //Field java/lang/System.out:Ljava/io/PrintStream; 49: new #8; //class java/lang/StringBuilder 52: dup 53: invokespecial #9; //Method java/lang/StringBuilder."":()V 56: aload 7 58: invokevirtual #10; //Method java/lang/reflect/Field.getName:()Ljava/lang/String; 61: invokevirtual #11; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 64: ldc #12; //String : 66: invokevirtual #11; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 69: aload 7 71: aconst_null 72: invokevirtual #13; //Method java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object; 75: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 78: invokevirtual #15; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 81: invokevirtual #16; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 84: iinc 6, 1 87: goto 26 90: return static {}; Code: 0: new #8; //class java/lang/StringBuilder 3: dup 4: ldc #17; //String xyz 6: invokespecial #18; //Method java/lang/StringBuilder."":(Ljava/lang/String;)V 9: putstatic #3; //Field CONST_OBJECT:Ljava/lang/Object; 12: return }
You can see that CONST_INT
is inlined, but CONST_STRING
and CONST_OBJECT
(of course) are not. Yet CONST_INT
is still available reflectively.

- 188,989
- 46
- 291
- 292
-
This solved my problem, thanks! I'm curious as to why we have to call f.setAccessible(true). What's the point of having static modifiers not accessible in the first place? – gsgx Feb 07 '12 at 16:31
-
@gsingh2011: The only reason that's necessary is to demonstrate that even private constants can be accessed through reflection (you may observe that the three constants in the example are declared private). Public constants would not need to be set accessible, since they are already accessible. – Michael Myers Feb 07 '12 at 17:17
-
Ahh, I see. I just realized my problem occurred because I did not provide a public/private modifier to my field, and then refactored my code into packages. Thanks anyway for the response. – gsgx Feb 07 '12 at 17:28
Yes. (Only there is no such thing as static, instance. It's static, non-instance.)
> If the underlying field is a static field, the obj argument is ignored; it may be null.
(include standard warning that most uses of reflection are a bad idea)

- 145,806
- 30
- 211
- 305
If open-source libraries are allowed on your project you can use
FieldUtils.readDeclaredStaticField
public class Test {
public final static String CONSTANT="myConstantValue";
}
In another class you can use:
Object value = FieldUtils.readDeclaredStaticField(Test.class, "CONSTANT");
System.out.println(value);
You will see "myConstantValue" in the console.

- 689
- 8
- 21
Just getting the name and value does not require setAccessible(true). Here's a useful example when you have to deal with constants declared in an interface, and want the symbolic names:
interface Code {
public static final int FOO = 0;
public static final int BAR = 1;
}
...
try {
for (Field field : Code.class.getDeclaredFields()) {
String name = field.getName();
int value = field.getInt(null);
System.out.println(name + "=" + value);
}
}
catch (IllegalAccessException e) {
System.out.println(e);
}

- 737
- 8
- 8