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



是否有任何方法,使用反射来确定静态final字段是否具有'='值(以便该值在访问时内联),或者其值是否由静态初始化器分配?如果字段确实有值,是否有任何方法可以在不使用字段的情况下检索该值。Get方法(因此导致静态初始化器被执行)?

只有当它是一个编译时常量时,该字段才会被"内联"——参见JLS中的详细定义。

所以在声明时赋值是不够的。虽然这是一个有效的声明,但它不是编译时常数:

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

仅通过反射不能确定字段是如何初始化的。

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

您不能通过反射来做到这一点,但是您可以使用字节码工程库来做到这一点,例如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

相关内容

  • 没有找到相关文章

最新更新