【问题标题】:Using reflection, can I determine if a Java static final field will be in-lined?使用反射,我可以确定 Java 静态最终字段是否会被内联?
【发布时间】:2015-09-10 10:28:28
【问题描述】:

有什么方法可以使用反射来确定静态最终字段是否具有“=”值(以便在访问时内联该值)或者其值是否由静态初始化程序分配? 如果该字段确实有一个值,是否有任何方法可以在不使用 Field.get 方法的情况下检索该值(并因此导致执行静态初始化程序)?

【问题讨论】:

    标签: java reflection field


    【解决方案1】:

    只有当它是编译时常量时,该字段才会被“内联” - 请参阅JLS 中的冗长定义。

    因此在声明时分配它是不够的。 这不是一个编译时常量,虽然是一个有效的声明:

    static final int INT_CONST = compute();
    
    static int compute() {
        return 5;
    }
    

    仅通过反射,您无法确定该字段是如何初始化的。

    要访问类字段的任何值,需要先加载该类,因此您无法阻止静态初始化程序运行。

    【讨论】:

      【解决方案2】:

      你不能通过反射来做到这一点,但你可以使用像ASM这样的字节码工程库来做到这一点:

      public class AsmTest {
          static final int a = 2; // constant
          static final String b = "string"; // constant
          static final String c = "foo "+"bar"; // constant: concatenation is allowed
          static final String d = " foobar ".trim(); // not constant: method called
      
          public static Object getFieldConstantValue(Class<?> clazz, final String field) {
              try(InputStream is = clazz.getResourceAsStream(clazz.getSimpleName()+".class")) {
                  final Object[] value = {null};
                  new ClassReader(is).accept(new ClassVisitor(Opcodes.ASM5) {
                      @Override
                      public FieldVisitor visitField(int access, String name, String desc,
                              String sig, Object val) {
                          if(name.equals(field))
                              value[0] = val;
                          return null;
                      }
                  }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
                  return value[0];
              } catch (IOException e) {
                  throw new RuntimeException(e);
              }
          }
      
          public static void main(String[] args) {
              for(String name : new String[] {"a", "b", "c", "d"}) {
                  System.out.println(name+"="+getFieldConstantValue(AsmTest.class, name));
              }
          }
      }
      

      输出:

      a=2
      b=string
      c=foo bar
      d=null
      

      【讨论】:

      • 感谢您,ASM 听起来是个不错的选择。我假设 ASM 代码不会导致静态初始化程序的执行?
      • @RobertSales,不,它只是将其读取为byte[] 数组。这样它就可以读取任何类,即使它根本没有加载到您的应用程序中。
      猜你喜欢
      • 2011-03-19
      • 2012-06-26
      • 1970-01-01
      • 2014-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多