![]() |
Inner Classes a liability
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. |
Re: Inner Classes a liability
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 |
Re: Inner Classes a liability
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. |
Re: Inner Classes a liability
> 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? |
Re: Inner Classes a liability
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 chris@kiffer.eunet.be /k/ Embedded Java Solutions |
Re: Inner Classes a liability
"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 |
Re: Inner Classes a liability
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 |
Re: Inner Classes a liability
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] > > 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 ;-)? 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 |
Re: Inner Classes a liability
"Michael Rauscher" <michlmann@gmx.de> wrote in message
news:c6jbl3$iuu$05$1@news.t-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] > > > > 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 ;-)? > > 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 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. |
Re: Inner Classes a liability
"Adam" <NOTFORSPAM.a_szczeblewski@poczta.onet.pl> 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 - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.' |
| All times are GMT. The time now is 05:13 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.