inner class extended by another inner class [duplicate] - java

This question already has answers here:
Why does a sub-class class of a class have to be static in order to initialize the sub-class in the constructor of the class?
(2 answers)
Closed 5 years ago.
Error occur when class C extends B. But, when I write new A().super(); problem is solved. Please consider following code:
public class A {
public class B extends A {
public class C extends B {
public C() {
// No enclosing instance of type A is available due to some intermediate constructor error
// new A().super();
}
}
}
}
My question is why class C cannot extend Class B? Why calling new A().super(); solved the problem? What does it mean? Is there better way to solve it (without using static nested class)?

Simplest code snippet which will be compiled and executed printing 'OK':
public class A {
public class B extends A {
public class C extends B {
public C() {
System.out.println("OK");
}
}
}
public static void main(String[] args) {
new A().new B().new C();
}
}
Here is another example of instantiation of A, B and C. That is, class C can extend Class B as of initial code snippet from your question. Your code is correct in terms of syntax, and can be compiled without adding any unnecessary new A().super()
For consideration, let's refer to the tutorial for inner classes, those by definition are non-static. For static case the correct name is static nested class
An instance of InnerClass can exist only within an instance of OuterClass
To instantiate an inner class, you must first instantiate the outer class
That means, that inner class exists only in context of particular OuterClass instance rather than OuterClass class, that's why new A() does solve the problem, providing runtime instance within which classes B and C do exist

Related

Why I am not able to call a.getHello()? [duplicate]

This question already has answers here:
private method in inheritance in Java
(6 answers)
How can a derived class invoke private method of base class?
(7 answers)
Closed 5 years ago.
public class A {
private void getHello(){
System.out.println("Prints A");
}
}
class B extends A {
public void getHello(){
System.out.println("Prints B");
}
}
class Test{
public static void main(String[] args) {
A a = new B();
}
}
I am creating private method in class A
creating public method with same name in class B by extending class A
Even after creating object for B with A reference
why I am not able to call getHello()?
getHello method is private for class A and you may call it only from this class.
Even if create an instance of class A in some other class you will not be able to access getHello() method.
This is also invalid code.
class Test {
public static void main(String[] args) {
A a = new A();
a.getHello();
}
}
Here is Java documentation.
Be declaring it as a type of A you are losing the implementation details of B although there still there.
A a = new B(); // a.getHello() is not accessible because it looks it up in A
B b = new B(); // a.getHello() is accessible because it calls it in B
Even if the getHello() method would be public in A it would still call it for the instance of B.
As Java Language Specification (https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6) states:
A private class member or constructor is accessible only within the body of the top level class (§7.6) that encloses the declaration of the member or constructor. It is not inherited by subclasses.
When you create a reference to object of A class it is not possible to get access to this method from outside of this class in your case.

Static inner class extending abstract outer class in java [duplicate]

This question already has answers here:
Java inner class and static nested class
(28 answers)
Closed 5 years ago.
I saw this pattern today and it confused me a lot:
abstract class A {
// does something
static class B extends A {
// does something as well
}
}
Two weird things I found about it:
Static class can be initialised using new A.B().
Static class is not unique in the application (therefore, not really static), as each initialisation creates a new object.
I am still perturbed as to why to use such a pattern? And does static class in this context mean, that you can access it's constructors statically, without needing to create an instance of A, but not really it being a unique in any way in the app?
EDIT:
OK, so I think my understanding of static classes came from C#. I am clear on the staticness of java classes now. But when would you use such a pattern (where inner static class is extending outer abstract one) and why?
static class doesnt have access to the outer class methods and variables, they keyword kind of means that it is a separated class.
class Out {
int i; void x(){}
static class In() {
i++; x(); // not valid instructions
}
class In2() {
i++; x(); // valid instructions
}
}
To instantiate a static inner class you just create a object of it:
Out.In obj = new Out.In();
non-static needs a instance of the outer class to be instantiated with:
Out o = new Out();
Out.In2 obj = new o.In2();
(If instantiating In2 inside of Out the word this is implicit)

Why can't a local class that extends an inner class access the inner class enclosing instance?

(I keep re-reading that question title and thinking about how ridiculous it must look, but I assure you that is the best description of the problem, and I have an actual application where this is the best structure. I swear I'm not crazy.)
Consider the following. Each block is a separate file:
package myPackage;
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
}
}
package myPackage;
import myPackage.A.B;
public class Main {
public static void main(String[] args) {
class C extends B {
public C(A enclosingInstance) {
enclosingInstance.super();
}
public void show() {
System.out.println(A.this.i);
}
}
A myA = new A(2);
C myC = new C(myA);
myC.show();
}
}
Note that the enclosingInstance business is to solve a problem involving intermediate constructor invocations. See "Why can't outer classes extend inner classes?".
I would expect the output to be "2". But instead, I have a compile error on System.out.println(A.this.i);:
No enclosing instance of the type A is accessible in scope
I think the programmatic concept I'm trying to solve is sound: Create a new type of B inside main to give to A that uses things from A that types of B can access.
So what am I doing wrong, or why isn't this possible in java?
EDIT/UPDATE: Note that the same error appears when the code in main is moved to a non-static method. That is to say, I tried moving everything inside of static void main to a new, non-static method of class Main called go(). Then I changed static void main to the single line new Main().go();. The error is in the same spot. So it doesn't seem to be an issue of class C being defined in a static context.
You want A.this to refer to the enclosing instance of the B instance. But why should it? That's not what the syntax means. A.this would mean the enclosing A instance of the C instance, and this does not make sense because C is not an inner class of A.
To make this clearer, here is an example where C is an inner class of A.
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
void foo() {
System.out.println(A.this.i);
}
}
public class C extends B {
C(A a) {
a.super();
}
void bar() {
System.out.println(A.this.i);
}
}
public static void main(String[] args) {
A a1 = new A(1);
A a2 = new A(2);
C c = a1.new C(a2);
c.foo();
c.bar();
}
}
Here C extends B, and both C and B are inner classes of A. Therefore any C has an enclosing A instance, and it also has an enclosing A instance when considered as a B, and these enclosing instances are different (as proved by the fact that foo and bar print different numbers).
So, A.this could not possibly mean what you want it to mean, because it already means something else. I guess the reason why the language designers didn't come up with other syntax to mean the enclosing instance of a super class, is because such syntax would be very complicated, with little pay-off (simple workarounds already exist).
This is absurd code that you should never write for production.
It is, in part, explained in the documentation for Explicit Constructor Invocations
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.
All this to say that C is a local class (which is an inner class, which is kind of nonsense because if you declare it in a static method there is no enclosing instance) that is a subclass of B but not a nested class of A. As such, there is no enclosing instance. An instance of C does not have an enclosing instance. (Though it would if you declared it in an instance method, but that would be an instance of Main.)
The newly created object's immediately enclosing instance (from JLS) is specified indirectly through a constructor parameter.
You'd have to store it yourself
private A enclosingInstance;
public C(A enclosingInstance) throws CloneNotSupportedException {
enclosingInstance.super();
this.enclosingInstance = enclosingInstance;
}
and since A#i is public, you can access it normally
public void show() {
System.out.println(enclosingInstance.i);
}
With the provided information, I would do this :
public class B {
protected A getOuterInstance() {
return A.this;
}
}
and just let C inherit and use this method. I know you dislike this method but this is the simplest answer I can see. With more information, I would probably propose a design which would try not involving any inner class as this is not a normal use case for inner classes.

Creating instance of inner class outside the outer class in java [duplicate]

This question already has answers here:
What causes error "No enclosing instance of type Foo is accessible" and how do I fix it?
(11 answers)
Closed 8 years ago.
I'm new to Java.
My file A.java looks like this:
public class A {
public class B {
int k;
public B(int a) { k=a; }
}
B sth;
public A(B b) { sth = b; }
}
In another java file I'm trying to create the A object calling
anotherMethod(new A(new A.B(5)));
but for some reason I get error: No enclosing instance of type A is accessible. Must qualify the allocation with an enclosing instance of type A (e.g. x.new B() where x is an instance of A).
Can someone explain how can I do what I want to do? I mean, do I really nead to create instance of A, then set it's sth and then give the instance of A to the method, or is there another way to do this?
Outside the outer class, you can create instance of inner class like this
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
In your case
A a = new A();
A.B b = a.new B(5);
For more detail read Java Nested Classes Official Tutorial
In your example you have an inner class that is always tied to an instance of the outer class.
If, what you want, is just a way of nesting classes for readability rather than instance association, then you want a static inner class.
public class A {
public static class B {
int k;
public B(int a) { k=a; }
}
B sth;
public A(B b) { sth = b; }
}
new A.B(4);
Interesting puzzle there. Unless you make B a static class, the only way you can instantiate A is by passing null to the constructor. Otherwise you would have to get an instance of B, which can only be instantiated from an instance of A, which requires an instance of B for construction...
The null solution would look like this:
anotherMethod(new A(new A(null).new B(5)));

Hierarchy of inner classes in Java

I am using a hierarchy of inner classes to represent some data in an application and I have run into an error message that I simply do not understand. My code can be boiled down to the following minimal example:
public class A {
public class B extends A {}
public class C extends B {}
}
Javac (and my IDE of course) fails to compile the code with the following error message:
A.java:3: cannot reference this before supertype constructor has been called
public class C extends B {}
^
1 error
I didn't write this anywhere. There is no more code than provided above, so I assume javac has generated something related to the inner class.
I have found another way to represent my data, so I am simply interested in a good explanation of why it doesn't compile.
You need an outer class instance to create an inner class instance i.e something like new Outer().new Inner();
To extend the inner class (Parent inner class) with another inner class (child inner class), you cannot call the constructor of 'parent inner class' because the instance of 'outer class' is not there.
Try like this,
public class A{
public class B extends A {
B() { }
}
public class C extends B {
C() {
new A().super();
}
}
public static void main(String args[]) {
}
}
Similar question : Odd situation for “cannot reference this before supertype constructor has been called”
The other poster is correct, but how to fix? Simply make your class static:
public class A {
public static class B extends A {}
public static class C extends B {}
}
Note that if your inner classes refer to fields of the outer class, you can't make them static, otherwise you can (and should - doing so reduces dependencies).
Your code compiles under Java 7.
The following workaround compiles under Java 6.
public class C extends B
{
public C()
{
A.this.super();
}
}
#saugok's link to the previous question quoted Joshua's explanation. Basically he argued that since C is subclass of A, C inherits A's members as C's members. Therefore B is also C's member. (For example a class literal C.B.class is valid.) Therefore he argues that C.this is the enclosing instance for B's super(), therefore C(){super();} is actually C(){C.this.super();}. Since C.this cannot be evaluated before super constructor, thus the error.
However this doesn't seem to be warranted by the language spec. See #8.1.3. Since B is not immediately lexically enclosed by C, B is not a direct inner class of C, there is no reason to say that B's direct enclosing instance must be an instance of C.
We need to pass B() an instance of A. It is true that C.this is an instance of A ( try this code: new C().new B().new C().new B();) therefore it could be a candidate. There is also another candidate, A.this. A.this is available and ready to use (it's passed in as the hidden parameter to C()).
According to javap, javac 7 compiles the code into
class B
private A this$0;
B( A a )
this$0 = a;
super(); // A()
class C extends B
private A this$0;
C( A a )
this$0 = a;
super( a ); // B(A)

Categories