Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is an anonymous inner class containing nothing generated from this code?

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?

like image 872
Andrew Westberg - BCSH Avatar asked May 21 '10 15:05

Andrew Westberg - BCSH


People also ask

What is an anonymous inner class?

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.

What is true about anonymous inner class?

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.

Why would you use an anonymous class rather than an inner class?

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.

How do I create an anonymous inner class instance?

Which constructs an anonymous inner class instance? Runnable r = new Runnable() { }; B. Runnable r = new Runnable(public void run() { });


1 Answers

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.

like image 156
Oak Avatar answered Sep 16 '22 21:09

Oak