简体   繁体   English

使用反射,我可以确定Java静态最终字段是否内联?

[英]Using reflection, can I determine if a Java static final field will be in-lined?

Is there any way, using reflection, to determine whether a static final field has an '=' value (so that the value will be in-lined when it is accessed) or whether its value is assigned by the static initializer? 有没有办法,使用反射来确定静态最终字段是否具有'='值(以便在访问时该值将被内联)或者它的值是否由静态初始化程序赋值? If the field does have a value, is there any way to retrieve that value without using the Field.get method (and therefore causing the static initializer to be executed)? 如果该字段确实有值,是否有任何方法可以在不使用Field.get方法的情况下检索该值(从而导致执行静态初始化程序)?

The field will be "inlined" only if it's a compile time constant - see the lengthy definition in the JLS . 只有当它是编译时常量时,该字段才会被“内联” - 请参阅JLS中的冗长定义。

So it's not enough for it to be assigned at the time of declaration. 因此,在宣布时分配它是不够的。 This is not a compile-time constant, although a valid declaration: 这不是编译时常量,尽管是有效的声明:

static final int INT_CONST = compute();

static int compute() {
    return 5;
}

Just by reflection you cannot determine how the field was initialized. 只是通过反射,您无法确定字段的初始化方式。

To access any value of a class field, that class needs to be loaded first, so you cannot prevent the static initializer from running. 要访问类字段的任何值,需要首先加载该类,因此无法阻止静态初始化程序运行。

You cannot do this by reflection, but you can do this using byte-code engineering library like ASM : 你不能通过反射来做到这一点,但你可以使用像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));
        }
    }
}

Output: 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM