Suppose I have an inner class as follows:
1 package com.examples;
2
3 public class Outer {
4
5 public void test() {
6 Inner ic = new Inner();
7 }
8
9 public class Inner {
10 private Inner() {
11 }
12 }
13 }
Even though the constructor for the inner class
Inner
is private, a package
-access constructor is created by the compiler as a side-effect when you call the private constructor at line 6 in the test
method.There are a couple of ways to verify this. First, you can just look at the generated class file
Outer$Inner.class
. You'll find two lines, one for the private constructor that you have written, and another which is a "synthetic"* constructor:
..
private Outer$Inner(com.examples.Outer arg0);
..
synthetic Outer$Inner(com.examples.Outer arg0, com.examples.Outer.Inner arg1);
If you are not convinced, you can run through the constructors using reflection, as shown in this example class:
1 package com.examples;
2 import java.lang.reflect.*;
3
4 public class InnerTester {
5 public static void main(String[] args) throws ClassNotFoundException {
6 InnerTester.printConstructors("com.examples.Outer$Inner");
7 }
8 public static void printConstructors(String str) throws ClassNotFoundException {
9 Class c = Class.forName(str);
10 Constructor[] cs = c.getDeclaredConstructors();
11 for (int i = 0; i < cs.length; i++) {
12 System.out.println(cs[i].toString());
13 }
14 }
15}
Running this program produces two lines of output:
com.examples.Outer$Inner(com.examples.Outer,com.examples.Outer$Inner)
private com.examples.Outer$Inner(com.examples.Outer)
If you comment out line 6 in
Outer.java
and recompile it, the output of this program is just one line:
private com.examples.Outer$Inner(com.examples.Outer)
You can look at the class file,
Outer$Inner.class
, and check that the package access constructor is gone, there, too.There's a rule warning against calling a private constructor of an inner class like this, because the constructor is effectively given package access. PMD suggests using a factory method instead of creating the instance directly in the outer class, or just making the constructor public, to solve the problem.
I can't imagine any situation in which this would be a problem unless you're using reflection to call constructors.
* The Sun tutorial on Java reflection has a brief discussion of synthetic (compiler-generated) constructors.