This question is about interesting behavior of Java: it produces additional (not default) constructor for nested classes in some situations.
This question is also about strange anonymous class, which Java produces with that strange constructor.
Consider the following code:
package a;
import java.lang.reflect.Constructor;
public class TestNested {
class A {
A() {
}
A(int a) {
}
}
public static void main(String[] args) {
Class<A> aClass = A.class;
for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c);
}
}
}
This will prints:
a.TestNested$A(a.TestNested)
a.TestNested$A(a.TestNested,int)
Ok. Next, lets make constructor A(int a)
private:
private A(int a) {
}
Run program again. Receive:
a.TestNested$A(a.TestNested)
private a.TestNested$A(a.TestNested,int)
It is also ok. But now, lets modify main()
method in such way (addition of new instance of class A
creation):
public static void main(String[] args) {
Class<A> aClass = A.class;
for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c);
}
A a = new TestNested().new A(123); // new line of code
}
Then input becomes:
a.TestNested$A(a.TestNested)
private a.TestNested$A(a.TestNested,int)
a.TestNested$A(a.TestNested,int,a.TestNested$1)
What is it: a.TestNested$A(a.TestNested,int,a.TestNested$1) <<<---??
Ok, lets again make constructor A(int a)
package local:
A(int a) {
}
Rerun program again (we don't remove line with instance of A
creation!), output is as in the first time:
a.TestNested$A(a.TestNested)
a.TestNested$A(a.TestNested,int)
Questions:
1) How this could be explained?
2) What is this third strange constructor?
UPDATE: Investigation shown following.
1) Lets try to call this strange constructor using reflection from other class.
We will not able to do this, because there isn't any way to create instance of that strange TestNested$1
class.
2) Ok. Lets do the trick. Lets add to the class TestNested
such static field:
public static Object object = new Object() {
public void print() {
System.out.println("sss");
}
};
Well? Ok, now we could call this third strange constructor from another class:
TestNested tn = new TestNested();
TestNested.A a = (TestNested.A)TestNested.A.class.getDeclaredConstructors()[2].newInstance(tn, 123, TestNested.object);
Sorry, but I absolutely don't understand it.
UPDATE-2: Further questions are:
3) Why Java use special anonymous inner class for an argument type for this third synthetic constructor? Why not just Object
type, of constructor with special name?
4) What Java could use already defined anonymous inner class for those purposes? Isn't this some kind of violation of security?
A
passing int value in it. But, really, why? – Consentaneousnew A(int)
from within the inner class. – Adorablea.TestNested$1
? Due to reflection investigation, this class even has not any constructors at all, and can not be instantiated using reflection. – ConsentaneousTestNested.class
,TestNested$1.class
andTestNested$A.class
. ThisTestNested$1.class
is a puzzle for me... – ConsentaneousTestNested
(just static fieldstatic Object o = new Object {...}
, then the number and names of generated.class
files will not change. But if we will create second anonymous class we will receive newTestNested$2.class
. – ConsentaneousTestNested$1
is just one static class. Inner classes can exists just inside a context of outer class. In this example we are instantiating inner class inside a static method, not somewhere in outer class. So, my opinion here (but I'm not shore) that java creates one more class, that is same like our inner class, except it is static. – Coelomnew Object {...}
and Java uses this anonymous class like thatTestNested$1
class. I can even pass its instance to that strange constructor. – ConsentaneousObject
as the argument type because you would be able to have your own constructor with anObject
argument and invoke it without reflection (by compilingA
with a non-privateA(int, Object)
constructor, saving theTestNested$A.class
file somewhere else, removing the new constructor, recompilingTestNested
, and replacing the newTestNested$A.class
with the version with theA(int, Object)
constructor.) Using an anonymous type (TestNested$1
) as the argument type of the synthetic constructor prevents that. – Jiujitsu