• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

inner class extends enclosing class

 
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Be suspicious when you see an inner class extending the enclosing class.
1. Normally, when an instance method of the enclosing class is invoked, �this� is the enclosing instance.

2. However, if B extends A, when an instance method of the enclosing class is invoked, �this� is Not the enclosing instance!

3. The print method of the enclosing class is invoked with respect to the inner class instance and the inner object field is accessed.

[ September 08, 2003: Message edited by: Marlene Miller ]
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Is this the correct explanation: The method of the superclass shadows the method of the enclosing class?
 
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

1. Normally, when an instance method of the enclosing class is invoked, "this" is the enclosing instance.

This makes sense to me. The invoked method is NOT a member of B. It is like one member accessing another member, like an instance method accessing an instance variable, or an instance method calling another instance method.

2. However, if B extends A, when an instance method of the enclosing class is invoked, "this" is Not the enclosing instance!

In this case, the invoked method is now member of B so it should be invoked with respect to the instance of B.
I also think that this may be related to the issue of innermost class or interface, as what we had discussed in your last thread. Perhaps in the 1st case, the innermost class is A, while in the 2nd case, it is B.
Just my 2 cents.
[ September 09, 2003: Message edited by: Alton Hernandez ]
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Alton,
Thank you for your comments.
This does remind me of our discussion on innermost. That was JLS 15.12.1 Determine the class or interface to search. This one is JLS 15.12.4.1 Compute the Target Reference.
Even though the method is declared in A, it is a member of B, so (I guess) B is the nth lexically enclosing type declaration.
In my opinion, it takes a stretch of the imagination. I have decided not to worry about. That�s the way the compiler does it.
I think it�s sad how inner classes has made the JLS so difficult to understand and, I suppose, the language so much more complex.
 
Ranch Hand
Posts: 125
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for posting these examples. I can't imagine sinister exam authors(and I'm sure they all are) failing to include an easily over-looked subtlety like this one.
But while it's subtle and devious, it also made me focus on some basics. An inner class "sees into" its lexical parent's enclosing instance - it refers to the parent's members as if they were its own. But if the inner class extends its parent, it inherits the parent's members, and so invocations of instance methods and references to instance variables will be bound to its own instance.
If it didn't work this way, it would really be confusing.
The "nth enclosing instance" rigamarole doesn't help my understanding at all. The language that does help me, at least in the case of methods, is "invoke on": on what instance is the method being invoked? It seems that question can be answered fairly simply without the aid of recursion or anything stronger than coffee. Then I can (or at least should) get the right answers to those nasty scoping/inheritance questions. Analogous thinking ("reference on"?) works for instance variables (remembering to watch out for "hidden" versus "overridden").
Who, besides a devious exam author, would make a non-static member class a subclass of it's enclosing class? Is there any good purpose for this? Java famously subclasses with static member classes in the awt.geom package, but in the static case there are no inherited members shadowing (hiding?) enclosing class members. There is this though: an xxx.Float or xxx.Double class inherits itself as a member. Can't think of how that would be a problem, but it does seem odd.

I think it�s sad how inner classes has made the JLS so difficult to understand and, I suppose, the language so much more complex.


It does seem like this is not java's happiest area. Could the unhappiness be due mostly to confused terminology? I only know about what it is in jls second edition, but I hear there was a first draft with different terminology. When I read or listen in on nested class discussions, I feel like I'm hearing a mish-mash of old and new terms - usually "inner" meaning "nested" with the odd "top-level-nested" (an oxymoron by the current jls definitions) thrown in. People also make up their own terms like K&B's "regular inner".
But I also think some of the confusion is caused by the jls in its current form, e.g., here's what I take to be jls's definition of inner (in 8.1.2)

An inner class C is a direct inner class of a class O if O is the immediately lexically enclosing class of C and the declaration of C does not occur in a static context. A class C is an inner class of class O if it is either a direct inner class of O or an inner class of an inner class of O.


Isn't this a corollary: "An inner class must be declared in a non-static context"?
If it's not a corollary, my logic is lacking and maybe someone could help me out.
I want it to be a corollary, because then "inner" has a clear and useful meaning: needing-an-enclosing-instance-of-lexical-parent. Then "inner" is not a type-based category but an attribute. But the jls seems to ignore the fact that local and anonymous classes can be declared in static contexts and simply declares they are always inner. This spoils Steve's Grand But Simple Taxonomy of Nested Classes (or I'm missing something and someone out there should spoil this for me):
  • A "nested" class is any class declared within another class.
  • A "top-level" class is any class which is not nested.
  • A "member" class is a nested class declared directly in the body of its enclosing class. Member classes are full-fledged members of their enclosing classes, and may be static or non-static.
  • A "local" class is a class defined within a method, initializer, or constructor. It obeys the same scoping rules as a local variable, and like a local variable, it can't be static.
  • An "anonymous" class is a nameless class declared via special syntax which forms an expression.


  • That's it, except for pointing out which of those classes are "inner" (in the wished-for definition):
  • non-static member classes
  • local classes declared in non-static contexts
  • anonymous classes declared in non-static contexts


  • But we don't have that. But maybe I could save this conception of inner by inventing a new term and throwing it on the pile; how about "truly inner"?
    fixed list item 4, minor tweaks
    [ September 10, 2003: Message edited by: Steve Lovelace ]
     
    Marlene Miller
    Ranch Hand
    Posts: 1392
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    What a terrific response! So thoughtful, articulate and very clearly expressed, well-informed, JLS consistent, full of ideas.
    Thank you very very much, Steve. I will have to study this response for a while before I comment.
    (When I edit my replies multiple times, I delete the previous automatic timestamp.)
     
    Steve Lovelace
    Ranch Hand
    Posts: 125
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Marlene,
    Sorry about disgorging all at once. I really like using nested classes and am frustrated that explanations of them are always so muddy, even in the jls, even in the java tutorial (I got aggravated to the point of turning in a bug there). So I've been stewing over this for a while and coughed it all up when you gave me the chance.
     
    Marlene Miller
    Ranch Hand
    Posts: 1392
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thank you Steve for your core dump. I have only a few small comments.

    There is this though: an xxx.Float or xxx.Double class inherits itself as a member. Can't think of how that would be a problem, but it does seem odd.


    Here is a problem.

    Isn't this a corollary: "An inner class must be declared in a non-static context"?

    I suppose you know about this one:

    An instance of an inner class I whose declaration occurs in a static context has no lexically enclosing instances. JLS 8.1.2

     
    Steve Lovelace
    Ranch Hand
    Posts: 125
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Wow! It does cause a problem, and so simply produced!

    An instance of an inner class I whose declaration occurs in a static context has no lexically enclosing instances. JLS 8.1.2


    So class I has some enclosing class (it's called inner). But by light of the definition of inner quoted above, it is NOT an inner class of that class. So why is it called inner? What is it inner to?
    [ September 10, 2003: Message edited by: Steve Lovelace ]
     
    Marlene Miller
    Ranch Hand
    Posts: 1392
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Steve, I read JLS 8.1.2 in a different way from you. I don�t think the two sentences you quoted above are the definition of inner class.
    I think the definition of inner class is � a nested class that is not explicitly or implicitly declared static.
    Given this definition of inner class, the JLS goes on to define a bunch of terms (such as direct inner class of a class O) used only for the purpose and goal of describing nth lexically enclosing instance. The concept nth lexically enclosing instance is needed in JLS 15.9.
    As I see it, some inner classes are direct inner classes of a class O and some are not.
    An inner class C is a direct inner class of a class O if ... is like saying a starfish is a spiny starfish of Bodega Bay if . This is not the definition of starfish.
    [ September 10, 2003: Message edited by: Marlene Miller ]
     
    Steve Lovelace
    Ranch Hand
    Posts: 125
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    But what comes after the ellipsis? Here's the whole thing again (so I don't have to keep rolling up).

    An inner class C is a direct inner class of a class O if O is the immediately lexically enclosing class of C and the declaration of C does not occur in a static context. A class C is an inner class of class O if it is either a direct inner class of O or an inner class of an inner class of O.

    It's the second sentence I'm pointing at. I realize it doesn't say "if and only if", but if it doesn't mean that, what is its intent?
    Here's what has me going on (and on) about this. That some nested classes require an enclosing instance of their enclosing class is a key concept. We need a descriptive term for talking about these clases which is pithier than "needs-an-enclosing-instance-of-its-enclosing-class". The definition I keep pointing at seems to be saying: that pithier term is "inner". It's as if we have the term in hand in this one paragraph, and everywhere else the jls forgets about it. I'm suggesting that if the jls only used "inner" for this narrower sense, and used "nested" otherwise, things would be a lot clearer.
     
    Ranch Hand
    Posts: 787
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    posted by Marlene:


    1. Normally, when an instance method of the enclosing class is invoked, �this� is the enclosing instance.


    I think 'this' always refers to currently executing object. If currently executing object is of type inner class and it invokes a method defined in outer class, any reference to this in that method will resolve to inner class object. To prove that see my code example below.


    2. However, if B extends A, when an instance method of the enclosing class is invoked, �this� is Not the enclosing instance!


    Regardless of B extends A or not, if currently executing object is of inner type, 'this' will always refer to inner object in inner class instance as well as outer class instance code.


    Is this the correct explanation: The method of the superclass shadows the method of the enclosing class?


    Both references to method resolve to same single method. The question is which object is invoking that method. If it is inner object, all references to this will be inner object. If it is outer object, all references to this will be to outer object.
    Here is how I see this:
    There three possible types of relationships between two classes. Namely:
    1. Super - Sub
    2. Outer - inner
    3. Outer - inner with super sub
    The following terms can be defined within the context each relationship type:
    this - always referes to currently executing object
    name - if such field exists in currently executing class (by virtue of explicit declaration or inheritance, it will take precedence. If none, than enclosing class's (if any) field is reported.
    A.this - Refers to enclosing class's object (outer object)
    super.name - refers to inherited name only.
    this.name - refers to inherited name only.
    Here is my code example:
    Super Class - Sub Class relationship:
    1. Only object is created.
    2. That object is of sub-class
    3. Sub-class inherits super class's name variable
    4. Only one variable exists called name.

    Outer class - Inner class relationship
    1. Two objects are created; outer and inner
    2. inner does not have its own copy of name
    3. It refers to outers name only.

    Outer class - Inner class relationship with Super-Sub class relationship
    1. Two objects are created; outer and inner
    2. inner DOES have its own copy of name
    3. outer DOES have its own copy of name
     
    Barkat Mardhani
    Ranch Hand
    Posts: 787
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    posted by Marlene:


    1. Normally, when an instance method of the enclosing class is invoked, �this� is the enclosing instance.


    I think 'this' always refers to currently executing object. If currently executing object is of type inner class and it invokes a method defined in outer class, any reference to this in that method will resolve to inner class object. To prove that see my code example below.


    2. However, if B extends A, when an instance method of the enclosing class is invoked, �this� is Not the enclosing instance!


    Regardless of B extends A or not, if currently executing object is of inner type, 'this' will always refer to inner object in inner class instance as well as outer class instance code.


    Is this the correct explanation: The method of the superclass shadows the method of the enclosing class?


    Both references to method resolve to same single method. The question is which object is invoking that method. If it is inner object, all references to this will be inner object. If it is outer object, all references to this will be to outer object.
    Here is how I see this:
    There three possible types of relationships between two classes. Namely:
    1. Super - Sub
    2. Outer - inner
    3. Outer - inner with super sub
    The following terms can be defined within the context each relationship type:
    this - always referes to currently executing object
    name - if such field exists in currently executing class (by virtue of explicit declaration or inheritance, it will take precedence. If none, than enclosing class's (if any) field is reported.
    A.this - Refers to enclosing class's object (outer object)
    super.name - refers to inherited name only.
    this.name - refers to inherited name only.
    Here is my code example:
    Super Class - Sub Class relationship:
    1. Only object is created.
    2. That object is of sub-class
    3. Sub-class inherits super class's name variable
    4. Only one variable exists called name.

    Outer class - Inner class relationship
    1. Two objects are created; outer and inner
    2. inner does not have its own copy of name
    3. It refers to outers name only.

    Outer class - Inner class relationship with Super-Sub class relationship
    1. Two objects are created; outer and inner
    2. inner DOES have its own copy of name
    3. outer DOES have its own copy of name
     
    Steve Lovelace
    Ranch Hand
    Posts: 125
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Back on this:You get the same result this way:So it's nothing to do with outer/inner. It's just constructor chaining. I recall being warned about invoking subclassed methods during initialization (cause of accessing data which has not yet been initialized). But don't recall being told not to instantiate subclasses during initialization. Clearly, you shouldn't do it.
    [ September 11, 2003: Message edited by: Steve Lovelace ]
    [ September 11, 2003: Message edited by: Thomas Paul ]
     
    Marlene Miller
    Ranch Hand
    Posts: 1392
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Barkat, thank you for your detailed and comprehensive and organized explanation of �this� relative to inner classes and extended classes. Thank you for your time.
    My concern in this post is when the method invoked by the B object is declared in the A object.


    In the second example, the compiler has a choice � to invoke print with respect to the B object or with respect to the enclosing instance.

    [ September 11, 2003: Message edited by: Marlene Miller ]
     
    Marlene Miller
    Ranch Hand
    Posts: 1392
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Steve, thank you for showing me your example. I agree, the stack overflow problem is not a result of an inner class extending an enclosing class.
    reply
      Bookmark Topic Watch Topic
    • New Topic