Why can't outer classes extend inner classes?

Why can't I do this / is there a workaround for this:

package myPackage; public class A { public class B { } } 

 package myPackage; import myPackage.AB; public class C extends B { } 

 package myPackage; public class Main { public static void main(String[] args) { A myA = new A(); C myC = myA.new C(); } } 

Two compilation errors:

  • In public class C extends B , No enclosing instance of type A is available due to some intermediate constructor invocation

  • On C myC = myA.new C(); , AC cannot be resolved to a type

Honestly, I think a conceptual idea sounds like this: I want to subclass B so that when I create B for A, I have the opportunity to make it functionality in B or functionality in C.

Four workarounds / solutions that I don't need and why I don't want them:

  • "Solution: put C inside A." I do not want this because if I cannot change the code for A.java (are there applications that have this limitation)? What if A is part of another API? Then I need to create a new file for C, as I did here.

  • "Solution: Put C inside a class D that extends A." I do not want this, because then C is limited only to an instance of instances of type D. I want to create a class that extends B, which can be created in all instances of type A (there are applications that need this). Therefore, I need C to not be closed by another class, as I did here.

  • (Added as an editing question - see JoshuaTaylor answer for sample code) "Solution: make statics B". I don't want this because if the functionality in B needs to access its encompassing instance of A (are there applications that need it)? Therefore, I need B to not be static, as I did here. (Editing 2nd question: you can make B static and create your constructor in your enclosing instance, storing it in a protected variable to access your children, but this is less elegant than the accepted RealSkeptic answer)

  • Deleted. See edit below.

So, if your answer tells me that I am doing one of the above, this is not the answer to this question, although it may be useful to other people.

If your answer: β€œThis is just a flaw in the Java language, you simply cannot fulfill this conceptual idea,” is a good answer, and you should post it. Just a warning though: I will hold on to marking your answer, as is the case in case you are mistaken. If this is your answer, I would really appreciate it if you have an explanation why this language restriction exists (as the name of this question).

Thanks for any help.

EDIT: JoshuaTaylor's answer raises a valid option: you can anonymously and avoid writing a constructor, as in the accepted RealSkeptic answer. I initially abandoned this idea because it does not allow you to access an instance of C enclosed through A through "A.this". However, since then I have learned that C does not have a spanning instance of A unless it is defined in the definition of A as a nested class. Therefore, note that none of the solutions below allows you to access an instance of environment A that encloses the ancestor of B from B by writing "A.this" in method C. Classes can only use ".this" to access types that they are nested in particular. However, if B has functionality that accesses an enclosing instance of A, either an anonymous class using the JoshuaTaylor method or any other class using the RealSkeptic method is required.

+7
java nested-class
source share
2 answers

Well, it can be done, but you must remember that every constructor should call it a super constructor, explicitly or implicitly. That's why you get "A missing instance of type A is available due to an intermediate constructor error." C The no-args constructor tries to implicitly invoke the B no-args constructor, and it cannot do this without A

So you are fixing your C as:

 public class C extends B { public C(A enclosing) { enclosing.super(); } } 

And then you can create a new C using:

 A myA = new A(); C myC = new C(myA); 

Answers to questions in the comments

  • @ Andy Turner asked:

    If you explicitly pass A to the constructor of C, can't C be static and have A as the "regular old" member variable in C on which you invoke the necessary methods?

    It should be noted that C is neither a static nor an inner class. This is a separate public class that extends the inner class B. The implementation of class B cannot be known to the author of C, therefore, he cannot know what methods A will use, and also does not have access to any private members of A, since C is not a member of A. But B does, and B requires an instance of A. An alternative approach would be composition rather than inheritance (where C has an instance of B and delegates operations to it), but if he wants to create this instance of B and not pass it inside, that's it equally required instance A, although it will use e enclosing.new B , instead enclosing.super .

  • @rajuGT asked:

    Is C an individual object? if so, why is an object needed? and what is the relationship between myA and myC in this case?

    Yes, C is a separate entity. He will not need any of his own methods. But if he tries to call (or inherits and does not redefine) the methods from B that are associated with access to A, then A is required to implement B. Formally, of course, any instance of B requires a reference to A even if it does not actually use it. The connection between myA and myC is that myA is the immediate spanning instance of myC with respect to B This term is taken from JLS section 8.1.3 :

    For each superclass S C , which itself is a direct inner class of a class or SO interface, there is an SO instance associated with i , known as a direct instance of i relative to S An approaching instance of an object with respect to its direct superclass of the class, if one exists, is determined when the constructor of the superclass is called using the explicit constructor invocation operator (Β§8.8.7.1)

Official link for this use.

This use is known as the qualified superclass constructor invocation statement and is referred to in JLS, section 8.8.7.1 - Explicit constructor invocations .

A call to the superclass constructor begins either with the keyword super (possibly preceded by explicit type arguments) or the Primary expression or expression. They are used to call the constructor of the direct superclass. They are further divided:

  • Unqualified calls to the superclass constructor begin with the super keyword (possibly preceded by an explicit type argument).

  • Qualified calls to the superclass constructor begin with a primary expression or expression. They allow the subclass constructor to explicitly specify a newly created object that immediately includes an instance relative to the direct superclass ( Β§8.1.3 ). This may be required when the superclass is an inner class.

At the end of this section, you can find examples for explicit constructor invocation instructions, including this use.

+10
source share

You can easily extend nested static classes.

Update: You mentioned that you do not want this first solution, but the wording of the question may lead to people being ready for the inner class to be static, so I will leave it in the hope that it will be useful to them. A more correct answer to your exact question is in the second section of this answer.

You can, but the inner class must be static, because if it is not, then each instance of the inner class has a link to the enclosing instance of the outer class. A static nested class does not have this link, and you are free to distribute it.

 public class Outer { public static class Inner { } } 
 public class InnerExtension extends Outer.Inner { } 

But you can also extend nested non-static classes

 package test; public class Outer { public class Inner { public String getFoo() { return "original foo"; } } } 
 package test; public class Extender { public static void main(String[] args) { // An instance of outer to work with Outer outer = new Outer(); // An instance of Outer.Inner Outer.Inner inner = outer.new Inner(); // An instance of an anonymous *subclass* of Outer.Inner Outer.Inner innerExt = outer.new Inner() { @Override public String getFoo() { return "subclass foo"; } }; System.out.println("inner class: "+inner.getClass()); System.out.println("inner foo: "+inner.getFoo()); System.out.println(); System.out.println("innerExt class: "+innerExt.getClass()); System.out.println("innerExt foo: "+innerExt.getFoo()); } } 
 inner class: class test.Outer$Inner inner foo: original foo innerExt class: class test.Extender$1 innerExt foo: subclass foo 
+3
source share

All Articles