7

I am befuddled why this is allowed

public class Foo {
    class Bar extends Foo {
    }
}

Yet this is not allowed

public class Foo {
    class Bar extends Foo {
    }

    class Fooey extends Bar {
    }
}

The compiler informed that it can not reference Fooey.this before supertype constructor has been called.

And this is allowed

public class Foo {
    static class Bar extends Foo {
    }

    class Fooey extends Bar {
    }
}

What is going on here? And where can I go to find more information on how inner class inheritance works?

EDIT I came upon both rather poor ideas; inner class extends outer class and inner class extends other static inner class. I wasn't sure what exactly was going and how I should refactor this. I ended up just yanking out the inner classes and encapsulating them in the outer class.

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
sal
  • 23,373
  • 15
  • 66
  • 85

4 Answers4

6

First of all: Don't do this sort of thing. It's evil. Really, Java 1.1 should have been specified very much more restrictively, IMO.

There is confusion about which this to use from the Foo.Fooey constructor. The outer this (Foo.this) would work. But the actual this is a Foo but it can't be passed to the superconstructor because of rules about using this before the superconstructor returns (and besides having an outer instance the same instance as the inner instance is fecked up). The outer this on the superclass "((Bar)this).this$0" (IIRC), is also inaccessible due to restrictions on use of this.

The solution is to be explicit. Explicit is usually a good thing in my book (unless it becomes boilerplate).

public class Foo {
    class Bar extends Foo {

    }

    class Fooey extends Bar {
        Fooey() {
            Foo.this.super();
        }
    }
}

Better yet, don't have an inner class extend its own outer class, or extend any inner class.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • +1 for your first remark. If you have to explicitly make a constructor, because the default one doesn't compile, I'd say you're doing it wrong (design wise). – Jorn Oct 19 '09 at 16:43
  • Tom, thanks for the answer. I came upon both rather poor ideas; inner class extends outer class and inner class extends other static inner class. I wasn't sure what was going on. – sal Oct 26 '09 at 19:40
1

I guess the JLS and the answers to this question are a starting point

Java inner class and static nested class

Inner Classes and Enclosing Instances

Community
  • 1
  • 1
jitter
  • 53,475
  • 11
  • 111
  • 124
1

Tom Hawtin answer is correct.

Have also a look at java puzzler. The sample chapter contains this case and a few other "interesting" case you may want to have a look at.

vdr
  • 958
  • 6
  • 7
1

(Can't comment yet - I need 50 rep)

I'm also befuddled that this is allowed. A (non-static) inner class of an outer class is actually a member of that outer class. Read: an inner object is a member of its outer object. (Incidentally, every outer object must own an inner object but this is besides the point.)

The analogy I like to use is this: let Car be the outer class and let Wheel be the inner class. Every instance of Car must, and does, have at least one instance of Wheel as a member.

Now it doesn't make conceptual sense for an inner class to extend an outer class. I can't think of any real-world situations that call for an object being both a member and a type of another object. Set Theorists will recall the Axiom of Regularity and its consequences.

Think of it this way: Let Honda extend Car, and let Honda be an inner class nested inside Car. What you're saying here is that every Honda object is a Car object (duh), and every Car object has a Honda object. Only one of these statements makes sense, but both are allowed to be true in Java.

Or back to the previous analogy, you shouldn't let Wheel extend Car because then a Wheel would be a Car, and by definition must have another Wheel, which by the way is a Car and so must have a Wheel and forever and ever Amen. Constructing a Car object would result in an infinite loop of nested objects.

I'm upset that this is legal and does not produce a compile-time error.

chharvey
  • 8,580
  • 9
  • 56
  • 95
  • Imagine how upset you would be if you saw it in production code! – sal Aug 10 '11 at 18:15
  • If Honda extends Car, it does *not* mean every Car object has a Honda Object. – RAY Aug 11 '11 at 07:18
  • @RAY: yes but if Honda is nested inside Car (a.k.a. a "member" of Car) then it *does* mean every Car object has a Honda object. – chharvey Aug 16 '11 at 06:01
  • 1
    Not true. If Honda is an inner class of Car, a Car object does not necessarily have a Honda object. On the other hand, a Honda object must have a reference to the parent Car object. You need to be able to differentiate between a member class and a member variable. – RAY Aug 16 '11 at 08:43
  • Understood. Would I be correct in supposing that a Car object has a Honda object only if the `Car` class contains the line: `private Honda accord;`? – chharvey Aug 24 '11 at 00:13