有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

是否有任何方法可以使用反射来确定静态final字段是否具有“=”值(以便在访问该字段时该值将以行形式显示)或其值是否由静态初始值设定项指定? 如果该字段确实有值,是否有任何方法可以在不使用该字段的情况下检索该值。get方法(从而导致执行静态初始值设定项)


共 (2) 个答案

  1. # 1 楼答案

    您不能通过反射来实现这一点,但可以使用字节码工程库(如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
    
  2. # 2 楼答案

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

    因此,在申报时分配还不够。 这不是编译时常量,尽管它是一个有效的声明:

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

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

    要访问类字段的任何值,需要首先加载该类,因此不能阻止静态初始值设定项运行