Use super() with reference in Java - java

I have three classes
class WithInner {
class Inner {}
}
public class InheritInner extends WithInner.Inner
{ //constructor
InheritInner(WithInner wi) {
wi.super();
}
}
This example is taken from Eckel's Thinking in Java. I can't understand why we can't call wi = new WithInner(); instead of .super()? And while calling wi.super() we are calling Object's default constructor, aren't we?

Inner classes maintain a reference to an outer instance (the exception is static inner classes). In this case, a WithInner.Inner instance has a reference to the containing WithInner instance. This association is created when the inner class is instantiated.
You cannot create an instance of the inner class without a reference to the outer class. A class that extends such an inner class also has by implication such a reference, and needs to delegate to the inner class constructor in order to set up the association. The syntax for doing that is as shown in your example:
wi.super();
Here, super() essentially refers to the superclass constructor - that is, the WithInner.Inner constructor. The constructor takes no parameters formally, but it still needs a reference to the outer instance (of type WithInner). The line as a whole essentially means "call the superclass constructor, and associate with the wi instance".
Compare to the syntax for instantiation of an inner class with explicit association:
wi.new WithInner.Inner()
Yes, that's also valid syntax. It's not commonly seen in the wild, though (because inner class instances are normally only created from within the outer class anyway, and in that case the association is implicit - there's no need in that case for this syntax, which provides the association explicitly).
With specific reference to your question:
I can't understand why we can't call wi = new WithInner(); instead of .super()?
This would not associate the created WithInner instance with the inner class instance. You'd get a compile-time error because your InheritInner constructor wouldn't any longer be explicitly calling the synthesized superclass constructor, and it can't be called implicitly because it needs the outer instance reference for association. It's probably easiest to think of the outer instance reference as a hidden parameter to the inner class constructor (indeed, that's how it's implemented under the hood).
And while calling wi.super() we are calling Object's default constructor, aren't we?
No, you're calling the WithInner.Inner constructor, which has a "hidden" parameter for the outer instance reference; wi is essentially passed to the WithInner.Inner constructor as a hidden parameter value.

Related

Program initialises both subclas and superclass constructors at once [duplicate]

Consider this code:
class Test {
Test() {
System.out.println("In constructor of Superclass");
}
int adds(int n1, int n2) {
return(n1+n2);
}
void print(int sum) {
System.out.println("the sums are " + sum);
}
}
class Test1 extends Test {
Test1(int n1, int n2) {
System.out.println("In constructor of Subclass");
int sum = this.adds(n1,n2);
this.print(sum);
}
public static void main(String[] args) {
Test1 a=new Test1(13,12);
Test c=new Test1(15,14);
}
}
If we have a constructor in super class, it will be invoked by every object that we construct for the child class (ex. Object a for class Test1 calls Test1(int n1, int n2) and as well as its parent Test()).
Why does this happen?
The output of this program is:
In constructor of Superclass
In constructor of Subclass
the sums are 25
In constructor of Superclass
In constructor of Subclass
the sums are 29
Because it will ensure that when a constructor is invoked, it can rely on all the fields in its superclass being initialised.
see 3.4.4 in here
Yes. A superclass must be constructed before a derived class could be constructed too, otherwise some fields that should be available in the derived class could be not initialized.
A little note:
If you have to explicitly call the super class constructor and pass it some parameters:
baseClassConstructor(){
super(someParams);
}
then the super constructor must be the first method call into derived constructor.
For example this won't compile:
baseClassConstructor(){
foo();
super(someParams); // compilation error
}
super() is added in each class constructor automatically by compiler.
As we know well that default constructor is provided by compiler automatically but it also adds super() for the first statement.If you are creating your own constructor and you don't have either this() or super() as the first statement, compiler will provide super() as the first statement of the constructor.
Java classes are instantiated in the following order:
(at classload time)
0. initializers for static members and static initializer blocks, in order
of declaration.
(at each new object)
create local variables for constructor arguments
if constructor begins with invocation of another constructor for the
class, evaluate the arguments and recurse to previous step. All steps
are completed for that constructor, including further recursion of
constructor calls, before continuing.
if the superclass hasn't been constructed by the above, construct the
the superclass (using the no-arg constructor if not specified). Like #2,
go through all of these steps for the superclass, including constructing
IT'S superclass, before continuing.
initializers for instance variables and non-static initializer blocks, in
order of declaration.
rest of the constructor.
That´s how Java works. If you create a child object, the super constructor is (implicitly) called.
In simple words if super class has parameterized constructor, you need to explicitly call super(params) in the first line of your child class constructor else implicitly all super class constructors are called untill object class is reachead.
The subclass inherits fields from it's superclass(es) and those fields have to get constructed/initialised (that's the usual purpose of a constructor: init the class members so that the instance works as required. We know that some people but a lot more functionality in those poor constructors...)
Constructor implements logic that makes the object ready to work. Object may hold state in private fields, so only its class' methods can access them. So if you wish instance of your subclass be really ready to work after calling constructor (i.e. all its functionality including inherited from base class is OK) the base class's constructor must be called.
This is why the system works this way.
Automatically the default constructor of base class is called. If you want to change this you have to explicitly call constructor of base class by writing super() in the first line of your subclass' constructor.
The base class constructor will be called before the derived class constructor. This makes sense because it guarantees that the base class is properly constructed when the constructor for the derived class is executed. This allows you to use some of the data from the base class during construction of the derived class.
When we create an object of subclass, it must take into consideration all the member functions and member variables defined in the superclass. A case might arise in which some member variable might be initialized in some of the superclass constructors. Hence when we create a subclass object, all the constructors in the corresponding inheritance tree are called in the top-bottom fashion.
Specifically when a variable is defined as protected it will always be accessible in the subclass irrespective of whether the subclass is in the same package or not. Now from the subclass if we call a superclass function to print the value of this protected variable(which may be initialized in the constructor of the superclass) we must get the correct initialized value.Hence all the superclass constructors are invoked.
Internally Java calls super() in each constructor. So each subclass constructor calls it's superclass constructor using super() and hence they are executed in top-bottom fashion.
Note : Functions can be overridden not the variables.
Since you are inheriting base class properties into derived class, there may be some situations where your derived class constructor requires some of the base class variables to initialize its variables. So first it has to initialize base class variables, and then derived class variables. That's why Java calls first base class constructor, and then derived class constructor.
And also it doesn't make any sens to initialize child class with out initializing parent class.
Constructor of Super class in called first because all the methods in the program firstly present in heap and after compilation they stores in to the stack,due to which super class constructor is called first.
There is a default super() call in your default constructors of sub classes.
//Default constructor of subClass
subClass() {
super();
}
"If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem."
(source: https://docs.oracle.com/javase/tutorial/java/IandI/super.html)
I'll try to answer this from a different perspective.
Suppose Java didn't call the super constructor for you automatically. If you inherit the class, you'd have to either call the super constructor implicitly, or rewrite it yourself. This would require you to have internal knowledge of how the super class works, which is bad. It would also require to to rewrite code, which is also not good.
I agree that calling the super constructor behind the scenes is a little unintuitive. On the other hand, I'm not sure how they could have done this in a more intuitive way.
As we know that member variables(fields)of a class must be initialized before creating an object because these fields represent the state of object. If these fields are explicitely not initilized then compiler implicitely provides them default values by calling no-argument default constructor. Thats why subclass constructor invokes super class no-argument default constructor or implicitely invoked by compiler .Local variables are not provided default values by compiler.
here your extending Test to your test1 class meaning u can access all the methods and variable of test in your test1. keep in note that u can access a class methods or variable only if memory is allocated to it and for that it need some constructor either a default or parameterized ,so here wen the compiler finds that it is extending a class it will try to find the super class constructor so that u can access all its methods.
Parents Exits First!!
And like real world Child Can't exist without the Parents..
So initialising parents(SuperClass) first is important in order to use thrm in the children(Subclass) Classes..

Inheriting from inner class

public class A {
public A() {
System.out.println("A()");
}
public class B {
public B() {
System.out.println("B()");
}
}
}
class Caller extends A.B {
Caller(A a){
a.super();
}
}
public class Main {
public static void main(String[] args) {
Caller as= new Caller(new A());
}
}
Why do we need a.super() call in class extending inner class? What does it doing?
Without a.super() program does not want to compile.
Error:(48, 20) java: an enclosing instance that contains A.B is required
a.super() does not call the A constructor. The A constructor runs as a result of the expression new A() in Main.main().
The a.super() invokes the nullary (and only) B constructor, specifying a as a reference to the containing instance of A, which, as a subclass of inner class A.B, each Caller must have.
The answer is: because that's how it is specified in the Java Language Specification.
Your class A.B is an inner class of A. The constructor has a hidden argument of type A - the enclosing (outer-class) instance.
You have subclassed A.B in your class Caller, which is itself not an inner class. But the constructor of the superclass needs this hidden instance of A - the outer class instance.
The way in which you pass this in Java is using this a.super(); syntax.
The Java Language specification defines this in section 8.8.7.1:
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.
Error says it all. One of key thing about inner classes (non-static nested ones) is that they have access to its outer (enclosing) instance. But inner class needs to know to which exactly outer instance it belongs. This information is saved in Outer this$0 reference which is not accessible to us, but it still needs to be set as some point, and that point is code of constructor.
This is why we are creating inner class instances via outer.new Inner() like
Outer outerInstance= new Outer();
Outer.Inner innerInstance = outerInstance.new Outer.Inner();
// ^^^^^^^^^^^^^^^^^
Thanks to that, outer instance is also passed to Inner class constructor (as hidden parameter).
Now since you are extending inner class, it means that your class will simply specify inner class, but it doesn't mean it stop being of Inner type.
So since instance of your Caller is also considered as A.B inner class (since it extends it) you must ensure, that it will have knowledge about its outer instance (of A class). To make this possible you in constructor of our class, you need to
have instance of your class
call constructor of inner superclass A.B, so you would let it save that outer class reference in this$0 variable.
First point is solved by passing A instance as argument of your class constructor Caller(A a).
Second point is done in similar way as calling outerInstance.new Inner(), but this time we can't use new keyword because we don't want to create new object of Inner class. We want to invoke code from superclass constructor to initialize current object (and its hidden this$0 field properly). Usual way to do it is by calling super(). Only thing which could be a bit strange, is that we need to somehow let super() call which outer instance is enclosing one. So probably to make it similar to outer.new Inner() syntax, we are using outer.super() syntax, which in your case is
a.super();
Since your Caller class extends A.B, the first call the Caller constructor makes will be the A.B constructor (even if you don't see it in your code).
So a.super() is NOT calling the A.B constructor.
It's not a.super() calling A.B constructor, but rather Caller() constructor calls it implicitly, since Caller extends A.B. Only after that the a.super() line is executed.

Overriding with Superclass Reference for Subclass Object

I have recently been moving through a couple of books in order to teach myself Java and have, fortunately, mostly due to luck, encountered very few difficulties. That has just changed.
I read a section on the following under inheritance and the whole superclass subclass setup
-- When a new superclass object is created, it is, like all objects, assigned a reference (superReference in this example)
-- If a new subclass object (with the defining subclass extending the superclass) is created, and then the superReference reference is set to refer to that instead of the original object, it is my understanding that, since the reference is made for a superclass, only members defined by the superclass may be accessed from the subclass.
First - is this correct?
Second: If I am overriding a method and therefore have one in the super and one in the sub, and I create a superclass object and then assign its reference, as I did above, to a subclass object, by the principle called something like Dynamic Method Dispatch, a called overridden method should default to accessing the subclass method right?
Well, my question is:
If a reference to a superclass-object is retooled for a subclass-object and will deny direct object.member access to subclass-defined members, only supporting superclass-defined members, how can, if a superclass reference is retooled for a subclass object, an overridden method apply to the subclass-object if access is limited by the superclass-originated-reference-
If you try like:
class SuperClass{
int intVar = 0;
void method(){
//in super class
}
}
class SubClass extends SuperClass{
int intVar = 2;
void method(){
//in sub class
}
}
Then
SuperClass obj = new SubClass();
int val = obj.intVar;// this is taken from SuperClass as variables are decided on reference basis
//if both superclass and subclass contain the same variable it is called shadowing
obj.method();// it is taken from the SubClass as it is method overriding
//and is decided at runtime based on the object not the reference
Check comments. Hope this helps.
only members defined by the superclass may be accessed from the subclass.
First : This is just plain wrong. The subclass may access it's own member without a problem. However once you have assigned a subclass instance to a super class variable (reference) the you can only call methods or members made accessible from the super class only. Is this what you meant to say?
Second : Methods that will be executed are the methods in the instance (object). Not the methods in reference (variable) type. So yes overridden methods will always be executed.
Third : A subclass may override a method but not a instance property. Whatever member variables are in the super class will be in the subclass as well. And you can override methods in the subclass just so long as you keep their existing access modifier or use a more accessible access modifier.
In Oracle documentation doesn't mention that or at least it is not clear or explicitly explained. This behaviour seems to me like virtual methods in C++ with the difference that in such language it is clear through the use of the keyword virtual preceding the methods defined in the base or parent class (superclass in java) and that must be redefined in the child class. In C++ there are not virtual variables, just virtual methods.
In that case, when we have a pointer (reference) to a base class that points to an instance of a child class and there are methods with the same signature and variables with the same name in both the parent and child classes, the definitions of the methods that will be executed are those of the parent class if they are not preceded by the keyword virtual, on the other hand the definitions in the child class will be executed for the methods declared as virtual.
In the case of the variables, the ones in the base class are taken and not the ones in the child classes.
Resuming, the similarities are:
-In java, variables are taken based in the reference
-In C++ there are not virtual variables
So in the case we are talking about, hidding variables in the child classes or subclasses are not taken but the hidden
-In java, methods are taken based on the object or instance
-In C++ virtual methods must be redefined in the child classes and those are taken

What is constructor in java, if it is not a member of class?

What do we we call a constructor, if it is not a member of a class as stated in Oracle doc: http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
I think the term "member" was defined to exclude constructors for the sake of convenience. Constructors, even public ones, are not inherited; members are inherited (unless they are static and/or private). It would be awkward when talking about the rules of inheritance to always have to say "members except constructors".
From the Java Language Specification, §8.2:
Constructors, static initializers, and instance initializers are not members and therefore are not inherited.
Just call constructors "constructors".
Its a special method that every class has, which is called after creation of the object. in JVM its called using invokespecial so, lets just call it a special method?
And since there is just 1 special method in Java - they all call it "constructor"
All the doc is saying is that the constructor is not inherited by default. Since the constructor is a method that is invoked on the construction of the object in the memory heap, then once you create a subclass that inherits from a super class, the constructor of the super class is not invoked by default.
For instance if you have a class Vehicle and a subclass Car, assume the Vehicle constructor is as follows:
public Vehicle(String vehName) {
this.vehName = vehName;
}
Then, even though your class Car inherits from class Vehicle, the vehName member (field) will not be set as the constructor above does.
So you will need to do something like this:
public Car(String vehName) {
super(vehName);
}
Hope that helps
In Java, a class body (the area between braces) can contain the following key items: (1) Fields (2) Methods (3) Other Classes (nested classes) (4) Constructors (5) Initializers
An object created from a particular class shall take the shape that is similar to the blueprint (class) from which it's created. Now, if you look at items that can be contained in a class body, only item (1) to (3) help in determining what sort of object can be created from a particular class definition.
Constructors and initializers only play part in actual creation of the object (e.g. initialization of already defined fields), but do not determine what shape/state that object shall carry, and what behaviors it will display.
For this reason, to me, it make sense to call item (1) to (3) class members (i.e. class members are those items within a class body that determine how an object created from the class looks like and behave); whereas constructors and initializers are not members because their absence in a class definition does not affect a class state and behavior.
As such, only class members can be inherited as the whole point behind inheritance is to enable a subclass reuse state and behavior of its superclass.
A Constructor is a method which is in a class which is used to create a new instance of that class.
Being a member of a class just means that the item in question is in the class.
Constructor is a method which name is same as the class. It is used to initialize the object of class. It's implicit in action. Parametric constructor initialize object with different value.

Must Inner classes have a reference to the enclosed class?

I have an inner class (non-static) which is using a reference to an enclosing class in its initialization. Will the inner class keep a reference to the enclosing class now?
class Enclosing {
class Inner {
private final ABC innerField = outerField.computeSomething();
}
private final XYZ outerField = something();
}
UPDATE
I am very much aware that one can reference the outer class with Enclosing.this.
But, if the class doesn't use the reference, must the reference be there after compilation? Is it necessary even if the reference is only used in the initialization?
Where does it say that an inner class always holds a reference to the outer class?
A non-static nested class always holds a reference to the enclosing class. In your example, you can reference the enclosing class from Inner as Enclosing.this.
JLS 8.1.3 "Inner classes and Enclosing Instances":
"An instance i of a direct inner class C of a class O is associated with an instance of O, known as the immediately enclosing instance of i. The immediately enclosing instance of an object, if any, is determined when the object is created (§15.9.2)."
Yes. An inner class (or non-static nested class) is just like any other instance member of the outer class, and as such always needs a reference of the enclosing class.
Where does it say that an inner class always holds a reference to the outer class?
In the same place it defines the Outer.this syntax. The existence of this syntax is the existence of the reference. There is nothing to suggest that it is suppressed if not used.
There are two cases of nested-classes:
static nested-classes. The nested-class does not keep reference to the outer-class.
non-static nested-classes. The nested-class does keep a reference to the outer-class.
The case of a static nested-class that extends the outer-class is not as interesting as the
non-static nested-class extending the outer-class.
An important thing to remember is that non static nested classes are simply called inner classes.

Categories