Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: private inner class synthesized constructors [duplicate]

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?

like image 599
shrini1000 Avatar asked Mar 04 '13 10:03

shrini1000


People also ask

When to use a private constructor in Java?

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.

What is a private inner class in Java?

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.

What is a constructor in Java?

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.

What is a static inner class in Java?

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.


3 Answers

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.

like image 82
sbridges Avatar answered Oct 01 '22 02:10

sbridges


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());
        }
    }
}
like image 32
assylias Avatar answered Oct 01 '22 02:10

assylias


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.

like image 24
Didier L Avatar answered Oct 01 '22 02:10

Didier L