Inner Classes a liability

Discussion in 'Java' started by Ben Wilson, Apr 26, 2004.

  1. Ben Wilson

    Ben Wilson Guest

    Hi, I'm hoping someone out there is an expert and can share some
    authoritative insights.

    I'm working with inner classes in Java, and I'm finding myself unsatisfied
    with the way they've been implemented, and frankly, somewhat alarmed. It is
    true that an inner class can access the methods and object variables of its
    enclosing class. However, it is also true that inner classes participate in
    overriding - I can set up an inner class that overrides the members of its
    enclosing class. However, inner classes can also be defined to extend
    another class entirely.

    Hello? I thought Java didn't support multiple inheritance but here it is!

    Have a look at this sample code and tell me what's going on here:

    //inners2.java

    class inners2
    {
    void printMessage()
    {
    System.out.println("ladida");
    }

    public static void main(String[] args)
    {
    new outerclass01().new sucker().printMessage();
    }
    }

    class outerclass01
    {
    void printMessage()
    {
    System.out.println("humdeedum");
    }

    class sucker extends inners2
    {}
    }

    So there you go, what's the above code going to print when run? Is it
    "ladida" or "humdeedum"?

    From seeing this I get the feeling that not a lot of thought got put into
    defining what it was exactly that inner classes were supposed to do. Anybody
    know what the story is here?

    Thanks,

    Ben.
    Ben Wilson, Apr 26, 2004
    #1
    1. Advertising

  2. Hi Ben,

    Ben Wilson schrieb:
    > Hi, I'm hoping someone out there is an expert and can share some
    > authoritative insights.
    >
    > I'm working with inner classes in Java, and I'm finding myself unsatisfied
    > with the way they've been implemented, and frankly, somewhat alarmed. It is
    > true that an inner class can access the methods and object variables of its
    > enclosing class. However, it is also true that inner classes participate in
    > overriding - I can set up an inner class that overrides the members of its
    > enclosing class. However, inner classes can also be defined to extend
    > another class entirely.


    Sure. But you cannot setup your inner class to override methods of its
    outer class *and* extend another class.

    >
    > Hello? I thought Java didn't support multiple inheritance but here it is!


    No, it isn't here.

    >
    > Have a look at this sample code and tell me what's going on here:
    >
    > //inners2.java
    >
    > class inners2
    > {
    > void printMessage()
    > {
    > System.out.println("ladida");
    > }
    >
    > public static void main(String[] args)
    > {
    > new outerclass01().new sucker().printMessage();


    you create an instance of sucker (subclass of inners2) and call it's
    printMessage method. So, where's multiple inheritance?

    > }
    > }
    >
    > class outerclass01
    > {
    > void printMessage()
    > {
    > System.out.println("humdeedum");
    > }
    >
    > class sucker extends inners2
    > {}
    > }
    >
    > So there you go, what's the above code going to print when run? Is it
    > "ladida" or "humdeedum"?


    ladida of course since you created an instance of sucker.

    Counterquestion: what do you get if you have the following in your main
    method?

    public static void main( String args[] ) {
    Object o = new outerclass01().new sucker();

    System.out.println( "is sucker: " + o instanceof sucker );
    System.out.println( "is inners2: " + o instanceof inners2 );
    System.out.println( "is outerclass01: "+o instanceof outerclass01 );
    }

    Michael
    Michael Rauscher, Apr 26, 2004
    #2
    1. Advertising

  3. Ben Wilson

    Ben Wilson Guest

    Hi, Michael

    >
    > Sure. But you cannot setup your inner class to override methods of its
    > outer class *and* extend another class.
    >


    Actually, that's a bit my point. You can set up an inner class to override
    methods of both the outer class *and* extend another class with ease.

    Here - the modified version... (try it if you don't believe me...)

    package temptests;

    class inners2
    {

    void printMessage()
    {
    System.out.println("ladida");
    }

    public static void main(String[] args)
    {
    outerclass01.sucker t = new outerclass01().new sucker();
    Object o = new outerclass01().new sucker();
    t.printMessage();
    t.prontMessage();
    System.out.println("is sucker" + (o instanceof
    temptests.outerclass01.sucker));
    System.out.println("is inners2" + (o instanceof inners2));
    System.out.println("is outerclass01" + (o instanceof outerclass01));

    }

    }


    class outerclass01
    {

    void prontMessage()
    {
    System.out.println("hodihum");
    }

    class sucker extends inners2
    {
    void printMessage()
    {
    System.out.println("The Rain");
    }

    void prontMessage()
    {
    System.out.println("In Spain");
    }

    }

    }

    If you run this, you'll get to see "The Rain" "In Spain" and then true,
    true, and false. There, have I just done something you thought was
    impossible ;-)?

    I do not believe Java was supposed to let this sort of thing happen. From
    seeing this I get the feeling that not a lot of thought got put into
    defining what it was exactly that inner classes were supposed to do. Anybody
    know what the story is here?

    Thanks,

    Ben.
    Ben Wilson, Apr 26, 2004
    #3
  4. Ben Wilson

    Adam Guest

    > I do not believe Java was supposed to let this sort of thing happen.
    From
    > seeing this I get the feeling that not a lot of thought got put into
    > defining what it was exactly that inner classes were supposed to do.

    Anybody
    > know what the story is here?


    I'm having the same reservations about inner classes and
    their possibilities. Once someone posted such a riddle here
    (see below). I think it shows how bug prone can inner
    (in this case - anonymous) classes be:

    public class T
    {
    private final String name;
    protected void prname() { System.out.println(name); }
    T(String name) { this.name = name; }

    public static void main(String[] args)
    {
    new T("main").doit();
    }

    private void doit()
    {
    new T("anonymous inner")
    {
    void method()
    {
    prname();
    }
    }.method();
    }
    }

    What will be printed when you run it?
    Adam, Apr 26, 2004
    #4
  5. Ben Wilson

    chris Guest

    Ben Wilson wrote:

    > From seeing this I get the feeling that not a lot of thought got put into
    > defining what it was exactly that inner classes were supposed to do.
    > Anybody know what the story is here?


    The usual one - Microsoft had "extended" the Java language, and Sun felt
    the need to offer an equivalent convenience in its own, "official" version
    of the language. That's how most of the ill thought-out features you come
    across in languages or applications get there.

    --
    Chris Gray
    /k/ Embedded Java Solutions
    chris, Apr 26, 2004
    #5
  6. Ben Wilson

    Bjorn Abelli Guest

    "Ben Wilson" wrote...

    > Hello? I thought Java didn't support multiple
    > inheritance but here it is!


    No, the inner class doesn't "inherit" the outer class.

    However, it is seen as a kind of "outer scope" for the
    inner class, and hence the methods from the outer class
    are accessible for the inner class.

    If the inner class has a method of its own with the
    same signature as a method in the outer class, it
    doesn't "override" it. It simply "hides" it.

    > class inners2
    > {
    > void printMessage()
    > {
    > System.out.println("ladida");
    > }
    >
    > public static void main(String[] args)
    > {
    > new outerclass01().new sucker().printMessage();
    > }
    > }
    >
    > class outerclass01
    > {
    > void printMessage()
    > {
    > System.out.println("humdeedum");
    > }
    >
    > class sucker extends inners2
    > {}
    > }
    >
    > So there you go, what's the above code going
    > to print when run? Is it
    > "ladida" or "humdeedum"?


    Of course it is "ladida" as it's the result of the
    method printMessage in the inner class, which it
    inherited from "inners2".

    As an evidence that the inner class doesn't inherit
    the outer class, remove "extends inners2" from the
    class sucker, and you will see that it won't even
    compile on the line

    new outerclass01().new sucker().printMessage();

    ....as "sucker" then doesn't even *have* a method printMessage.

    FWIW, I still think you have a point in that inner classes is an "ugly" and
    possibly "errorprone" concept. I never use it myself, as anything you can do
    with inner classes can be solved with other means.

    // Bjorn A
    Bjorn Abelli, Apr 26, 2004
    #6
  7. Ben Wilson

    Chris Smith Guest

    Ben Wilson wrote:
    > Actually, that's a bit my point. You can set up an inner class to override
    > methods of both the outer class *and* extend another class with ease.


    Your confusion comes primarily from misuse of the word "override". That
    word has a specific meaning in Java. Because you've been talking about
    overriding methods of the outer class, everyone who has responded has
    been assuming that your inner class extends your outer class. If that
    were the case, it could not also extend a different class.

    It seems, though, that you're using "override" to refer to the masking
    behavior by which a method declared in the smaller scope of an inner
    class hides a method of the same name declared in the outer class.
    That's not overriding a method: it's not polymorphic, and method
    resolution is strictly limited to lexical scope and determined by the
    compiler.

    A couple points about inner classes:

    1. If your inner class is closely related to your outer class, then yes
    things can get confusing. That's because you've essentially declared
    two different relationships between the two classes (inner/outer, and
    inheritance), and you're apparently having trouble keeping the two kinds
    of relationships straight.

    Fortunately, I've rarely if ever seen a good reason for an inner class
    to extend its outer class.

    2. It's best to avoid ambiguous method names where you share a method
    name between inner and outer classes. Since the inner type is a
    dependent concept on its outer class, that's always entirely possible.

    >
    > Here - the modified version... (try it if you don't believe me...)


    And, as predicted, the inner class (sucker), extends only one other
    class (inners2). It does not extend outerclass01, and hence can't
    override its methods. However, sucker does indeed lexically hide the
    implementation of prontMessage in outerclass01, so that a call to
    sucker.prontMessage will resolve at compile-time to the sucker
    implementation. Since this happens at compile-time, it is so resolved
    before any resolution of method overrides; so if you an instance of a
    subclass of sucker that overrides the prontMessage method, then the
    subclass implementation would be called.

    > I do not believe Java was supposed to let this sort of thing happen. From
    > seeing this I get the feeling that not a lot of thought got put into
    > defining what it was exactly that inner classes were supposed to do. Anybody
    > know what the story is here?


    Perhaps it will be illustrative to understand that the following doesn't
    work. It doesn't work specifically because the resolution of methods
    between inner and outer classes is *not* based on inheritance.

    public class Test
    {
    public static void main(String[] args)
    {
    new Test2().new TestInner().printMessage();
    }
    }

    class Test2
    {
    public void printMessage()
    {
    System.out.println("Test message");
    }

    class TestInner
    {
    }
    }

    --
    www.designacourse.com
    The Easiest Way to Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Apr 26, 2004
    #7
  8. Hi Ben,

    Ben Wilson schrieb:
    > Hi, Michael
    >
    >
    >>Sure. But you cannot setup your inner class to override methods of its
    >>outer class *and* extend another class.
    >>

    >
    >
    > Actually, that's a bit my point. You can set up an inner class to override
    > methods of both the outer class *and* extend another class with ease.


    No, you can't (see below)

    Code:
    [color=blue]
    >
    > If you run this, you'll get to see "The Rain" "In Spain" and then true,
    > true, and false. There, have I just done something you thought was
    > impossible ;-)?[/color]
    
    No, you haven't. That are exactly the results I'd expect.
    
    You get true, true and false. What does this mean?
    
    Your sucker-object is an instance of outerclass01.sucker (of course) its
    an instance of inners2 (since outerclass01.sucker extends inners2) but
    it is not an instance of outerclass01.
    
    The latter means that sucker isn't a subclass of outerclass01. And since
    sucker doesn't extend outerclass01 you didn't overwrite any method of
    outerclass01.
    
    Therefore this has nothing to do with multiple inheritance. sucker
    extends inners2, sucker does neither extend outerclass01 nor does it
    overwrite methods of outerclass01...
    
    Bye
    Michael
    Michael Rauscher, Apr 26, 2004
    #8
  9. Ben Wilson

    xarax Guest

    "Michael Rauscher" <> wrote in message
    news:c6jbl3$iuu$05$-online.com...
    > Hi Ben,
    >
    > Ben Wilson schrieb:
    > > Hi, Michael
    > >
    > >
    > >>Sure. But you cannot setup your inner class to override methods of its
    > >>outer class *and* extend another class.
    > >>

    > >
    > >
    > > Actually, that's a bit my point. You can set up an inner class to override
    > > methods of both the outer class *and* extend another class with ease.

    >
    > No, you can't (see below)
    >
    >
    Code:
    [color=green]
    > >
    > > If you run this, you'll get to see "The Rain" "In Spain" and then true,
    > > true, and false. There, have I just done something you thought was
    > > impossible ;-)?[/color]
    >
    > No, you haven't. That are exactly the results I'd expect.
    >
    > You get true, true and false. What does this mean?
    >
    > Your sucker-object is an instance of outerclass01.sucker (of course) its
    > an instance of inners2 (since outerclass01.sucker extends inners2) but
    > it is not an instance of outerclass01.
    >
    > The latter means that sucker isn't a subclass of outerclass01. And since
    > sucker doesn't extend outerclass01 you didn't overwrite any method of
    > outerclass01.
    >
    > Therefore this has nothing to do with multiple inheritance. sucker
    > extends inners2, sucker does neither extend outerclass01 nor does it
    > overwrite methods of outerclass01...
    >
    > Bye
    > Michael[/color]
    
    Inner classes are not a form of multiple inheritance
    of implementation nor interface. The compiler creates
    a hidden field that contains a reference to the outer
    class instance. Whenever the inner class has a method
    call or refers to field of the enclosing instance, the
    hidden reference is used.
    
    Also, you cannot assign a reference from the inner
    class to a variable or field that is declared of the
    outer class type.
    xarax, Apr 26, 2004
    #9
  10. "Adam" <> writes:

    > I'm having the same reservations about inner classes and
    > their possibilities. Once someone posted such a riddle here
    > (see below). I think it shows how bug prone can inner
    > (in this case - anonymous) classes be:


    > What will be printed when you run it?


    It will print "anonymous inner".

    The point of confuzion is that Java doesn't have textual scope. The
    binding of an identifier is not necessarily the nearest textually
    enclosing declaration of that name.

    Another example:
    ----
    class B {
    String foo = "bar";
    }

    class A {
    int foo = 37;
    int main(String[] args) {
    boolean foo = false;
    new B() {
    method() { System.out.println(foo); }
    }.method();
    }
    }
    ----
    There are plenty of declarations of variables called foo around the
    call to println, but the one actually used is not diretly in scope.

    It's a mind-bender for sure, but once you get the knack of it, it
    won't bite you too often :)

    /L
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Apr 26, 2004
    #10
  11. Ben Wilson

    Robert Guest

    Ben Wilson wrote:

    > Hi, I'm hoping someone out there is an expert and can share some
    > authoritative insights.
    >
    > I'm working with inner classes in Java, and I'm finding myself unsatisfied
    > with the way they've been implemented, and frankly, somewhat alarmed. It is
    > true that an inner class can access the methods and object variables of its
    > enclosing class. However, it is also true that inner classes participate in
    > overriding - I can set up an inner class that overrides the members of its
    > enclosing class. However, inner classes can also be defined to extend
    > another class entirely.
    >
    > Hello? I thought Java didn't support multiple inheritance but here it is!
    >
    > Have a look at this sample code and tell me what's going on here:
    >
    > //inners2.java
    >
    > class inners2
    > {
    > void printMessage()
    > {
    > System.out.println("ladida");
    > }
    >
    > public static void main(String[] args)
    > {
    > new outerclass01().new sucker().printMessage();
    > }
    > }
    >
    > class outerclass01
    > {
    > void printMessage()
    > {
    > System.out.println("humdeedum");
    > }
    >
    > class sucker extends inners2
    > {}
    > }
    >
    > So there you go, what's the above code going to print when run? Is it
    > "ladida" or "humdeedum"?
    >
    > From seeing this I get the feeling that not a lot of thought got put into
    > defining what it was exactly that inner classes were supposed to do. Anybody
    > know what the story is here?
    >
    > Thanks,
    >
    > Ben.
    >

    Maybe good timing on JDJ's part.

    There is an article called "Strategies for Securing Java Code". Rule #1
    is "Avoid Using Inner Classes". A good read and here is the link to it:

    http://sys-con.com/story/?storyid=44375&DE=1
    Robert, Apr 26, 2004
    #11
  12. Christophe Vanfleteren, Apr 26, 2004
    #12
  13. Ben Wilson

    Chris Smith Guest

    Robert wrote:
    > Maybe good timing on JDJ's part.
    >
    > There is an article called "Strategies for Securing Java Code". Rule #1
    > is "Avoid Using Inner Classes". A good read and here is the link to it:
    >
    > http://sys-con.com/story/?storyid=44375&DE=1


    Or perhaps a really bad article. I don't read JDJ much, so I'm
    struggling not to judge the whole magazine on the fact that this load of
    balogna got through their editing process...

    I'll constrain my criticism to the inner classes issue. In particular,
    the article makes a few assumptions:

    1. That package access is insecure. Aside from the inconsequential
    misinformation about the treatment of private field access from inner
    classes (which really is inconsequential, as the result is a package-
    access member either way), there's nothing wrong with package access for
    security!

    I'd go as far as saying that anything stronger than package access
    (i.e., private access) is nice from a code maintenance standpoint, but
    absolutely pointless to someone concerned about security. The authors
    say they are concerned about package access because someone could
    conceivably provide code that declares the same package as the security-
    sensitive code. The authors mention package-sealing... that security
    feature that's used effectively by the *entire* core API to prevent
    exactly these kinds of security issues... but imply that it's a "second-
    best" kind of answer. Not the case; if you want to secure access by
    untrusted code to an API, it *has* to be in a sealed package.

    The only remaining possibility, then, is concern about someone replacing
    the existing implementation... a task which requires the kind of access
    to the system that makes security completely moot!

    Basically, if package access is broken from a security standpoint, then
    Java is broken from a security standpoint. So if the authors really
    believe what they say, then they need to stop using Java for security-
    sensitive code. Of course, that won't really be necessary because they
    are wrong.

    2. The basic assumption that protection is needed against an attacker
    running arbitrary bits of your code. This general concept fails
    miserably. Any attacker who can run arbitrary bits of your code has
    already won. Period. "Full stop" (if you're British). End of story.
    If the authors are concerned about untrusted code running under a
    security manager, then fine... but shouldn't they mention using the
    security manager in that case?

    Truth is, using inner classes is not a security risk. Failing to take
    basic precautionary steps such as sealing security-sensitive packages in
    the presence of untrusted code, on the other hand, is definitely a
    security risk.

    --
    www.designacourse.com
    The Easiest Way to Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Apr 27, 2004
    #13
  14. Ben Wilson

    Chris Smith Guest

    Chris Smith, Apr 27, 2004
    #14
  15. Ben Wilson

    Robert Guest

    Robert, Apr 27, 2004
    #15
  16. Ben Wilson

    Ben Wilson Guest

    To everyone who has helped me by replying to this, thank you!

    My confusion started with the explanation of inner classes as "getting
    access to the members of its enclosing class". From this I assumed that this
    access was just made available, also to the inner class's callable
    interface. In other words, I thought it was bigger than it actually was.

    To use the example from Chris Smith:

    public class Test
    {
    public static void main(String[] args)
    {
    new Test2().new TestInner().printMessage();
    }
    }

    class Test2
    {
    public void printMessage()
    {
    System.out.println("Test message");
    }

    class TestInner
    {
    }
    }


    Yes, I can see now that this doesn't work. However, the call here to
    printMessage(), had it been done within the class TestInner, would have.

    The principles of "hiding" members from the outer class from within the
    inner class have many parallels with overriding, so it is easy to get
    confused. My dissatisfaction started because I realised I could "hide" a
    method from the outer class by making one with an identical signature from
    an inner class, but once I did that I could never actually get a-hold of the
    outer class with something like "super". But more about this later.

    First, two observations:
    First observation: the literature makes a *real* lousy job of explaining
    this. Take Heller&Roberts book "Complete Java 2 Certification Study Guide
    Fourth Edition". When they talk about reusing method names, very
    specifically, they say "As you construct classes and add methods to them, in
    some circumstances you will want to re-use the same name for a method. You
    can do so two ways with Java. Re-using the same method name with different
    arguments and perhaps a different return type is known as overloading. Using
    the same method name with identical arguments and return type is known as
    overriding." Apparantly this statement is incorrect or at best incomplete -
    there is also this "hiding" thing. Since what I was doing was using the same
    method name with identical arguments and return type, well, it just *had* to
    be overriding, right? Well, sure shows me!

    As a second example, take Peter van der Linden's book "Just Java 2 - Fifth
    edition". He says, in his chapter on Polymorphism: "Polymorphism is a
    complicated name for a straightforward concept. It is Greek for 'many
    shapes' and it merely means using the same one name to refer to different
    methods. 'Name reuse' would be a better term. There are two types of
    polymorphism in Java: the really easy kind (overloading) and the interesting
    kind (overriding)." Same thing here, there's nothing on this hiding trick
    you do with inner classes.

    Second observation, this "hiding" principle is still iffy. Even if it it's
    true that an inner class does not override the methods of its outer class
    (as Chris and others have demonstrated) still it is possible for an inner
    class to extend one of the methods of the outer class, much like a subclass
    would do for its parent. Fortunately I read a bit from Bruce Eckel's book
    where he explains this - and I've made a sample program to demonstrate:

    package temptests;

    class inners2
    {

    void printMessage()
    {
    System.out.println("hidiho");
    }

    public static void main(String[] args)
    {

    outerclass01 oc001 = new outerclass01();
    outerclass01.sucker t2 = oc001.new sucker();
    t2.lemmeSee();

    }
    }


    class outerclass01
    {

    void printMessage()
    {
    System.out.println("deedledeedledeedle");
    }

    class sucker extends inners2
    {

    void printMessage()
    {
    System.out.println("feefifofum");
    }

    void lemmeSee()
    {
    printMessage();
    super.printMessage();
    outerclass01.this.printMessage();
    }

    }

    }


    The output is "feefifofum" "hidiho" and "deedledeedledeedle". This mechanism
    enables me to extend methods with identical names, coming from two wholly
    unrelated classes (outerclass01 and inners2). While it's great that this
    sort of stuff is possible, I do believe, however, that it violates the
    spirit of what they were trying to do when they specified no multiple
    inheritance in Java.

    I would be interested if somebody strongly disagreed with this.

    Thanks,

    Ben.





    "Ben Wilson" <> skrytta an brickt
    news:408c4b31$0$10808$...
    > Hi, I'm hoping someone out there is an expert and can share some
    > authoritative insights.
    >
    > I'm working with inner classes in Java, and I'm finding myself unsatisfied
    > with the way they've been implemented, and frankly, somewhat alarmed. It

    is
    > true that an inner class can access the methods and object variables of

    its
    > enclosing class. However, it is also true that inner classes participate

    in
    > overriding - I can set up an inner class that overrides the members of its
    > enclosing class. However, inner classes can also be defined to extend
    > another class entirely.
    >
    > Hello? I thought Java didn't support multiple inheritance but here it is!
    >
    > Have a look at this sample code and tell me what's going on here:
    >
    > //inners2.java
    >
    > class inners2
    > {
    > void printMessage()
    > {
    > System.out.println("ladida");
    > }
    >
    > public static void main(String[] args)
    > {
    > new outerclass01().new sucker().printMessage();
    > }
    > }
    >
    > class outerclass01
    > {
    > void printMessage()
    > {
    > System.out.println("humdeedum");
    > }
    >
    > class sucker extends inners2
    > {}
    > }
    >
    > So there you go, what's the above code going to print when run? Is it
    > "ladida" or "humdeedum"?
    >
    > From seeing this I get the feeling that not a lot of thought got put into
    > defining what it was exactly that inner classes were supposed to do.

    Anybody
    > know what the story is here?
    >
    > Thanks,
    >
    > Ben.
    >
    >
    >
    >
    Ben Wilson, Apr 27, 2004
    #16
  17. Ben Wilson

    Tony Morris Guest

    It was I who posted that case, and it was to demonstrate the question:
    "Are private members inherited ?"

    --
    Tony Morris
    (BInfTech, Cert 3 I.T.)
    Software Engineer
    (2003 VTR1000F)
    Sun Certified Programmer for the Java 2 Platform (1.4)
    Sun Certified Developer for the Java 2 Platform


    "Adam" <> wrote in message
    news:c6ictd$blf$...
    > > I do not believe Java was supposed to let this sort of thing happen.

    > From
    > > seeing this I get the feeling that not a lot of thought got put into
    > > defining what it was exactly that inner classes were supposed to do.

    > Anybody
    > > know what the story is here?

    >
    > I'm having the same reservations about inner classes and
    > their possibilities. Once someone posted such a riddle here
    > (see below). I think it shows how bug prone can inner
    > (in this case - anonymous) classes be:
    >
    > public class T
    > {
    > private final String name;
    > protected void prname() { System.out.println(name); }
    > T(String name) { this.name = name; }
    >
    > public static void main(String[] args)
    > {
    > new T("main").doit();
    > }
    >
    > private void doit()
    > {
    > new T("anonymous inner")
    > {
    > void method()
    > {
    > prname();
    > }
    > }.method();
    > }
    > }
    >
    > What will be printed when you run it?
    >
    >
    Tony Morris, Apr 27, 2004
    #17
  18. Ben Wilson

    Adam Guest

    "Tony Morris" <> wrote in message
    news:c6kv7b$ma2$...
    > It was I who posted that case, and it was to demonstrate the

    question:
    > "Are private members inherited ?"


    Sorry, Tony for not mentioning you. I just could'n remember.
    Anyway, it's a great example for this topic too,
    presenting confusion that may arise when
    using inner/anonymous classes.

    Adam
    Adam, Apr 27, 2004
    #18
  19. Ben Wilson

    Chris Smith Guest

    Ben Wilson wrote:
    > First, two observations:
    > First observation: the literature makes a *real* lousy job of explaining
    > this.


    Yes, indeed. For many of us who've been around since Java 1.0.2 (and
    that includes many of those who write books), it seems natural to
    describe the old behavior of classes as "normal", and just know that
    nested/inner classes are the exception. It's a bad habit, and should be
    broken. You'll see the same thing regarding access specifiers: many
    books will give you a blanket statement that classes can only have
    public or package access, and then mention in chapter 17 somewhere that
    nested classes can have the full range of private, package, protected,
    or public just like any other member.

    It's good to get the difference between overriding and overloading down;
    but it only applies in cases where you're working with instance methods
    declared in a common supertype. For static methods, only overloading
    applies. For outer class methods, I'd wonder if use of the word
    "overloading" is justified... but the behavior is the same as if it
    were. The difference in the latter is really only conceptual in nature.

    > As a second example, take Peter van der Linden's book "Just Java 2 - Fifth
    > edition". He says, in his chapter on Polymorphism: "Polymorphism is a
    > complicated name for a straightforward concept. It is Greek for 'many
    > shapes' and it merely means using the same one name to refer to different
    > methods. 'Name reuse' would be a better term. There are two types of
    > polymorphism in Java: the really easy kind (overloading) and the interesting
    > kind (overriding)."


    Well, frankly I don't know what Peter was thinking. I respect Peter's
    opinion on most topics (and he used to be a fairly active participant in
    this newsgroup), but this is just dead wrong. Polymorphism has nothing
    to do with method overloading. It is the property of runtime dispatch
    of overridden methods.

    > Second observation, this "hiding" principle is still iffy. Even if it it's
    > true that an inner class does not override the methods of its outer class
    > (as Chris and others have demonstrated) still it is possible for an inner
    > class to extend one of the methods of the outer class, much like a subclass
    > would do for its parent.


    I still disagree with the terminology here.

    You should think of the ability of an inner class to call methods of its
    outer class as a convenience offered to you by the compiler, and nothing
    more. Any meaningful relationship between a method in an inner class
    and a similarly named method in an outer class is a myth. Exactly like
    any relationship between mutually overloaded methods is a myth. The
    sooner you understand that, the sooner this will make sense to you.

    In your example, there are exactly two classes that have a definite
    relationship, and they are inners2 and sucker. outerclass01 is just
    there, and is used by sucker to delegate a method call. That's it. The
    fact that the method 'printMessage' in sucker/inners2 has the same name
    and parameters as printMessage in outerclass01 is a coincidence. In
    fact, it has the unfortunate side-effect that it's harder to actually
    call that printMessage method, requiring you to use "OuterClass.this."
    to resolve the ambiguity.

    > The output is "feefifofum" "hidiho" and "deedledeedledeedle". This mechanism
    > enables me to extend methods with identical names, coming from two wholly
    > unrelated classes (outerclass01 and inners2). While it's great that this
    > sort of stuff is possible, I do believe, however, that it violates the
    > spirit of what they were trying to do when they specified no multiple
    > inheritance in Java.


    I really believe not. The similarity in name is coincidental, and has
    no semantic significance. The purpose of disallowing multiple
    inheritance in Java was to avoid overly complex method dispatch. There
    is no dispatch here; the compiler knows entirely at compile-time exactly
    which method you are calling.

    --
    www.designacourse.com
    The Easiest Way to Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Apr 27, 2004
    #19
  20. Ben Wilson wrote:
    > My confusion started with the explanation of inner classes as "getting
    > access to the members of its enclosing class". From this I assumed that this
    > access was just made available, also to the inner class's callable
    > interface. In other words, I thought it was bigger than it actually was.


    [...]

    > The principles of "hiding" members from the outer class from within the
    > inner class have many parallels with overriding, so it is easy to get
    > confused. My dissatisfaction started because I realised I could "hide" a
    > method from the outer class by making one with an identical signature from
    > an inner class, but once I did that I could never actually get a-hold of the
    > outer class with something like "super". But more about this later.


    Well, "super" itself doesn't work, and oughtn't, but a construct of the
    form Outer.this does. You even offer your own example later.

    > First, two observations:
    > First observation: the literature makes a *real* lousy job of explaining
    > this. Take Heller&Roberts book "Complete Java 2 Certification Study Guide
    > Fourth Edition". When they talk about reusing method names, very
    > specifically, they say "As you construct classes and add methods to them, in
    > some circumstances you will want to re-use the same name for a method. You
    > can do so two ways with Java. Re-using the same method name with different
    > arguments and perhaps a different return type is known as overloading. Using
    > the same method name with identical arguments and return type is known as
    > overriding." Apparantly this statement is incorrect or at best incomplete -
    > there is also this "hiding" thing. Since what I was doing was using the same
    > method name with identical arguments and return type, well, it just *had* to
    > be overriding, right? Well, sure shows me!


    No, you are applying the statement too broadly. You seem to have not
    grasped the fact that for all intents and purposes, an inner class is a
    *seperate* class from its containing class[es]. It has special access
    to its containing class[es], true, but that's irrelevant. When you add
    a method to an inner class you are not adding it to any containing
    class, so you H&R's statement does not apply.

    > As a second example, take Peter van der Linden's book "Just Java 2 - Fifth
    > edition". He says, in his chapter on Polymorphism: "Polymorphism is a
    > complicated name for a straightforward concept. It is Greek for 'many
    > shapes' and it merely means using the same one name to refer to different
    > methods. 'Name reuse' would be a better term. There are two types of
    > polymorphism in Java: the really easy kind (overloading) and the interesting
    > kind (overriding)." Same thing here, there's nothing on this hiding trick
    > you do with inner classes.


    Again, same comment: methods on an inner class are not methods on any
    containing class. Polymorphism is an aspect of relationships among
    classes. Unless the inner class extends a containing class (rarely good
    or appropriate) the concept of polymorphism is just not germane to the
    relationship between inner classes and their containing classes.

    > Second observation, this "hiding" principle is still iffy. Even if it it's
    > true that an inner class does not override the methods of its outer class
    > (as Chris and others have demonstrated) still it is possible for an inner
    > class to extend one of the methods of the outer class, much like a subclass
    > would do for its parent.


    No. Perhaps we're having another terminology problem, but the word
    "extend" has specific meaning in the context of Java: the relationships
    between a class and each of its superclasses. As we've been discussing,
    a class can override methods inherited from any class it extends, and it
    can offer overloaded versions of those methods.

    You are quite right that under certain circumstances an inner class may
    override a method inherited from its superclass, which itself hides a
    method of the containing class. The confusing mess that results is not
    a language problem, it is a language usage problem. Good designs,
    including those that use inner classes, do not exhibit such problems.
    You can shoot yourself in the foot in any language (see
    http://www-users.cs.york.ac.uk/~susan/joke/foot.htm, or any of the many
    variations available on the web) but that doesn't mean that all computer
    languages are therefore flawed.

    John Bollinger
    John C. Bollinger, Apr 27, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Robert Hanson

    Cookies Liability Issue

    Robert Hanson, Jul 2, 2003, in forum: ASP .Net
    Replies:
    2
    Views:
    344
    Yan-Hong Huang[MSFT]
    Jul 3, 2003
  2. Larry Rekow

    Access advantage/liability

    Larry Rekow, Aug 24, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    340
    Larry Rekow
    Aug 24, 2004
  3. Steven T. Hatton

    A summary of the #include liability

    Steven T. Hatton, Sep 8, 2004, in forum: C++
    Replies:
    15
    Views:
    495
    Ioannis Vranos
    Sep 9, 2004
  4. Carlo v. Dango
    Replies:
    14
    Views:
    999
    Alex Martelli
    Oct 19, 2003
  5. Pyenos
    Replies:
    2
    Views:
    371
    Pyenos
    Dec 27, 2006
Loading...

Share This Page