How to Use the super Keyword in Java (With Examples)
The super keyword in Java is a reference variable that refers to the immediate parent class of a currently instantiated object. When you write a class that extends another class, the child class inherits fields and methods from the parent, but there are situations where the child class needs to explicitly access or invoke something from the parent rather than using its own overridden version. The super keyword provides that explicit reference, giving the child class a reliable way to reach into its parent class for constructors, methods, and fields that would otherwise be shadowed or overridden by the child class implementation.
Java uses super in three distinct contexts — calling a parent class constructor, invoking a parent class method that has been overridden in the child class, and accessing a parent class field that has been hidden by a child class field with the same name. Each of these uses solves a specific problem in object-oriented programming, and understanding when and why each use applies makes inheritance-based code significantly cleaner and more predictable. The super keyword is not available in static contexts because it is fundamentally tied to object instances and the inheritance chain of those instances.
Before the super keyword makes complete sense, having a clear picture of how Java inheritance works is essential. When one class extends another using the extends keyword, the child class gains access to all non-private fields and methods of the parent class. This relationship creates a hierarchy where the child class is considered a more specialized version of the parent, and objects of the child class carry both the parent class behavior and whatever additional behavior the child class defines or overrides.
The inheritance chain can extend multiple levels — a class can extend a parent that itself extends a grandparent — but super always refers specifically to the immediate parent in the chain, not to any ancestor further up. If you need to access behavior from a grandparent class, Java does not allow chaining super calls like super.super, which is a deliberate language design decision. This restriction encourages clean class design where each level of the hierarchy is responsible for its own relationship with its immediate parent rather than reaching across multiple inheritance levels. The practical effect is that super is always a two-level relationship between exactly the current class and the class it directly extends.
The most common use of the super keyword is calling a parent class constructor from within a child class constructor. When a child class object is created, Java requires that a parent class constructor runs as part of the object initialization process. If you do not explicitly call a parent constructor using super, Java automatically inserts a call to the no-argument parent constructor as the first line of your child constructor. This implicit call works fine when the parent class has a no-argument constructor available, but it causes a compilation error when the parent class only defines constructors that require arguments.
When a parent class requires specific parameters in its constructor, the child class must explicitly pass those parameters using super as the very first statement in its own constructor. Placing super anywhere other than the first line is a compilation error that Java enforces without exception. This requirement exists because parent class initialization must complete before child class initialization begins, ensuring that inherited fields are properly set up before the child class adds its own state on top of the parent foundation. A Dog class extending an Animal class that requires a name at construction time must pass that name upward through super before setting any of its own breed or size fields.
When you write a child class constructor without explicitly calling super, Java silently inserts a call to the parent class no-argument constructor as if you had written it yourself. This automatic behavior is convenient when parent classes are designed with a default no-argument constructor, which is itself automatically generated by Java when you write no constructor at all in your class. The entire chain runs without you needing to think about it, and the parent class initializes with its default values before your child constructor proceeds.
The problem arises the moment a parent class defines only parameterized constructors without a no-argument version. Java no longer generates the default no-argument constructor automatically once any constructor is explicitly written, so the automatic super call that Java tries to insert has nothing to call, and the compilation fails with an error message indicating that no suitable constructor was found in the parent class. This is one of the most common beginner errors in Java inheritance, and the fix is straightforward once you understand the relationship — explicitly call super with the required arguments as the first line of the child constructor, and the compilation error disappears immediately.
When a child class overrides a method from the parent class, the overridden version completely replaces the parent version for objects of the child type during runtime. This is the intended behavior of polymorphism in most cases, but there are situations where the child class wants to extend the parent method rather than completely replace it. The child class might want to perform everything the parent method does and then add additional behavior on top, rather than rewriting the parent logic from scratch inside the override.
The super keyword solves this elegantly by allowing the child class to call the parent version of the overridden method explicitly using the syntax super followed by the method name and its required arguments. Using this approach from within the child class invokes the parent implementation regardless of the override, and the child method can then add its own logic before or after that call depending on the intended sequence of operations. This pattern appears constantly in real codebases because it respects the principle that the parent class owns its own behavior and the child class should build upon that behavior rather than duplicating or ignoring it entirely.
Imagine a Vehicle class with a method that performs a standard startup sequence — checking fuel levels, verifying that the engine oil pressure is within acceptable range, and confirming that the brake system is responsive. A child class representing an ElectricCar extends Vehicle and overrides the startup method because it has additional checks specific to electric powertrains — battery charge level, thermal management system status, and regenerative braking calibration.
Without super, the ElectricCar class would need to either duplicate all the standard Vehicle startup logic inside its own override or abandon the parent checks entirely, both of which are bad design outcomes. With super, the ElectricCar startup method calls super to run all the standard Vehicle checks first, then adds its electric-specific checks afterward. The result is a clean separation of responsibilities where Vehicle is responsible for universal startup logic and ElectricCar is responsible only for the additional electric-specific layer. If the Vehicle startup logic ever changes, ElectricCar benefits from those changes automatically without requiring any modification to its own code.
The third use of the super keyword involves accessing parent class fields that have been hidden by a child class field with the same name. When a child class declares a field with an identical name to a field in the parent class, the child field shadows the parent field within the child class scope. Any reference to that field name inside the child class resolves to the child class version, and the parent class version becomes inaccessible through normal field reference syntax.
Using super followed by the field name explicitly tells Java to resolve the reference against the parent class rather than the child class, bypassing the shadowing effect. This situation is considerably less common than constructor or method uses of super, and many experienced Java developers consider field hiding to be a design problem worth avoiding rather than a pattern worth embracing. When two fields in a class hierarchy have the same name, it creates confusion about which field is being referenced in any given context, and the code becomes harder to read and maintain over time. Refactoring the field names to be distinct is almost always the better solution, but understanding how super accesses hidden fields is still useful knowledge for reading and maintaining code written by others who made different design choices.
Polymorphism and the super keyword exist in a complementary tension within Java’s object-oriented model. Polymorphism achieves its power by allowing method calls on a parent class reference to execute the child class override at runtime, which is the fundamental mechanism behind interface-driven design and the open-closed principle. The super keyword works in the opposite direction by bypassing that dynamic dispatch mechanism and pinning the method call to the specific parent class implementation at compile time.
This means that super calls are resolved statically rather than dynamically, which is a meaningful distinction in languages that rely heavily on runtime polymorphism. When you call super.someMethod() from within a child class, Java always calls the parent class version of that method, full stop. It will not further dispatch to a grandparent or an overriding version in another subclass. This predictability is precisely what makes super useful — in situations where you specifically need the parent class behavior rather than whatever the most derived class has defined, super gives you a guaranteed and unambiguous way to get exactly that behavior without depending on the runtime type of the object.
One of the most frequent mistakes involving super is attempting to use it in a static method. Because super is fundamentally tied to object instances and their inheritance relationships, it has no meaning in a static context where no object instance exists. Java will produce a compilation error immediately if you attempt to reference super from within a static method, which serves as a clear signal that the code design needs reconsideration. If a static method needs behavior from a parent class, it must call that behavior through other means, typically by creating an instance or restructuring the code to operate in an instance context.
Another common mistake is calling super in a constructor after other initialization statements have already appeared. Java’s strict requirement that super must be the absolute first statement in a constructor catches many developers off guard, particularly those coming from other languages where constructor chaining rules are more relaxed. The error message Java produces in this situation is clear enough, but developers who do not understand why the restriction exists sometimes try workarounds — like computing values before the super call — that are not permitted by the language. The correct approach is to compute any values needed as arguments to super within the super call itself using expressions, since expressions evaluate before the call executes.
The this and super keywords both serve as special reference variables in Java, and they are often discussed together because they complement each other in similar contexts — both can be used to call constructors, invoke methods, and access fields, but they resolve these references in opposite directions within the class hierarchy. The this keyword refers to the current object instance, while super refers to the parent class portion of that same object instance. Together they cover the two most common needs for explicit reference resolution in object-oriented Java code.
Just as super must appear as the first statement when calling a parent constructor, this must appear as the first statement when calling another constructor within the same class. Importantly, a constructor cannot contain both a this constructor call and a super constructor call because both must be first — Java simply does not allow both in the same constructor, and the compiler enforces this by flagging the second one as an error. This constraint is consistent with the initialization ordering rules that Java enforces throughout the object construction process, ensuring that every object is initialized in a complete and predictable sequence from the top of the class hierarchy downward to the most specific child class.
When class hierarchies extend beyond a single level of inheritance, the behavior of super becomes important to reason about carefully. If class C extends class B which extends class A, and class C uses super to call a method, that call resolves to class B’s version of the method — not class A’s version. If class B itself uses super to call the same method, that call resolves to class A’s version from within class B’s context. Each super call is always relative to the class in which it is written, not relative to the runtime type of the object or the overall depth of the hierarchy.
This level-by-level resolution means that a well-designed multi-level hierarchy can chain behavior through super calls in a disciplined way. Class A defines base behavior, class B calls super to include class A’s behavior and adds its own layer, and class C calls super to include class B’s behavior — which already incorporates class A through class B’s own super call — and adds the final specialized layer on top. When this pattern is applied consistently and each class in the hierarchy is responsible for one coherent layer of behavior, the result is an inheritance structure that is both flexible and readable, where each class can be understood in terms of what it adds to its immediate parent.
The super keyword is one of those Java features that appears simple on the surface but reveals genuine depth the more you work with inheritance-based class hierarchies. At its core, super is a tool for maintaining clear relationships between parent and child classes — a way of saying explicitly that this particular piece of behavior comes from the parent, and the child class is deliberately invoking or building upon it. Used well, super makes inheritance cleaner, more intentional, and easier to follow for anyone reading the code later.
The three contexts in which super applies — constructor delegation, method extension, and field access — each address a specific design situation that inheritance creates. Constructor delegation solves the initialization chain problem by ensuring that parent class state is properly established before child class state is added. Method extension solves the behavior composition problem by allowing child classes to include parent behavior rather than duplicating or discarding it. Field access solves the shadowing problem by providing a clear path to the parent version of a field when both levels of the hierarchy define it under the same name.
What ties all three uses together is the underlying principle that parent and child classes are partners in defining the behavior of an object, not competitors. A child class that ignores its parent through method overrides that discard parent behavior, or constructors that fail to properly initialize inherited state, creates fragile and confusing code that is difficult to maintain and extend. A child class that engages thoughtfully with its parent through appropriate use of super produces code that respects the contract of the parent class while adding the specialized behavior that justifies the child class existing at all.
As you grow in Java development experience, the patterns where super is genuinely useful become intuitive rather than requiring conscious deliberation. You will recognize when an override should include a super call because discarding the parent behavior would create an inconsistency, and you will recognize when it should not because the child class is intentionally providing a completely different implementation. That judgment — knowing when to include the parent and when to replace it — is one of the marks of mature object-oriented design thinking, and the super keyword is the mechanism through which Java gives you the control to act on that judgment precisely and explicitly in your code.
Popular posts
Recent Posts
