簡體   English   中英

使用反射,我可以確定Java靜態最終字段是否內聯?

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

有沒有辦法,使用反射來確定靜態最終字段是否具有'='值(以便在訪問時該值將被內聯)或者它的值是否由靜態初始化程序賦值? 如果該字段確實有值,是否有任何方法可以在不使用Field.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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM