AP Computer Science A

💻ap computer science a review

9.4 Super Keyword

Verified for the 2025 AP Computer Science A examLast Updated on June 18, 2024

When working with inheritance in Java, subclasses often need to interact with their parent classes. Perhaps you need to call a constructor from the superclass, or maybe you want to use a method from the superclass that you've overridden. This is where the super keyword comes into play. The super keyword allows subclasses to access and use constructors and methods from their superclass, creating a bridge between parent and child classes. This guide explores how to use the super keyword effectively, its various applications, and why it's an essential tool in inheritance relationships.

What is the super Keyword?

The super keyword in Java is a reference variable that refers to the immediate parent class object. It provides a way for a subclass to access its superclass's constructors and methods. Think of it as a way for a child class to "reach up" and use functionality from its parent class.

The super keyword has two main uses:

  1. Calling superclass constructors
  2. Accessing superclass methods and fields

Calling Superclass Constructors with super

When you create an object of a subclass, Java must first initialize the superclass portion of the object. This is done by calling a constructor from the superclass.

You can explicitly call a superclass constructor using the super keyword followed by parentheses and any necessary arguments:

super();  // Call the no-argument constructor of the superclass
super(arg1, arg2);  // Call a parameterized constructor of the superclass

Important rules about using super for constructors:

  • The call to super() must be the first statement in the subclass constructor
  • If you don't explicitly call super(), Java automatically inserts a call to the superclass's no-argument constructor
  • If the superclass doesn't have a no-argument constructor and you don't call any constructor explicitly, you'll get a compilation error

Here's an example of using super to call a superclass constructor:

// Superclass
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Getters and other methods...
}

// Subclass
public class Student extends Person {
    private String studentId;
    
    public Student(String name, int age, String studentId) {
        super(name, age);  // Call Person constructor with name and age
        this.studentId = studentId;
    }
    
    // Other methods...
}

In this example, the Student constructor uses super(name, age) to call the Person constructor, ensuring that the name and age fields inherited from the Person class are properly initialized.

Calling Superclass Methods with super

The super keyword can also be used to call methods from the superclass. This is particularly useful when you've overridden a method but still want to use the original implementation as part of your new implementation.

To call a superclass method, use the super keyword followed by a dot and the method name:

super.methodName();  // Call the superclass version of the method

Here's an example of using super to call a superclass method:

// Superclass
public class Animal {
    public void makeSound() {
        System.out.println("The animal makes a generic sound");
    }
}

// Subclass
public class Dog extends Animal {
    @Override
    public void makeSound() {
        super.makeSound();  // Call Animal's makeSound method
        System.out.println("The dog barks: Woof! Woof!");
    }
}

When dog.makeSound() is called, it first executes the makeSound() method from the Animal class, then executes the additional code in the Dog class's version.

Output:

The animal makes a generic sound
The dog barks: Woof! Woof!

Passing Appropriate Parameters

When calling a superclass constructor or method with super, you must pass appropriate parameters that match the parameter list of the superclass constructor or method you're calling.

For constructors:

// Superclass with multiple constructors
public class Vehicle {
    private String make;
    private String model;
    
    public Vehicle() {
        this.make = "Unknown";
        this.model = "Unknown";
    }
    
    public Vehicle(String make, String model) {
        this.make = make;
        this.model = model;
    }
}

// Subclass calling different superclass constructors
public class Car extends Vehicle {
    private int numDoors;
    
    public Car(int numDoors) {
        super();  // Calls Vehicle's no-argument constructor
        this.numDoors = numDoors;
    }
    
    public Car(String make, String model, int numDoors) {
        super(make, model);  // Calls Vehicle's two-argument constructor
        this.numDoors = numDoors;
    }
}

For methods:

// Superclass
public class Shape {
    public double calculateArea() {
        return 0.0;
    }
    
    public void display(String prefix) {
        System.out.println(prefix + ": This is a shape");
    }
}

// Subclass
public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public void display(String prefix) {
        super.display(prefix);  // Calls Shape's display method with the prefix parameter
        System.out.println("This is a circle with radius " + radius);
    }
}

When to Use super

1. To Call an Overridden Method

Use super when you want to extend rather than completely replace the behavior of a superclass method:

public class Employee {
    public void displayInfo() {
        System.out.println("Employee Information");
    }
}

public class Manager extends Employee {
    @Override
    public void displayInfo() {
        super.displayInfo();  // Call the original method first
        System.out.println("This employee is a manager");
    }
}

2. To Access Superclass Constructors

Use super when you need to ensure proper initialization of inherited fields:

public class BankAccount {
    protected double balance;
    
    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }
}

public class SavingsAccount extends BankAccount {
    private double interestRate;
    
    public SavingsAccount(double initialBalance, double interestRate) {
        super(initialBalance);  // Initialize the balance through the superclass constructor
        this.interestRate = interestRate;
    }
}

3. To Avoid Ambiguity

Use super when there might be naming conflicts between superclass and subclass members:

public class Parent {
    protected int value = 10;
    
    public void printValue() {
        System.out.println("Parent value: " + value);
    }
}

public class Child extends Parent {
    private int value = 20;  // Same name as the superclass field
    
    @Override
    public void printValue() {
        System.out.println("Child value: " + value);  // Refers to Child's value (20)
        System.out.println("Parent value: " + super.value);  // Refers to Parent's value (10)
        super.printValue();  // Calls Parent's printValue method
    }
}

Common Mistakes and Best Practices

Common Mistakes

  1. Forgetting that super() must be the first statement in a constructor:

    // WRONG
    public Child(int value) {
        this.value = value;
        super();  // Error: super() must be first statement
    }
    
  2. Calling a non-existent superclass constructor:

    // WRONG - if Parent doesn't have a two-argument constructor
    public Child(int a, int b) {
        super(a, b);  // Error: no matching constructor in Parent
    }
    
  3. Trying to use super in a class that doesn't extend another class:

    // WRONG
    public class Standalone {
        public void someMethod() {
            super.someMethod();  // Error: Standalone doesn't extend anything
        }
    }
    

Best Practices

  1. Always call the most appropriate superclass constructor to properly initialize inherited state.

  2. Use super.method() when extending functionality rather than completely replacing it.

  3. Make clear which method you're calling by using super explicitly when overriding methods.

  4. Document constructor chains to help other developers understand initialization sequences.

Practical Examples

Example 1: Multi-level Inheritance

// Base class
public class Device {
    private String brand;
    
    public Device(String brand) {
        this.brand = brand;
        System.out.println("Device constructor called");
    }
    
    public void turnOn() {
        System.out.println("Device turning on");
    }
    
    public String getBrand() {
        return brand;
    }
}

// Intermediate class
public class Phone extends Device {
    private String model;
    
    public Phone(String brand, String model) {
        super(brand);  // Call Device constructor
        this.model = model;
        System.out.println("Phone constructor called");
    }
    
    @Override
    public void turnOn() {
        super.turnOn();  // Call Device's turnOn method
        System.out.println("Phone display lighting up");
    }
    
    public void makeCall(String number) {
        System.out.println("Calling " + number);
    }
    
    public String getModel() {
        return model;
    }
}

// Leaf class
public class Smartphone extends Phone {
    private String operatingSystem;
    
    public Smartphone(String brand, String model, String operatingSystem) {
        super(brand, model);  // Call Phone constructor
        this.operatingSystem = operatingSystem;
        System.out.println("Smartphone constructor called");
    }
    
    @Override
    public void turnOn() {
        super.turnOn();  // Call Phone's turnOn method
        System.out.println("Smartphone showing boot animation");
    }
    
    public void installApp(String appName) {
        System.out.println("Installing " + appName);
    }
    
    public void displayInfo() {
        System.out.println("Brand: " + super.getBrand());  // Call superclass method
        System.out.println("Model: " + super.getModel());  // Call superclass method
        System.out.println("OS: " + operatingSystem);
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        Smartphone myPhone = new Smartphone("Samsung", "Galaxy", "Android");
        
        // Constructor chain output:
        // Device constructor called
        // Phone constructor called
        // Smartphone constructor called
        
        myPhone.turnOn();
        // Output:
        // Device turning on
        // Phone display lighting up
        // Smartphone showing boot animation
        
        myPhone.displayInfo();
        // Output:
        // Brand: Samsung
        // Model: Galaxy
        // OS: Android
    }
}

Example 2: Using super in a Banking Application

// Base class
public class Account {
    protected double balance;
    protected double interestRate;
    
    public Account(double initialBalance, double interestRate) {
        this.balance = initialBalance;
        this.interestRate = interestRate;
    }
    
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Deposited: $" + amount);
            System.out.println("New balance: $" + balance);
        }
    }
    
    public void withdraw(double amount) {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            System.out.println("Withdrawn: $" + amount);
            System.out.println("New balance: $" + balance);
        } else {
            System.out.println("Insufficient funds");
        }
    }
    
    public void addInterest() {
        double interest = balance * interestRate;
        balance += interest;
        System.out.println("Interest added: $" + interest);
        System.out.println("New balance: $" + balance);
    }
}

// Subclass
public class CheckingAccount extends Account {
    private double overdraftLimit;
    
    public CheckingAccount(double initialBalance, double interestRate, double overdraftLimit) {
        super(initialBalance, interestRate);  // Call Account constructor
        this.overdraftLimit = overdraftLimit;
    }
    
    @Override
    public void withdraw(double amount) {
        if (amount > 0) {
            // Can withdraw if within combined balance and overdraft limit
            if (balance + overdraftLimit >= amount) {
                // Use the standard withdraw logic when possible
                if (balance >= amount) {
                    super.withdraw(amount);  // Use superclass method for normal case
                } else {
                    // Handle overdraft case ourselves
                    balance -= amount;
                    System.out.println("Withdrawn: $" + amount + " (includes overdraft)");
                    System.out.println("New balance: $" + balance);
                }
            } else {
                System.out.println("Exceeds overdraft limit");
            }
        }
    }
    
    @Override
    public void addInterest() {
        // Checking accounts have lower interest, only apply if balance is positive
        if (balance > 0) {
            super.addInterest();  // Use superclass method
        }
    }
}

Summary

The super keyword is a powerful tool in Java inheritance, allowing subclasses to interact with their superclasses in meaningful ways. By using super to call constructors, you ensure proper initialization of inherited fields. By using super to call methods, you can extend rather than completely replace superclass behavior. Remember that super can only access the immediate parent class, and it must be used as the first statement in constructors. When used properly, the super keyword helps create well-designed inheritance hierarchies where subclasses can leverage and build upon the functionality provided by their superclasses.

Key Terms to Review (9)

Area method: The area method is a technique used in computer science to calculate the size or complexity of an algorithm by counting the number of basic operations performed. It helps determine the efficiency and performance of an algorithm.
Inheritance: Inheritance is a concept in object-oriented programming where a class inherits the properties and behaviors of another class. It allows for code reuse and promotes the creation of hierarchical relationships between classes.
IsEquivalent method: The isEquivalent method is a function used in computer programming that compares two objects or values and determines if they are equal in terms of their properties or attributes. It returns true if they are equivalent and false otherwise.
Overloading: Overloading refers to defining multiple methods with the same name but different parameters within a single class. The methods must have different parameter lists or different types of parameters.
Overriding: Overriding occurs when a subclass provides its own implementation of a method that is already defined in its superclass. The overridden method in the subclass replaces the implementation inherited from the superclass.
Quadrilateral Class: A quadrilateral class is a general class in object-oriented programming that represents a four-sided polygon. It serves as the parent class for more specific types of quadrilaterals, such as rectangles, squares, and parallelograms.
Rectangle Class: A rectangle class is a specific type of shape defined in object-oriented programming that represents a four-sided polygon with opposite sides being equal in length and all angles being right angles.
Super keyword: The super keyword is used in Java to refer to the superclass of a subclass. It allows access to the superclass's methods, constructors, and instance variables.
Superclass: A superclass, also known as a parent class or base class, is a class that is extended by another class (subclass). It provides common attributes and behaviors that can be inherited by its subclasses.