Why Calling super.super.method() is Not Allowed in Java
Java follows a strict object-oriented approach with a well-defined inheritance model. Unlike some languages that allow direct access to grandparent methods, Java restricts access to only the immediate superclass using super
. Let us delve into understanding why Java super super not allowed is a restriction in the language.
1. Understanding the Problem
In Java, the super keyword allows a subclass to access methods of its direct superclass. It allows access to:
- Superclass methods that are overridden in a subclass.
- Superclass constructors.
- Superclass instance variables.
However, developers sometimes expect to call methods of the grandparent class (two levels up) directly using super.super.method()
, but Java does not allow this.
2. Why super.super.method() Is Forbidden in Java?
Java enforces encapsulation and method resolution through a single-level inheritance mechanism. Directly calling a grandparent’s method would break this encapsulation and can lead to ambiguity in method resolution.
2.1 Example of the Issue
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | class Grandparent { void show() { System.out.println( "Grandparent method" ); } } class Parent extends Grandparent { void show() { System.out.println( "Parent method" ); } } class Child extends Parent { void display() { // Attempting super.super.show() is NOT ALLOWED // super.super.show(); // This will cause a compilation error } } |
The above example attempts to call super.super.show()
but fails to compile because Java does not allow skipping levels in inheritance.
2.2 Why Java Restricts super.super.method()?
In the above example, Java programming language prevents super.super.method()
because:
- Violation of Encapsulation: Java enforces encapsulation by ensuring that a subclass interacts with its immediate superclass without direct access to deeper levels of the inheritance chain. Allowing
super.super.method()
would expose internal implementation details of the class hierarchy, making it harder to refactor or modify base classes without affecting subclasses.In the following code, class
C
should only interact withB
, but ifsuper.super.method()
were allowed, it would break encapsulation and tightly coupleC
toA
, violating abstraction principles.01020304050607080910111213141516171819202122232425262728class
A {
void
show() {
System.out.println(
"Class A method"
);
}
}
class
B
extends
A {
@Override
void
show() {
System.out.println(
"Class B method"
);
}
}
class
C
extends
B {
@Override
void
show() {
System.out.println(
"Class C method"
);
super
.show();
// Calls B's method
// super.super.show(); // Invalid in Java - would break encapsulation
}
}
public
class
Main {
public
static
void
main(String[] args) {
C obj =
new
C();
obj.show();
}
}
- Ambiguity with Multiple Inheritance via Interfaces: While Java does not support multiple inheritance with classes, it allows a class to implement multiple interfaces. If Java permitted
super.super.method()
, resolving method calls from multiple interfaces could lead to conflicts, especially when different interfaces provide default methods with the same name.In the example below, interfaces
X
andY
both define ashow()
method. Ifsuper.super.show()
were allowed, it would be unclear which implementation should be invoked.010203040506070809101112131415161718192021222324252627interface
X {
default
void
show() {
System.out.println(
"Interface X"
);
}
}
interface
Y {
default
void
show() {
System.out.println(
"Interface Y"
);
}
}
class
Z
implements
X, Y {
@Override
public
void
show() {
// Conflict! Java does not allow automatic resolution of super calls from multiple interfaces.
// super.super.show(); // Invalid in Java
X.
super
.show();
// Must explicitly specify which interface to call
}
}
public
class
Main {
public
static
void
main(String[] args) {
Z obj =
new
Z();
obj.show();
// Calls X's implementation explicitly
}
}
- Dynamic Method Resolution (Polymorphism) via Virtual Method Table (VMT): Java uses a mechanism called the Virtual Method Table (VMT) to resolve method calls dynamically at runtime. This ensures that the most specific overridden method in the hierarchy is executed. If
super.super.method()
were allowed, it would bypass this mechanism, leading to unexpected behavior and breaking polymorphism.In the example below, Java ensures that method resolution happens dynamically. If
super.super.method()
were allowed, it would force execution of a grandparent’s method, breaking the expected behavior.01020304050607080910111213141516171819202122232425262728class
Parent {
void
display() {
System.out.println(
"Parent class"
);
}
}
class
Child
extends
Parent {
@Override
void
display() {
System.out.println(
"Child class"
);
}
}
class
GrandChild
extends
Child {
@Override
void
display() {
System.out.println(
"GrandChild class"
);
super
.display();
// Calls Child's method
// super.super.display(); // Invalid in Java - would break VMT resolution
}
}
public
class
Main {
public
static
void
main(String[] args) {
Parent obj =
new
GrandChild();
obj.display();
// Calls the most overridden method in GrandChild due to VMT
}
}
3. A Workaround: Indirect Call
Though super.super.method()
is not allowed, we can explicitly call the grandparent’s method by defining a public method in the parent class that exposes it.
3.1 Workaround Example
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // Base class (Grandparent) with a method 'show' class Grandparent { void show() { System.out.println( "Grandparent method" ); } } // Intermediate class (Parent) that overrides 'show' from Grandparent class Parent extends Grandparent { void show() { System.out.println( "Parent method" ); } // Method to explicitly call Grandparent's 'show' using 'super' void callGrandparentShow() { super .show(); // Calls Grandparent's show() method } } // Child class that extends Parent class Child extends Parent { void display() { // Indirectly calls Grandparent's show() through Parent's callGrandparentShow() callGrandparentShow(); } } // Test class with main method public class Test { public static void main(String[] args) { Child c = new Child(); c.display(); } } |
3.1.1 Code Explanation and Output
In the given Java code, we have a class hierarchy demonstrating method overriding and the use of super
to access a grandparent class method.
The Grandparent
class has a method show()
that prints “Grandparent method”. The Parent
class extends Grandparent
and overrides the show()
method to print “Parent method”. Additionally, it has a method callGrandparentShow()
, which explicitly calls the show()
method from Grandparent
using super.show()
.
The Child
class extends Parent
and defines a method display()
, which calls callGrandparentShow()
. This ensures that the show()
method from Grandparent
is invoked, bypassing the overridden show()
method in Parent
.
In the main
method, an instance of Child
is created, and the display()
method is called. This triggers a chain of method calls:display()
→ callGrandparentShow()
→ super.show()
, resulting in “Grandparent method” being printed.
1 | Grandparent method |
This code illustrates the concept of method overriding and how super
can be used to access methods from grandparent classes in a multilevel inheritance structure.
4. Conclusion
Java enforces a strict inheritance model where a subclass can access only its immediate superclass using super
. This prevents direct calls to grandparent methods using super.super.method()
. However, a workaround exists by defining a method in the parent class that explicitly calls the grandparent’s method. Understanding these restrictions helps in designing clean, maintainable, and encapsulated Java applications.