package com.test; public class OuterClass { public class InnerClass { public class InnerInnerClass { } } public class InnerClass2 { } //this class should not exist in OuterClass after dummifying private class PrivateInnerClass { private String getString() { return "hello PrivateInnerClass"; } } public String getStringFromPrivateInner() { return new PrivateInnerClass().getString(); } }
When run through javac
on the command line with Sun JVM 1.6.0_20
, this code produces 6 .class files:
OuterClass.class
OuterClass$1.class
OuterClass$InnerClass.class
OuterClass$InnerClass2.class
OuterClass$InnerClass$InnerInnerClass.class
OuterClass$PrivateInnerClass.class
When run through JDT in eclipse, it produces only 5 classes.
OuterClass.class
OuterClass$1.class
OuterClass$InnerClass.class
OuterClass$InnerClass2.class
OuterClass$InnerClass$InnerInnerClass.class
OuterClass$PrivateInnerClass.class
When decompiled, OuterClass$1.class
contains nothing. Where is this extra class coming from and why is it created?
An anonymous inner class is an inner class which is declared without any class name at all. In other words, a nameless inner class is called an anonymous inner class. Since it does not have a name, it cannot have a constructor because we know that a constructor name is the same as the class name.
It can extend exactly one class and can implement multiple interfaces. It can extend exactly one class and implement exactly one interface. It can implement multiple interfaces regardless of whether it also extends a class. It can extend exactly one class or implement exactly one interface.
Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.
Which constructs an anonymous inner class instance? Runnable r = new Runnable() { }; B. Runnable r = new Runnable(public void run() { });
I'm using polygenelubricants's smaller snippet.
Remember there's no concept of nested classes in the bytecode; the bytecode is, however, aware of access modifiers. The problem the compiler is trying to circumvent here is that the method instantiate()
needs to create a new instance of PrivateInnerClass
. However, OuterClass
does not have access to PrivateInnerClass
's constructor (OuterClass$PrivateInnerClass
will be generated as a package-protected class without a public constructor).
So what can the compiler do? The obvious solution is to change PrivateInnerClass
to have a package-protected constructor. The problem here is that this will allow any other code which interfaces with the class to create a new instance of PrivateInnerClass
, even though it's explicitly declared as private!
To try and prevent that, the javac compiler is doing a little trick: instead of making PrivateInnerClass
's regular constructor visible from other classes, it leaves it as hidden (actually it does not define it at all, but that's the same thing from outside). Instead, it creates a new constructor which receives an additional parameter of the special type OuterClass$1
.
Now, if you look at instantiate()
, it calls that new constructor. It actually sends null
as the 2nd parameter (of the type OuterClass$1
) - that parameter is only used for specifying that this constructor is the one that should be called.
So, why create a new type for the 2nd parameter? Why not use, say, Object
? It's only used to differentiate it from the regular constructor and null
is passed anyway! And the answer is that as OuterClass$1
is private to OuterClass, a legal compiler will never allow the user to invoke the special OuterClass$PrivateInnerClass
constructor, as one of the required parameter types, OuterClass$1
, is hidden.
I'm guessing JDT's compiler uses another technique to solve the same problem.
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