I have an Outer
class which has a private Inner
class.
In my Outer
class method, I instantiate the Inner
class as follows:
Outer outer = new Outer();
Inner inner = outer.new Inner();
The compiler converts this code to:
Outer outer = new Outer();
Inner inner = new Inner(outer, null);
Using reflection shows that the Inner
class has the following synthesized constructors:
private Outer$Inner(Outer)
Outer$Inner(Outer,Outer$Inner)
Since the Inner
class is private
, the compiler adds that private
constructor to it so nobody can instantiate that class. But obviously the Outer
class should be able to instantiate it, so the compiler adds that other package private constructor which in turn calls the private constructor. Also, since the package-private constructor has that $
in its name, normal Java code can't call it.
Question: why synthesize one private and one package-private constructor? Why not synthesize only the package-private constructor and be done with it?
If a class has a private constructor and when we try to extend the class, a compile-time error occurs. We cannot access a private constructor from any other class. If all the constant methods are there in our class, we can use a private constructor. If all the methods are static then we can use a private constructor.
Inner Classes (Non-static Nested Classes) Inner classes are a security mechanism in Java. We know a class cannot be associated with the access modifier private, but if we have the class as a member of other class, then the inner class can be made private.
In Java, the constructor is a special type of method that has the same name as the class name. Internally, a constructor is always called when we create an object of the class.
If you compile and execute the above program, it gives you the following result − A static inner class is a nested class which is a static member of the outer class. It can be accessed without instantiating the outer class, using other static members.
If you write the code like,
public class Outer {
private class Inner {}
}
You will note that there is only one constructor private Outer$Inner(Outer)
This constructor is required by Section 8.8.9 of the JLS, which says that if no constructor is defined a default constructor must be generated, and in this case the default constructor must be private,
In a class type, if the class is declared public, then the default constructor is implicitly given the access modifier public (§6.6); if the class is declared protected, then the default constructor is implicitly given the access modifier protected (§6.6); if the class is declared private, then the default constructor is implicitly given the access modifier private (§6.6); otherwise, the default constructor has the default access implied by no access modifier.
However, when you you instantiate an instance of Inner inside Outer with code like,
public class Outer {
private class Inner {}
public String foo() {
return new Inner().toString();
}
}
The compiler has to generate a constructor that Outer can legally call (you can't legally call the private default constructor because it is private). So a new synthetic constructor must be generated by the compiler. The new constructor must be synthetic, according to section 13.1 of the JLS
Any constructs introduced by the compiler that do not have a corresponding construct in the source code must be marked as synthetic, except for default constructors and the class initialization method.
This second constructor has no corresponding construct in the source code, so this new constructor must be synthetic. The first private constructor must still be generated, since the JLS requires a private default constructor.
This is not an answer, which I think has been well covered by sbridges. It is simply a working example that produces the behaviour you describe:
public class Outer {
private class Inner {
}
public static void main(String[] args) {
printConstructors();
//only one constructor is printed but two would appear if you
//uncommented the line below
//new Outer().new Inner();
}
private static void printConstructors() {
Constructor[] constructors = Outer.Inner.class.getDeclaredConstructors();
for (Constructor c : constructors) {
System.out.println(c.toGenericString());
}
}
}
The most likely answer is to respect what you declared in your source code. Doing this still allows to use the private constructor by reflection as you declared it.
This also avoids to check whether the private constructor is actually called within the Inner
class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With