So I have this code:
public class A {
private State _state;
public abstract class State {
protected void setState(State newState) {
_state = newState;
}
}
public A() {
_state = new AbstractState(this);
}
}
public abstract class AbstractState extends A.State {
AbstractState(A a) {
a.super();
}
}
And I'm having a hard time understanding how it works.
So when a A object is created it creates a AbstractState object with that same A object as a parameter. And the AbstractState constructor, which receives that A object, calls a.super().
From my understanding, a.super() calls the construtor of the super class of A a, which is Object, right? So what's the point?
I know that AbstractState is an abstract class. A subclass could be:
public class StateOne extends AbstractState {
StateOne(A a) {
super(a);
}
}
The question remains though.
From my understanding, a.super() calls the constructor of the super class of A a, which is Object, right? So what's the point?
I think you are asking why you have to write a.super() rather than super().
First of all, it is not calling the constructor of A or of the superclass of A. The super(...) call in a constructor always means a constructor in the immediate superclass of the class that you are instantiating. In this case the superclass is the inner class A.State.
What a.super() actually says is "call my super class constructor with a as my enclosing instance".
The unusual syntax is needed because the superclass is an inner class, and when an inner class is instantiated, it needs to know what instance of the enclosing class that it is inside.
In your example, State is declared as an inner class (i.e. not static) so the setState method can see the private _state variable of some instance the enclosing class (A). The a.super() is necessary so that the JVM can know which instance of A is the enclosing one.
To call an inner class (State), it must tell it who is its super class A first. JVM can find who is the father class of StateOne, just using this statement " extends A.State" .
a.super() is corresponding to A.State
a --> A in " extends A.State ", tell inner class who is your father class (the instance of father class)
super() ----> State in "extends A.State ", it is the constructor of inner class
You can understand it like this, a common class extends use "super()/super(xx)", but extending inner class must have to know an instance of its super class first. So how to know its super class, in the constructor, use the parameter. Then, using super() calls father's constructor, like this, inner class use (my father class).super()
Related
I'd like to know what really happens when somebody calls java super() method in the constructor of a class that inherits from an abstract class. As we know it, an abstract class cannot be instantiated but super calls the constructor of the abstract class.
Let's take an example.
public abstract class Figure { // cant be instantiated
private type firstAttribute;
private type secondAttribute;
public Figure(type firstAttribute, type secondAttribute) {
this.fisrtAttribute = fisrtAttribute;
this.fisrtAttribute = fisrtAttribute;
}
protected abstract void anyMethod();
}
class Rectangle extends Figure {
public Rectangle(type firstAttribute, type secondAttribute) {
/*
* call the abstract class constructor but we know, a
* constructor is used to
* instantiate class and we can't instantiate an abstract class
*/
super(firstAttribute, secondAttribute);
// then what really happen ?
}
#override
....
}
The confusion stems from the fact that calling the super() constructor doesn't actually instantiate the super class. It simply invokes the super() constructor. No more, no less.
This means that the code in the super constructor will be called when super() is called. You're correct that abstract classes cannot be instantiated, but invoking the super constructor from a subclass constructor doesn't count as instantiation.
The abstract base class initialised any properties you inherit in your concrete inheriting class, so you can avoid code duplication in the initialisation
I executes the code in the constructor it calls.
There is no need to create an instance of the abstract class for that; after all, during constructor invocation, the instance of the class is never created already.
Abstract Class:
public abstract class ParentClass {
private static ParentClass mpParentClass;
public ParentClass() {
mpParentClass = this;
}
public abstract void method1();
public static ParentClass getInstance() {
return mpParentClass;
}
}
Child Class :
public class ChildClass extends ParentClass{
#Override
public void method1() {
System.out.print("ChildClass class method");
}
}
Test Class :
public class TestClass {
public static void main(String[] args) {
ChildClass cl = new ChildClass();
ParentClass.getInstance().method1();
}
}
Here I have created an abstract class and a Child class which extends the parent Abstract class.
Parent abstract class holds a reference to its own instance and returns the instance through a static method.
In Test class, if I don't create an object of ChildClass, java throws NullPointerException.
But after creating object of ChildClass, and then querying instance of ParentClass and invoking abstract method, it calls method implemented by ChildClass.
I am unable to understand this behavior . Please anyone explain.
The first time you Instantiate a ChildClass you use the default constructor of parentClass which instantiate the private field with the ChildClass type . If you don't do that, the private field mpParentClass is not instantiate. So you have a NullPointerException
ParentClass.getInstance() is a static method so it doesn't require an instance of your class to run.
By calling this method you will return the static member mpParentClass.
But by default this member contains a null reference.
So without doing anything this will indeed result in a NullPointerException because you didn't call the constructor of ParentClass.
In your example you first make an instance of the ChildClass.
This will call the default constructor of that class. This default constructor has the standard behavior of calling the default constructor of the super class (by calling super()).
So by instantiating the ChildClass you call the constructor of ParentClass that will set the mpParentClass datamember to this. And here this refers to the instance of the ChildClass you are creating.
So after construction mpParentClass will contain the newly created instance of the ChildClass.
Here's what's happening.
When you call the constructor for your ChildClass, it's implicit that the first actual call in that method is to the superclass constructor. If you had a superclass constructor that required/allowed alternate arguments, you could call it manually. But it's happening for you.
When the superclass constructor is called, a static reference is being assigned to that new instance, which is a ChildClass instance. (Because that's what this is, in this case.)
If you were to call:
new ChildClass();
new ParentClass() {
public void method1() {
System.out.println("Anonymous class!");
}
};
ParentClass.getInstance().method1();
You would see "Anonymous class!", because there is one static reference that is going to be reassigned every time you create any instance of a ParentClass implementation.
Regarding your NullPointerException - the only place where mpParentClass is assigned to a value is in the constructor for ParentClass. If you never create an instance of a ParentClass, then this code will never be called, and mpParentClass will be left with its original value, which is null. Attempting to call a method or access a property on a null reference is what produces a NullPointerException.
The question to ask is: If you never instantiate any of your implementations (by 'calling' their constructors), what do you expect the mpParentClass variable to be set to, if not null?
Parent class is abstract so you can't use the constructor directly. The static variable instance is null by default which leads to your NullPointerException. The only way to set this variable is by calling the constructor which is only called when a constructor of a child class is called.
This is because you are only assigning to the static field mpParentClass in your ParentClass constructor. Therefore, until you create an instance of ChildClass, mpParentClass is null. In your example, the base class ParentClass constructor is called implicitly when you create an instance of the derived class ChildClass.
Might I suggest that you use the singleton pattern instead?
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
You're creating a ChildClass then calling its method1() through unnecessary trickery.
You do realize that this will be a ChildClass instance at the ParentClass constructor, right? It has to be, since the parent class is abstract and therefore there can never be a this instance that would represent it.
In the book Java: The complete reference
// Demonstrate when constructors are called.
// Create a super class.
class A {
A() {
System.out.println("Inside A's constructor.");
}
}
// Create a subclass by extending class A.
class B extends A {
B() {
System.out.println("Inside B's constructor.");
}
}
// Create another subclass by extending B.
class C extends B {
C() {
System.out.println("Inside C's constructor.");
}
}
class CallingCons {
public static void main(String args[]) {
C c = new C();
}
}
Output:
Inside A’s constructor
Inside B’s constructor
Inside C’s constructor
It is demonstrating how the constructor of a subclass is called. But why are constructors of the super class called in the absence of a super() constructor.
Why did the Java Language designers consider it necessary to do so?
As others have pointed out, if you don't start your constructor with a super(...) call, the compiler will put in a call to super() for you.
As to the why, you have to start with remembering what a constructor is for in the first place: initializing the object. What does that mean, specifically? In practice, it means assigning values to the object's fields, and establishing invariants.
Without a call to super(), the B and A classes wouldn't have a chance to do that for whatever fields they contain. And you can't even have the C() constructor do it for them, if those fields are private, since private fields aren't accessible outside your class (not even your super class's fields are accessible). Even if you could, it wouldn't be a good idea; it would also break encapsulation. For instance, imagine having to change your code if a super class -- possibly a complex one whose internals you're not an expert in -- suddenly decided to change its implementation details.
To illustrate this, consider a very simple set of classes:
public class Super {
private final String name;
Super() {
name = "default";
}
public String name() {
return name.toUpperCase();
}
}
public class Sub extends Super {
public Sub() {
// don't do anything
}
}
When you instantiate Sub, it will start out by calling Super's constructor. If it didn't, the name field would be null (the default value for reference types). But the name() method doesn't check for null; it assumes that the reference is non-null, because the constructor establishes that invariant. So, in our pseudo-Java that doesn't call the super constructor, Super.name has to get a bit more complicated -- it has to check for name == null.
You can imagine that as the classes gain more fields, with more interesting invariants, this toy example can become more and more complicated. Forcing you to call the super constructor -- either explicitly or implicitly -- lets the authors of that super class establish their invariants, resulting in simpler, more maintainable code.
Every constructor calls its superclass constructor. super() call take place as the first line in the constructor. From javadoc:
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.
more here
Because it says so in the Java Language Specification.
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments.
Even it has a role with Abstract classes also. we can't initialize object of abstract class. But Child class of Abstract class calls the super() method by default. So abstract class constructor can initialize its instance variables.
for example:
public abstract class TestA {
private int a;
public TestA()
{
a=10;
}
public int displayA()
{
return a;
}
abstract void display();
}
public class TestB extends TestA{
#Override
void display() {
System.out.println("this is class B");
}
}
package Abstract;
public class TestMain {
public static void main(String[] args) {
TestA obj= new TestB();
System.out.println(obj.displayA());
}
}
Output is : 10
Here you can see, when we initiating object of class TestB , by default super constructor is calling and TestA's constructor is assigning the value of a. If super will not be called by default we can't assign instance variables of abstract class.
Inheritance is basically inheriting all the properties of your parent class. So if a sub class constructor is called, it should definitely and by default inherit all its parent class properties also. In the following code, all the properties of class A should be made available in class B also, so if I just call B's constructor, all the class A's properties(except private) are also initialized and made available, meaning B has inherited A's properties
class A {
protected int a;
A() {
a=12;
System.out.println("Inside A's constructor.");
}
}
class B extends A {
B() {
System.out.println("Inside B's constructor.");
System.out.println(a);
}
}
public class ConstructorInheritance {
public static void main(String args[]) {
B b=new B();
}
}
output:
Inside A's constructor.
Inside B's constructor.
12
Imagine class C accessing an unitialized variable of class B or A. Implicitly calling constructors of class B-->class A makes sure that you are always accessing initialized variables of inherited classes(A or B)
"The Java programming language" says "A constructor in subclass can initialize its individual state, however, as keeping contract, only super class knows how to initialize super class's state".
Thus, constructor of super class have to be called. There is sequence how the constructor processed:
Call super class constructor
Initialize fields with initializers and initialization blocks
Execute body of the constructor
For more details, have a look of the book to section "3.2".
What is the need for the JVM to call superclass constructor?
public class Test1{
public void dis()
{
System.out.println("In Test1");
}
}
public class Test2 extends Test1{
public void dis()
{
System.out.println("Inside test2");
super.dis();
}
}
Since dis() is an instance method, is it safe to assume that super is pointing to parent class object since the constructor is automatically called?
The keyword super does not point to some "parent class object". It is a name qualifier so you can refer to a method defined in the parent class for the current object. Thus, in the following:
public class Test2 extends Test1{
public void dis()
{
System.out.println("Inside test2");
super.dis();
}
}
the call super.dis() invokes the dis() method defined in the parent class for this object. It does not invoke the dis() method of some other object named super.
Slightly different things are going on with constructors. Every constructor must always start with a call to some constructor in the parent class. You can do this explicitly using the super keyword:
public class Test2 extends Test1{
public Test2() {
super(); // explicitly invokes parent class default constructor
. . .
}
}
If you don't explicitly call a particular parent class constructor, the compiler automatically inserts a call to the default (no-argument) parent class constructor. The call to a parent class constructor (if present) must be the first statement in a constructor. Within a method, however, super. can be used as a qualifier for any name wherever it is used (provided the name is a member of the parent class).
The super keyword is useful for:
Calling the superclass' implementation of a method overriden in this class
Accessing the superclass' constructor from a subclass constructor
Your example shows the first case in action, when calling dis() on an instance of Test2 the program must print, in this order:
Inside test2
In Test1
is it safe to assume that super is pointing to parent class object
super keyword is used to access direct super class members on the current object. It does not refer to any super class object.
since constructor is automaticallt called?
The role of super keyword is not dependent upon the super class constructor being called. Super class constructor is always called through constructor chaining using super() call to either no-arg or parameterized constructor.
One difference between chaining super class constructor, and invoking super class member is that: "While chaining constructors, the super() call has to be the first statement in constructor, while you can invoke super class method at any point in your current method".
This has nothing to do with constructors. Since Test2 extends Test1 and dis() is implemented in both classes, super.dis() in the subclass will call dis() in the superclass.
using super constructor we can call functions and variables directly from
super class in subclass for
public class Test1{
int a=5;
}
public class Test2 extends Test1{
int a=15;
int c;
c=a+super.a;
System.out.println("value of c is:"+
}
result :value of c is:20
you can call default constructor of super class by super() .
if there is variables then you can call it by super(parameter_list).
public class Superclass {
void method0(){
System.out.println("superclass");
}
}
public class Subclass extends Superclass{
void method0(){
System.out.println("subclass");
}
void method1(){
super.method0();
}
void method2(){
this.method0();
}
}
public class RunClass {
public static void main(String[] args){
new Subclass().method1();
new Subclass().method2();
}
}
the code above print out
superclass
superclass
while I expect it to print out
superclass
subclass
Isn't this.method0() refer to the method0 in subclass and print out subclass instead of superclass?
super represents the instance of parent class.
this represents the instance of current class.
It will print
superclass
subclass
I ran your code and it gaves me
superclass
subclass
this what should printed every thing seems ok
new Subclass().method1();
executes the method1() of Subclass instance, which in turn calls super.method0(); i.e parent class instance's method0() i.e. Superclass instance method0().
new Subclass().method2();
executes the method2() of Subclass instance, which in turn calls this.method0(); i.e this instance's method0() i.e. Subclass instance method0().
super is used to access instance members of the parent class while this is used to access members of the current class.
First of all, it prints out the what you are expecting.
Second,
Isn't this.method0() refer to the method0 in subclass and print out
subclass instead of superclass?
this => refer to current object, using it you can use it (kinda of pointer to itself, in general terms )
super => refer to super class object in an hierarchy, usually used to access the hidden members in subclass