In final variable passed to anonymous class via constructor, Jon Skeet mentioned that variables are passed to the anonymous class instance via an auto-generated constructor. Why would I not be able to see the constructor using reflection in that case:
public static void main(String... args) throws InterruptedException {
final int x = 100;
new Thread() {
public void run() {
System.out.println(x);
for (Constructor<?> cons : this.getClass()
.getDeclaredConstructors()) {
StringBuilder str = new StringBuilder();
str.append("constructor : ").append(cons.getName())
.append("(");
for (Class<?> param : cons.getParameterTypes()) {
str.append(param.getSimpleName()).append(", ");
}
if (str.charAt(str.length() - 1) == ' ') {
str.replace(str.length() - 2, str.length(), ")");
} else
str.append(')');
System.out.println(str);
}
}
}.start();
Thread.sleep(2000);
}
The output is:
100
constructor : A$1()
Here is what your program prints out on my system:
100
constructor : A$1()
So the constructor is there. However, it is parameterless. From looking at the disassembly, what happens is that the compiler figures out that it doesn't need to pass x
to run()
since its value is known at compile time.
If I change the code like so:
public class A {
public static void test(final int x) throws InterruptedException {
new Thread() {
public void run() {
System.out.println(x);
for (Constructor<?> cons : this.getClass()
.getDeclaredConstructors()) {
StringBuilder str = new StringBuilder();
str.append("constructor : ").append(cons.getName())
.append("(");
for (Class<?> param : cons.getParameterTypes()) {
str.append(param.getSimpleName()).append(", ");
}
if (str.charAt(str.length() - 1) == ' ') {
str.replace(str.length() - 2, str.length(), ")");
} else
str.append(')');
System.out.println(str);
}
}
}.start();
Thread.sleep(2000);
}
public static void main(String[] args) throws InterruptedException {
test(100);
}
}
The constructor that gets generated is now:
constructor : A$1(int)
The sole argument is the value of x
.
In this case, it's because 100 is a constant. That gets baked into your class.
If you change x
to be:
final int x = args.length;
... then you'll see Test$1(int)
in the output. (This is despite it not being explicitly declared. And yes, capturing more variables adds parameters to the constructor.)