we know in Java, there is no multiple inheritance, how will you justify it with this example.
Class A
{
has some features
Class B extends Class C
{
I can access A + C's features, B is child of two parents?
}
}
B is an inner class, with respect to A. It is not subclassing A on the other hand.
More accurately, B is a non-static nested class (which makes it an inner class). A nested class is a member of its enclosing class. Inner classes are allowed to have access to all members of the class that nests them. A private access specifier declared on a member of the enclosing class will not prevent an inner class from accessing the member.
The difference between inheritance via a sub-class and access to members via inner classes is that inheritance of members allows for members to shadowed (for attributes) and overridden (for methods). Inner classes cannot shadow enclosing class attributes, they will have access to them.
To simplify this even further, consider the code sample:
class C
{
void c()
{}
}
public class A {
void a(){}
class B extends C
{
// a new member of B
void b()
{
}
//does not override A.a()
void a()
{
a(); //invokes A.a() as B has access to it.
super.a(); //illegal
}
//overrides C.c()
#Override
void c()
{
super.c(); //invokes C.c()
}
}
}
Notice that you cannot invoke super.a() from the nested class. That's the difference between inheriting a member and merely accessing it.
Further reading
The Java Language tutorial on classes and objects.
B is not a child of two parents, it's a "child" of C, but has access to A's attributes, it's a part of A but not a subclass of it.
you can run the following code to be sure:
class Main {
public void bar() {
Object o = new B();
System.out.println("is B subclass of Main:" + (o instanceof Main));
System.out.println("is B subclass of C:" + (o instanceof C));
}
public class C { }
public class B extends C { }
public static void main(String[] argv) {
Main a = new Main();
a.bar();
}
}
it will print false since o (which is a B) is not an instacneof Main for first question, but true for 2nd question, since B is an instance of C
EDIT: editted the code to make it more readable (in my opinion at least..)
"multiple inheritance" refers to having more than one immediate parent.
In your example, A surrounds B and B is the parent of C, but this does not make A the parent of C.
If it was multiple inheritance then both A and B would be the parents of C (C extends A, B), and this can not be done in Java.
(and as a side note: In Java, if no parent is explicitly specified, then java.lang.Object is silently used. This is why every method has a toString()).
Related
I have two child classes B and C which inherit from one parent class A. Is it possible that I can make certain functions of class A accessible in B but not in C in java?
Well i don't know a way to forbid it in the Code. But you could just override and then don'f fill them.
If what you want is to forbid to call destroyEverything() from class C:
public class A {
public void travel() {
System.out.println("Travel from A");
}
public void makePee() {
System.out.println("Call from A");
}
}
public class B extends A {
public void travel() {
super.travel();
System.out.println("Travel from B");
}
public void makePee() {
super.makePee();
System.out.println("Call from B");
}
}
Then, on C:
public class C extends A {
public void travel() {
super.travel();
System.out.println("Travel from C");
}
public void makePee(){
throw new UnsupportedOperationException("Not supported from C");
}
}
BUT, if what you want is to not inherit stuff from A, it is probably a flaw at the design of your class hierarchy and class C should not inherit from A.
Example of design flaw: Class A is Animal, class B is Beaver, and you want your class C Cadillac to inherit stuff from Animal since Animal already has the method travel.
Since maybe you don't want to inherit the method makePee (every animal urinates, but Cadillacs don't), it is better to move Cadillacs (class C) to another class hierarchy or find another class design
As per my thinking it is not possible.
Let's see the one real time example->
A Parent have a two child then both are able to access parent property .it is there no restriction on that you can not use this or you can not use this.
And if you want to do like that then you can implicitly write logic in B class also
Java does not support multiple inheritance. One of the reasons is that there could be an ambiguity between methods while inheriting. For example, in the below scenario, there will be an ambiguity to which version of "LevelMethod()" should be inherited in Class “Level3”
class Level1{
public void LevelMethod(){
System.out.println("Level1 method");
}
}
class Level2{
public void LevelMethod(){
System.out.println("Level2 method");
}
}
class Level3 extends Level1,Level2{
}
But, same kind of ambiguity might occur in the following scenario through multi-level inheritance to which version of "LevelMethod()" should be inherited in
Class “Level4”.
class Level1{
public void LevelMethod(){
System.out.println("Level1 method");
}
}
class Level2 extends Level1{
public void LevelMethod(){
System.out.println("Level2 method");
}
}
class Level3 extends Level2{
public void LevelMethod(){
System.out.println("Level3 method");
}
}
class Level4 extends Level3{
}
How java is able to resolve ambiguity in multilevel inheritance, but not in multiple inheritance?
The ambiguity exists when there is no mechanism for conflict resolution.
On single inheritance, the children override the methods on their parents, the method lookup has a clear resolution with no conflicts, since there is an order.
Classic multiple inheritance does not specify conflict resolution mechanism and thus the diamond problem appears.
FYI other models like mixins specify a linearization mechanism for implicit conflict resolution, while traits require you to make explicit the algebra for conflict resolution.
The method being invoked in the inheritance hierarchy will depend on the object type. Each subclass is overriding the parent's "levelMethod".
Try with a few examples
Level1 level = new Level1();
level1.levelMethod(); //Prints "Level1 method"
Level1 level = new Level2();
level.levelMethod(); //Prints "Level2 method"
Level1 level = new Level3();
level.levelMethod(); //Prints "Level3 method"
and so on...
Objects in java are nothing but simply references. So, it doesn't matter whether two or more classes having is-a relationship have same method because it'll depend on which object calls the method, because references will be different (identified by their hashCode). in your given code, if object of Level 2 calls the method LevelMethod() then the context of class Level 2 is been referred, so evidently Java will interpret results from LevelMethod() of Level 2.
But as object of super class can refer object of child class, while calling LevelMethod() you'd need to specify of which class.
If you want to prove that references are different then execute this program:
class A{
public void cmethod(){
System.out.println("Class A");
}
}
class B extends A{
public void cmethod(){
System.out.println("Class B");
}
}
class C extends B{
public void cmethod(){
System.out.println("Class C");
}
}
class MainClass{
public static void main(String[] args){
A aObj = new A();
B bObj = new B();
C cObj = new C();
System.out.println(aObj.toString());
System.out.println(bObj.toString());
System.out.println(cObj.toString());
}
}
Explanation: If you create your own class and don't override the method toString(), then Object class will call it's default toString() method which displays Class#refHashCode (All classes are child class of class Object).
(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.
Suppose I have the structure
class A {
class B {}
class C extends B {}
}
It seems that instances of C should have 2 references to the root class A: the first is inherited from B superclass, the second is own implicit inner class reference. My question: does JVM (HotSpot) optimize this case and keep only one reference to the root class?
I decompiled A.class and got this result which shows two references to A, one from B and one from C. But this actually means that C actually has two references - one is its own and the other is inherited from B.
class A {
class B {
final A this$0;
B() {
this$0 = A.this;
}
}
class C extends B {
final A this$0;
C() {
this$0 = A.this;
}
}
}
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)