Accessing Java static final variable value through reflection

前端 未结 4 1901
轮回少年
轮回少年 2020-11-27 18:13

Can the value of a Java static final class variable be retrieved through reflection?

相关标签:
4条回答
  • 2020-11-27 18:55

    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)

    0 讨论(0)
  • 2020-11-27 18:58

    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.

    0 讨论(0)
  • 2020-11-27 19:02

    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);
    }
    
    0 讨论(0)
  • 2020-11-27 19:13

    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.

    0 讨论(0)
提交回复
热议问题