更新:这或多或少是dupe,结果是编译器魔术添加构造函数来传递build2中的局部变量。
给出如下界面:
public interface IFoo {
public int get();
}
下面的代码打印1,1,2,然后在尝试对build2返回的值调用getClass()。newInstance()时抛出异常,但在build1的返回值上调用时不会抛出异常。有什么想法吗?
public class Foo {
public static IFoo build1() {
return new IFoo() { public int get() { return 1; } };
}
public static IFoo build2(final int v) {
return new IFoo() { public int get() {return v;} };
}
public static void main(String[] args) throws Exception {
IFoo foo, bar;
foo = build1();
System.out.println(foo.get());
bar = foo.getClass().newInstance();
System.out.println(bar.get());
foo = build2(2);
System.out.println(foo.get());
bar = foo.getClass().newInstance();
System.out.println(bar.get());
}
}
我的调试器指示在newInstance()调用中,getConstructor0抛出NoSuchMethodException。
答案 0 :(得分:4)
以下是发生的事情:
newInstance()
需要一个无效的构造函数final
变量的匿名类时,实际上会隐式创建一个字段来保存此值,该值最初会传递给其隐式构造函数IFoo
中创建的build2
实际上没有一个无效的构造函数这是一个显示正在发生的事情的片段:
import java.lang.reflect.*;
public class Foo {
interface IFoo { public int get(); }
public static IFoo build2(final int v) {
return new IFoo() { public int get() {return v;} };
}
public static void main(String[] args) throws Exception {
Class<?> klazz = build2(42).getClass();
for (Constructor<?> c : klazz.getDeclaredConstructors()) {
System.out.println(c);
}
// prints: Foo$1(int)
}
}
它显示Foo$1
(匿名IFoo
类的指定二进制名称)只有一个构造函数,它需要int
。这就是它return v
的方式,因为返回的实际上是由隐式创建的构造函数分配给隐式创建的字段的任何内容。
反编译Foo$1
(使用例如javap -c
)以查看生成的字节码是有益的。您将看到,实际上这是匿名类访问final
变量时发生的情况。