【发布时间】:2015-07-05 00:43:54
【问题描述】:
我不敢相信我不得不问这个问题,这真的很令人困惑。这个问题的目的是找出为什么和/或找到一种更简单的方法(比反思)来获得正确的结果。
背景故事
我通过URLClassLoader 从目录和 jar 文件中加载了一些类文件,我想转储所有类名及其声明的方法。无法初始化这些类(请参阅false),因为如果在这些类中运行任何代码,则可能由于缺少某些依赖项而引发异常。我在尝试只输出类名时遇到了这个问题。
问题
我错过了什么,我怎样才能绕过 Groovy 的魔法,而只是简单地在对象(java.lang.Class 类型)上调用一个方法(称为 getName)而不进行反射?也请有人指出规范说明为什么会这样工作。
这是我的迷你测试(见下文)和我的 cmets 的输出:
.name // magically initializes class X and calls X.get("name")
name and Y
.getName() // tries to reload class Y in another ClassLoader and initialize it
X and thrown SHOULD NOT INIT
["name"] // this is just plain magic! What a Terrible Failure :)
name and thrown SHOULD NOT INIT
reflection // obviously works, becase it's really explicit
X and Y
测试工具和测试用例
将测试闭包更改为在参数类型上显式 (Class<?> c ->) 没有任何区别。
new File("X.java").write('''
public class X {
public static String get(String key) {
return key;
}
}
''');
new File("Y.java").write('''
public class Y {
static {
if (true) // needed to prevent compile error
throw new UnsupportedOperationException("SHOULD NOT INIT");
}
}
''');
print 'javac X.java Y.java'.execute().err.text;
def test = { String title, Closure nameOf ->
URL url = new File(".").toURI().toURL();
// need a new ClassLoader each time because it remembers
// if a class has already thrown ExceptionInInitializerError
ClassLoader loader = java.net.URLClassLoader.newInstance(url);
// false means not to initialize the class.
// To get the name of the class there's no need to init
// as shown in the reflection test.
// Even fields and methds can be read without initializing,
// it's essentially just parsing the .class file.
Class x = Class.forName("X", false, loader);
Class y = Class.forName("Y", false, loader);
println()
println title
try {
print nameOf(x)
} catch (Throwable ex) {
print "thrown " + ex.cause?.message
}
print " and "
try {
print nameOf(y)
} catch (Throwable ex) {
print "thrown " + ex.cause?.message
}
println()
}
test '.name', { c -> c.name; }
test '.getName()', { c -> c.getName(); }
test '["name"]', { c -> c["name"] }
test 'reflection', { c -> java.lang.Class.class.getDeclaredMethod("getName").invoke(c); }
【问题讨论】:
标签: java methods reflection groovy gradle