Which construct allows The constructor of a subclass to invoke The constructor of its super class

According to The Java Language Specification, §12.5, "Creation of New Class Instances" [JLS 2015]:

Unlike C++, the Java programming language does not specify altered rules for method dispatch during the creation of a new class instance. If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely initialized.

Invocation of an overridable method during object construction may result in the use of uninitialized data, leading to runtime exceptions or to unanticipated outcomes. Calling overridable methods from constructors can also leak the this reference before object construction is complete, potentially exposing uninitialized or inconsistent data to other threads (see TSM01-J. Do not let the this reference escape during object construction for additional information). As a result, a class's constructor must invoke (directly or indirectly) only methods in that class that are static, final or private.

Noncompliant Code Example

This noncompliant code example results in the use of uninitialized data by the doLogic() method:

class SuperClass {
  public SuperClass () {
    doLogic();
  }

  public void doLogic() {
    System.out.println("This is superclass!");
  }
}

class SubClass extends SuperClass {
  private String color = "red";

  public void doLogic() {
    System.out.println("This is subclass! The color is :" + color);
    // ...
  }
}

public class Overridable {
  public static void main(String[] args) {
    SuperClass bc = new SuperClass();
    // Prints "This is superclass!"
    SuperClass sc = new SubClass();
    // Prints "This is subclass! The color is :null"
  }
}

The doLogic() method is invoked from the superclass's constructor. When the superclass is constructed directly, the doLogic() method in the superclass is invoked and executes successfully. However, when the subclass initiates the superclass's construction, the subclass's doLogic() method is invoked instead. In this case, the value of color is still null because the subclass's constructor has not yet concluded.

Compliant Solution

This compliant solution declares the doLogic() method as final so that it cannot be overridden:

class SuperClass {
  public SuperClass() {
    doLogic();
  }

  public final void doLogic() {
    System.out.println("This is superclass!");
  }
}

Risk Assessment

Allowing a constructor to call overridable methods can provide an attacker with access to the this reference before an object is fully initialized, which could lead to a vulnerability.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MET05-J

Medium

Probable

Medium

P8

L2

Automated Detection

Automated detection of constructors that contain invocations of overridable methods is straightforward.

Bibliography


Which construct allows The constructor of a subclass to invoke The constructor of its super class
Which construct allows The constructor of a subclass to invoke The constructor of its super class
Which construct allows The constructor of a subclass to invoke The constructor of its super class

The super keyword is used to access properties on an object literal or class's [[Prototype]], or invoke a superclass's constructor.

The super.prop and super[expr] expressions are valid in any method definition in both classes and object literals. The super(...args) expression is valid in class constructors.

Syntax

super([arguments]) // calls the parent constructor.
super.propertyOnParent
super[expression]

Description

The super keyword can be used in two ways: as a "function call" (super(...args)), or as a "property lookup" (super.prop and super[expr]).

Note: super is a keyword and these are special syntactic constructs. super is not a variable that points to the prototype object. Attempting to read super itself is a SyntaxError.

const child = {
  myParent() {
    console.log(super); // SyntaxError: 'super' keyword unexpected here
  },
};

In the constructor body of a derived class (with extends), the super keyword may appear as a "function call" (super(...args)), which must be called before the this keyword is used, and before the constructor returns. It calls the parent class's constructor and binds the parent class's public fields, after which the derived class's constructor can further access and modify this.

The "property lookup" form can be used to access methods and properties of an object literal's or class's [[Prototype]]. Within a class's body, the reference of super can be either the superclass's constructor itself, or the constructor's prototype, depending on whether the execution context is instance creation or class initialization. See the Examples section for more details.

Note that the reference of super is determined by the class or object literal super was declared in, not the object the method is called on. Therefore, unbinding or re-binding a method doesn't change the reference of super in it (although they do change the reference of this). You can see super as a variable in the class or object literal scope, which the methods create a closure over. (But also beware that it's not actually not a variable, as explained above.)

When setting properties through super, the property is set on this instead.

Examples

Using super in classes

This code snippet is taken from the classes sample (live demo). Here super() is called to avoid duplicating the constructor parts' that are common between Rectangle and Square.

class Rectangle {
  constructor(height, width) {
    this.name = 'Rectangle';
    this.height = height;
    this.width = width;
  }
  sayName() {
    console.log(`Hi, I am a ${this.name}.`);
  }
  get area() {
    return this.height * this.width;
  }
  set area(value) {
    this._area = value;
  }
}

class Square extends Rectangle {
  constructor(length) {
    this.height; // ReferenceError, super needs to be called first!

    // Here, it calls the parent class's constructor with lengths
    // provided for the Rectangle's width and height
    super(length, length);

    // Note: In derived classes, super() must be called before you
    // can use 'this'. Leaving this out will cause a reference error.
    this.name = 'Square';
  }
}

Super-calling static methods

You are also able to call super on static methods.

class Rectangle {
  static logNbSides() {
    return 'I have 4 sides';
  }
}

class Square extends Rectangle {
  static logDescription() {
    return `${super.logNbSides()} which are all equal`;
  }
}
Square.logDescription(); // 'I have 4 sides which are all equal'

Accessing super in class field declaration

super can also be accessed during class field initialization. The reference of super depends on whether the current field is an instance field or a static field.

class Base {
  static baseStaticField = 90;
  baseMethod() {
    return 10;
  }
}

class Extended extends Base {
  extendedField = super.baseMethod(); // 10
  static extendedStaticField = super.baseStaticField; // 90
}

Note that instance fields are set on the instance instead of the constructor's prototype, so you can't use super to access the instance field of a superclass.

class Base {
  baseField = 10;
}

class Extended extends Base {
  extendedField = super.baseField; // undefined
}

Here, extendedField is undefined instead of 10, because baseField is defined as an own property of the Base instance, instead of Base.prototype. super, in this context, only looks up properties on Base.prototype, because that's the [[Prototype]] of Extended.prototype.

Deleting super properties will throw an error

You cannot use the delete operator and super.prop or super[expr] to delete a parent class' property, it will throw a ReferenceError.

class Base {
  foo() {}
}
class Derived extends Base {
  delete() {
    delete super.foo; // this is bad
  }
}

new Derived().delete(); // ReferenceError: invalid delete involving 'super'.

Using super.prop in object literals

Super can also be used in the object initializer / literal notation. In this example, two objects define a method. In the second object, super calls the first object's method. This works with the help of Object.setPrototypeOf() with which we are able to set the prototype of obj2 to obj1, so that super is able to find method1 on obj1.

const obj1 = {
  method1() {
    console.log('method 1');
  }
}

const obj2 = {
  method2() {
    super.method1();
  }
}

Object.setPrototypeOf(obj2, obj1);
obj2.method2(); // logs "method 1"

Methods that read super.prop do not behave differently when bound to other objects

Accessing super.x behaves like Reflect.get(Object.getPrototypeOf(objectLiteral), "x", this), which means the property is always seeked on the object literal/class declaration's prototype, and unbinding and re-binding a method won't change the reference of super.

class Base {
  baseGetX() {
    return 1;
  }
}
class Extended extends Base {
  getX() {
    return super.baseGetX();
  }
}

const e = new Extended();
console.log(e.getX()); // 1
const { getX } = e;
console.log(getX()); // 1

The same happens in object literals.

const parent1 = { prop: 1 };
const parent2 = { prop: 2 };

const child = {
  myParent() {
    console.log(super.prop);
  },
};

Object.setPrototypeOf(child, parent1);
child.myParent(); // logs "1"

const myParent = child.myParent;
myParent(); // still logs "1"

const anotherChild = { __proto__: parent2, myParent };
anotherChild.myParent(); // still logs "1"

Only resetting the entire inheritance chain will change the reference of super.

class Base {
  baseGetX() { return 1; }
  static staticBaseGetX() { return 3; }
}
class AnotherBase {
  baseGetX() { return 2; }
  static staticBaseGetX() { return 4; }
}
class Extended extends Base {
  getX() { return super.baseGetX(); }
  static staticGetX() { return super.staticBaseGetX(); }
}

const e = new Extended();
// Reset instance inheritance
Object.setPrototypeOf(Extended.prototype, AnotherBase.prototype);
console.log(e.getX()); // Logs "2" instead of "1", because the prototype chain has changed
console.log(Extended.staticGetX()); // Still logs "3", because we haven't modified the static part yet
// Reset static inheritance
Object.setPrototypeOf(Extended, AnotherBase);
console.log(Extended.staticGetX()); // Now logs "4"

Setting super.prop will set the property on this instead

Setting properties of super, such as super.x = 1, behaves like Reflect.set(Object.getPrototypeOf(objectLiteral), "x", 1, this). This is one of the cases where understanding super as simply "reference of the prototype object" falls short, because it actually sets the property on this instead.

class A {}
class B extends A {
  setX() {
    super.x = 1;
  }
}

const b = new B();
b.setX();
console.log(b); // B { x: 1 }
console.log(Object.hasOwn(b, "x")); // true

super.x = 1 will look for the property descriptor of x on A.prototype (and invoke the setters defined there), but the this value will be set to this, which is b in this context. You can read Reflect.set for more details on the case when target and receiver differ.

This means that while methods that get super.prop are usually not susceptible to changes in the this context, those that set super.prop are.

/* Reusing same declarations as above */

const b2 = new B();
b2.setX.call(null); // TypeError: Cannot assign to read only property 'x' of object 'null'

However, super.x = 1 still consults the property descriptor of the prototype object, which means you cannot rewrite non-writable properties, and setters will be invoked.

class X {
  constructor() {
    // Create a non-writable property
    Object.defineProperty(this, 'prop', {
      configurable: true,
      writable: false,
      value: 1,
    });
  }
}

class Y extends X {
  constructor() {
    super();
  }
  foo() {
    super.prop = 2;   // Cannot overwrite the value.
  }
}

const y = new Y();
y.foo(); // TypeError: "prop" is read-only
console.log(y.prop); // 1

Specifications

Specification
ECMAScript Language Specification
# sec-super-keyword

Browser compatibility

BCD tables only load in the browser

See also

How does a subclass invoke its superclass constructor?

A subclass can call a constructor defined by its superclass by use of the following form of super: super(parameter-list); Here, parameter-list specifies any parameters needed by the constructor in the superclass. super( ) must always be the first statement executed inside a subclass constructor.

Which keyword is used to refer super class constructor from subclass constructor?

For super keyword in Java, we have the base keyword in C#. Super keyword in Java refers immediate parent class instance. It is used to differentiate the members of superclass from the members of subclass, if they have same names. It is used to invoke the superclass constructor from subclass.

When you create an object of a subclass the constructor of the superclass calls the constructor of the subclass True or false?

(*2) A subclass constructor always calls the constructor of its superclass, and so on up to the Object constructor, to initialize all the aspects of the instance that the subclass inherits from its superclass.

Can a subclass use a superclass constructor?

A subclass inherits all the members (fields, methods, and nested classes) from its superclass. Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.