【问题标题】:Accessing Java static final variable value through reflection通过反射访问Java静态最终变量值
【发布时间】:2009-05-11 21:23:02
【问题描述】:

Java静态final类变量的值可以通过反射获取吗?

【问题讨论】:

    标签: java reflection


    【解决方案1】:

    我猜这取决于类型和编译器(再想一想,最好不要!)。 Sun 的编译器内联原始常量,但我不知道它们是否完全从类中删除了条目。我会找出答案的。

    编辑:是的,即使它们是内联的,您仍然可以访问它们。测试类:

    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));
            }
        }
    }
    

    输出:

    常量_INT:100 CONST_STRING:字符串 CONST_OBJECT: xyz

    javap -c 输出:

    编译自“ReflectionConstantTest.java” 公共类从头开始.ReflectionConstantTest 扩展 java.lang.Object{ public scratch.ReflectionConstantTest(); 代码: 0:aload_0 1:调用特殊#1; //方法 java/lang/Object."":()V 4:返回 public static void main(java.lang.String[]) 抛出 java.lang.Exception; 代码: 0:双向推 100 2:istore_1 3:最不发达国家#2; //字符串字符串 5:astore_2 6:获取静态#3; //字段 CONST_OBJECT:Ljava/lang/Object; 9:astore_3 10:ldc_w #4; //类从头开始/ReflectionConstantTest 13:调用虚拟#5; //方法java/lang/Class.getDeclaredFields:()[Ljava/lang/reflect/Field; 16:4号店 18:加载 4 20:数组长度 21:istore 5 23:图标st_0 24:istore 6 26:加载 6 28:加载 5 30: if_icmpge 90 33:加载 4 35:加载 6 37:加载 38:商店 7 40:加载 7 42:图标st_1 43:调用虚拟#6; //方法 java/lang/reflect/Field.setAccessible:(Z)V 46:得到静态#7; //字段 java/lang/System.out:Ljava/io/PrintStream; 49:新#8; //类 java/lang/StringBuilder 52:重复 53:调用特殊#9; //方法 java/lang/StringBuilder."":()V 56:加载 7 58:调用虚拟#10; //方法 java/lang/reflect/Field.getName:()Ljava/lang/String; 61:调用虚拟#11; //方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 64:最不发达国家#12; //细绳 : 66:调用虚拟#11; //方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 69:加载 7 71: 常量空值 72:调用虚拟#13; //方法java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object; 75:调用虚拟#14; //方法java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 78:调用虚拟#15; //方法 java/lang/StringBuilder.toString:()Ljava/lang/String; 81:调用虚拟#16; //方法java/io/PrintStream.println:(Ljava/lang/String;)V 84:iinc 6、1 87:转到 26 90:返回 静止的 {}; 代码: 0:新#8; //类 java/lang/StringBuilder 3:重复 4:最不发达国家#17; //字符串xyz 6:调用特殊#18; //方法java/lang/StringBuilder."":(Ljava/lang/String;)V 9:静置#3; //字段 CONST_OBJECT:Ljava/lang/Object; 12:返回 }

    您可以看到CONST_INT 是内联的,但CONST_STRINGCONST_OBJECT(当然)不是。然而CONST_INT 仍然可以通过反射获得。

    【讨论】:

    • 这解决了我的问题,谢谢!我很好奇为什么我们必须调用 f.setAccessible(true)。一开始就无法访问静态修饰符有什么意义?
    • @gsingh2011:唯一必要的原因是证明即使是私有常量也可以通过反射访问(您可能会观察到示例中的三个常量被声明为私有)。公共常量不需要设置为可访问的,因为它们已经可以访问了。
    • 啊,我明白了。我刚刚意识到我的问题发生了,因为我没有为我的字段提供公共/私有修饰符,然后将我的代码重构为包。无论如何感谢您的回复。
    【解决方案2】:

    是的。 (只是没有静态、实例这样的东西。它是静态的、非实例。)

    > If the underlying field is a static field, the obj argument is ignored; it may be null.

    (包括标准警告,大多数使用反射都是一个坏主意)

    【讨论】:

      【解决方案3】:

      如果您的项目允许使用开源库,您可以使用

      FieldUtils.readDeclaredStaticField

      public class Test {
          public final static String CONSTANT="myConstantValue";
      }
      

      在另一个类中你可以使用:

      Object value = FieldUtils.readDeclaredStaticField(Test.class, "CONSTANT");
      System.out.println(value);
      

      您将在控制台中看到“myConstantValue”。

      【讨论】:

        【解决方案4】:

        仅获取名称和值不需要 setAccessible(true)。当您必须处理接口中声明的常量并需要符号名称时,这是一个有用的示例:

        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);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-10
          • 2010-10-15
          • 1970-01-01
          • 2018-11-09
          相关资源
          最近更新 更多