Why can\'t I do this/is there a workaround to accomplish this:
package myPackage;
public class A {
public class B {
}
}
Well, it can be done, but you have to remember that each constructor needs to call its super constructor, explicitly or implicitly. That's why you get the "No enclosing instance of type A is available due to some intermediate constructor invocation" error. C
's no-args constructor is trying to implicitly call B
's no-args constructor, and it can't do that without an A
.
So you fix your C
to be:
public class C extends B {
public C(A enclosing) {
enclosing.super();
}
}
And then you can create a new C
by using:
A myA = new A();
C myC = new C(myA);
Answers to the questions in the comments
@Andi Turner asked:
If you are explicitly passing in an A to the constructor of C, can't C now be static, and have A as a "plain old" member variable in C on which you invoke the required methods?
It should be noted that C is neither static nor an inner class. It is an individual public class which is extending an inner class B. The implementation of the class B may not be known to the author of C, so it cannot know what methods would be using A, nor does it have access to any private members of A, as C is not a member of A. But B does, and B requires the A instance. An alternative approach would be composition rather than inheritance (where C holds a B instance and delegates operations to it), but if it wants to create that B instance rather than have it passed inside, it will still need an A instance, although it will use enclosing.new B
rather than enclosing.super
.
@rajuGT asked:
Is C is an individual entity? if so, why does it need A object? and what is the association between myA and myC in this case?
Yes, C is an individual entity. It wouldn't need A for any of its own methods. But if it tries to call (or inherits and doesn't override) methods from B that involve access to A - then that A is required by the implementation of B. Formally, of course, any instance of B requires a reference to A even if it doesn't actually make use of it. The association between myA
and myC
are is that myA
is the immediate enclosing instance of myC
with respect to B
. This term is taken from section 8.1.3 of the JLS:
For every superclass
S
ofC
which is itself a direct inner class of a class or interfaceSO
, there is an instance ofSO
associated withi
, known as the immediately enclosing instance ofi
with respect toS
. The immediately enclosing instance of an object with respect to its class' direct superclass, if any, is determined when the superclass constructor is invoked via an explicit constructor invocation statement (§8.8.7.1)
Official reference for this usage
This usage is known as a qualified superclass constructor invocation statement, and is mentioned in the JLS, section 8.8.7.1 - Explicit Constructor Invocations.
Superclass constructor invocations begin with either the keyword
super
(possibly prefaced with explicit type arguments) or a Primary expression or an ExpressionName. They are used to invoke a constructor of the direct superclass. They are further divided:
Unqualified superclass constructor invocations begin with the keyword
super
(possibly prefaced with explicit type arguments).Qualified superclass constructor invocations begin with a Primary expression or an ExpressionName. They allow a subclass constructor to explicitly specify the newly created object's immediately enclosing instance with respect to the direct superclass (§8.1.3). This may be necessary when the superclass is an inner class.
At the end of that section, you can find examples for explicit constructor invocation statements, including this usage.
Update: You've mentioned that you don't want this first solution, but the phrasing of the question may lead people to it who are willing to have the inner class be static, so I'll leave this in the hopes that it's useful to them. A more proper answer to your exact question is in the second section of this answer.
You can, but the inner class has to be static, because if it's not, then every instance of the inner class has a reference to the enclosing instance of the outer class. A static nested class doesn't have that reference, and you can extend it freely.
public class Outer {
public static class Inner {
}
}
public class InnerExtension extends Outer.Inner {
}
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's class: "+inner.getClass());
System.out.println("inner's foo: "+inner.getFoo());
System.out.println();
System.out.println("innerExt's class: "+innerExt.getClass());
System.out.println("innerExt's foo: "+innerExt.getFoo());
}
}
inner's class: class test.Outer$Inner
inner's foo: original foo
innerExt's class: class test.Extender$1
innerExt's foo: subclass foo