简体   繁体   中英

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)?

The field will be "inlined" only if it's a compile time constant - see the lengthy definition in the 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 :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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