This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
Hi There, Look at the example below and I also appended list of .class files generated by javac. Refer the .class file listings below. The question is, how come the program is generating "Parcel3$1.class" file. I would appreciate, if someone get a chance to look into this. Let me know, if the question is not obvious. Thanks for your Help. -siva
List of class files: ======================= PARCEL~4 CLA 585 01-03-03 6:13p Parcel3.class TEST~1 CLA 405 01-03-03 6:13p Test.class PARCEL~1 CLA 552 01-03-03 6:13p Parcel3$PContents.class PARCEL~2 CLA 643 01-03-03 6:13p Parcel3$PDestination.class PARCEL~3 CLA 144 01-03-03 6:13p Parcel3$1.class DESTIN~1 CLA 146 01-03-03 6:11p Destination.class CONTEN~1 CLA 119 01-03-03 6:11p Contents.class [ January 03, 2003: Message edited by: Michael Ernest ]
Hm hm hm. Ok, what I can tell you so far is that this notation represents an anonymous inner class. I can also tell you that it's being generated by the dest() method, and that the String parameter has something to do with it. I have some fuzzy guesses only to explain why, so I'm off to read the spec and see what this effect relates to.
Make visible what, without you, might perhaps never have been seen. - Robert Bresson
OK, this is absolutely not a beginner topic. The Java in General - Beginner answer is "don't worry about it." But for those who want to know anyway, here's the deal. Don't say you weren't warned. Back in the dark ages when JDK 1.1 came out and nested classes were introduced to the language, the decision was made not to require any major changes to the JVM (or JVM spec) in order to accommodate nested classes. Instead, they are implemented entirely by the compiler, which generates class files for each class as if it's a separate top-level class. Often the methods and constructors of the classes have extra parameters you might not expect - e.g. the constructor for an inner class may require an instance of the enclosing class, even though this was never mentioned in the code. The compiler makes it an inner class behave as though it automatically has access to an outer class instance; it does this by passing an extra parameter to the "inner" class constructor (really a top-level class as far as the JVM knows) which allows the "inner" class to access the "outer" instance. This is just one example - the general point is, the compiler creates a lot of extra stuff to explain nested classes to the JVM, since the JVM doesn't really understand the concept of nested classes. In this particular case, the problem is that the inner class PDestination has a private constructor, yet that constructor is being accessed from outside the PDestination class (yet inside the enclosing top-level class Parcel3. Here's a simplified view:
The JLS says that any private member can be accessed only from within the same top-level class as the member. Thus the PDestination constructor should be accessible from anywhere inside Parcel3, even if you're outside the PDestination inner class. However the JVM doesn't see this the same way - it thinks PDestination is a top-level class like any other class, and since its constructor is private, that constructor can't be accessed from another class such as Parcel3. The JVM sees the classes like this:
Here the PDestination constructor can't be accessed from the Parcel3 class. In order to resolve this dilemma, the compiler needs a new way to access the private constructor. Rather than simply changing the constructor access lever from private to package level, it instead creates a new, separate constructor for class PDestination which is package-level:
What's with the asterisk? Well, the problem with adding a constructor is that we can't just give it a new name -- it must have the name of the class after all. Instead we must overload the constructor with a new argument list. The new argument could be anything really - it's just important that the new argument list be different than any previous argument list used in a constructor for this class. I used a * initially as a placeholder for the new argument - we need to decide what to put there. The compiler chooses to create a whole new datatype, Parcel3$1, whose only real use is to provide a dummy argument which differentiates the PDestination() constructor from PDestination(Parcel3$1):
Strange, no? But it works. If you like you can use javap to disassemble the class files to see what's going on - but that does take some time to sort through. You can also verify that if you change the private PDestination() constructor to be package-level instead, then the class Parcel3$1 is no longer generated. It also will go away if you modify the dest() method to return null rather than invoking the PDestination() constructor. The class Parcel3$1 is only there to help provide a bridge between the private PDestination() constructor, and its invocation in a separate class.