2
public class MyClass {
    private String s = "foo";
}

是否可以"foo"使用反射而不必实例化一个新的MyClass

Field field = MyClass.class.getDeclaredField("s");
// -- ideally: --
// Object initializationValue = field.getInitializationValue();
// assert initializationValue.equals("foo");
4

3 回答 3

5

您所展示的初始化语句实际上已由编译器移入类的构造函数中。您需要实际实例化一个类才能执行它们。当然,这一切都在幕后。但是在回答你的问题时,不,你不能,无论如何都不能反思。

但是您可以使用 Soot 等静态分析工具确定这些字段值。

于 2013-02-08T13:31:41.423 回答
1

没有“作弊”是不可能的。

一种作弊可能是编写(或生成)一个创建新MyClass实例的类,并使用反射挖掘出您想要的值并将其写入标准输出。然后你启动一个子JVM来运行那个类,并在当前读取它。

净结果 - 您在没有MyClass 在当前 JVM 中实例化的情况下获得了值。

另一个欺骗是使用字节码库从MyClass“.class”文件中读取字节码,并在当前 JVM 的上下文中模拟初始化程序的执行。MyClass

于 2013-02-08T14:03:40.473 回答
0

ClassGraph可以这样做:

String clsName = "com.xyz.MyClass";
String s;
try (ScanResult scanResult =
        new ClassGraph().whitelistClasses(clsName).enableFieldInfo().scan()) {
    s = (String) scanResult.getClassInfo(clsName).getFieldInfo("s")
            .getConstantInitializerValue();
}

注意这仅适用于常量初始化器值(可以在没有对象实例化的情况下计算的值,除了String),分配给静态最终字段。编译器可以在编译时为简单的算术和简单的字符串连接生成一个常量。

(免责声明,我是ClassGraph的作者)

如果你不介意加载类,你也可以简单地使用反射来访问静态字段:https ://stackoverflow.com/a/4076792/3950982

于 2018-10-21T01:13:12.450 回答