Update: this is more-or-less a dupe, and it turns out to be compiler magic adding a constructor to pass in the local variable in build2.
Given an interface like such:
public interface IFoo {
public int get();
}
The code below prints 1, 1, 2 and then throws an exception when trying to call getClass().newInstance() on the value returned by build2, but does not when calling the same on the returned value of build1. Any ideas why?
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());
}
}
My debugger indicates that in the newInstance() call, getConstructor0 is throwing a NoSuchMethodException.
Here’s what happens:
newInstance()requires a nullary constructorfinalvariable, a field is actually implicitly created to hold this value, which is initially passed to its implicit constructorIFoocreated inbuild2does NOT actually have a nullary constructorHere’s a snippet to show what’s going on:
It shows that
Foo$1(the assigned binary name for the anonymousIFooclass) has only one constructor, and it takes anint. This is how it canreturn v, because what’s returned is actually whatever is assigned to the implicitly created field by this implicitly created constructor.It is instructive to decompile the
Foo$1(using e.g.javap -c) to see what bytecode gets generated. You will see that in fact this is what happens when afinalvariable is accessed by an anonymous class.Related questions