Start learning free

LESSON 182 OF 344 · OBJECT-ORIENTED PROGRAMMING

Inheritance in Java: extends, super and Reusing Code

Lesson Read the full explanation

TL ; DR:

A child class can inherit from a parent class — it gets all the parent's fields and methods for free, and can add its own. This lets you reuse code instead of copy-pasting it.


class Puppy extends Dog {
    public Puppy(String name) { super(name); }
    public void whine() { System.out.println("whimper"); }
}


Full lesson:

Inheritance is one of the four classic OOP pillars (along with encapsulation, polymorphism, and abstraction). The idea is simple: most real-world things are kinds of other things — a Puppy is a Dog, a Car is a Vehicle, a Manager is an Employee. When you model that "is-a" relationship in code, the child class gets the parent's data and behavior automatically.

What gets inherited?

  • Fields — the Puppy has a name field even though we only declared it on Dog.
  • Methods — the Puppy can call bark() even though we only defined it on Dog.
  • The contract — anywhere code expects a Dog, you can pass a Puppy (we'll see this when we cover polymorphism).

What you still write

  • The constructor usually has to forward arguments up to the parent's constructor (because the parent's fields need initializing).
  • Any new methods or new fields specific to the child.

Your task

Below the Dog class, create a Puppy class that inherits from Dog and adds one new method, whine(), that prints "whimper". The harness creates a Puppy named "Buddy", calls its inherited bark(), and then its new whine().

Expected output:

Woof! I am Buddy
whimper
STEP 1 OF 2
    Ctrl + Enter to check

    JAVA · OBJECT-ORIENTED PROGRAMMING

    Inheritance in Java, explained

    The idea

    Many things are kinds of other things: a puppy is a dog, a car is a vehicle, a manager is an employee. Inheritance models that "is-a" relationship in code. A child class (also called a subclass) is declared from a parent class (the superclass). It receives the parent's fields and methods automatically and can add its own, so you reuse code instead of copying it.

    The syntax

    You write extends and the parent's name after the child's name:

    class Puppy extends Dog {
    }
    

    Even this empty body is meaningful: Puppy already has everything Dog has. In Java a class can extend exactly one other class, though a chain is fine, such as Puppy extending Dog and Dog extending Animal.

    What gets inherited

    • Fields. A Puppy has a name field although only Dog declares it.
    • Methods. A Puppy can call bark() although only Dog defines it.
    • The type. Anywhere the code expects a Dog, you can supply a Puppy, because every puppy is a dog. The polymorphism lesson builds on this.

    One limit applies: private members of the parent exist in the child object but cannot be named directly in the child's code. A parent that wants to share a field with its children uses protected or public, or offers a getter. Constructors are never inherited.

    What you still write

    • A constructor, which usually passes its arguments to the parent's constructor, because the parent's fields still need to be initialized.
    • Any new methods and fields that only the child has.

    Calling the parent's constructor with super

    Every constructor starts by running a constructor of its parent. If you don't say which, Java quietly inserts a call to the parent's no-argument constructor. That works only if the parent has one. The Dog class in this lesson has a single constructor, Dog(String name), so Java has no no-argument version to call and the compiler stops with an error. You fix it by calling the right parent constructor yourself with super(...):

    public Puppy(String name) {
        super(name);
    }
    

    super(name) runs Dog's constructor, which stores the name. It must be the first statement of the constructor, because the parent part of the object has to be built before the child's part.

    Without it, a child like this fails to compile:

    class Kit extends Dog { }
    

    The compiler reports that constructor Dog in class Dog cannot be applied to the given types, and that the required argument is a String.

    The lesson's exercise, step by step

    The starter code supplies Dog, with a public name, a constructor and a bark method, and a mainFunction that uses a Puppy. You create the class:

    1. Declare Puppy with extends Dog below Dog, so it reuses the name field and the bark method. Give it a public constructor that takes a String name and calls super(name).
    2. Add the new behavior. Inside Puppy, below the constructor, write public void whine() and print "whimper". bark is inherited, so only the new method is needed.

    The complete program:

    class Dog {
        public String name;
        public Dog(String name) { this.name = name; }
        public void bark() {
            System.out.println("Woof! I am " + name);
        }
    }
    
    class Puppy extends Dog {
        public Puppy(String name) { super(name); }
        public void whine() {
            System.out.println("whimper");
        }
    }
    
    class Solution {
        public void mainFunction() {
            Puppy buddy = new Puppy("Buddy");
            buddy.bark();
            buddy.whine();
        }
    }
    

    The output shows both an inherited method and a new one:

    Woof! I am Buddy
    whimper
    

    The call buddy.bark() finds no bark in Puppy, so Java looks in the parent and runs Dog's version. It prints the name that super(name) stored.

    Details worth knowing

    • One direction only. A Puppy can use everything in Dog, but a plain Dog doesn't have whine(). Calling whine() on a variable of type Dog doesn't compile.
    • Every class has a parent. A class with no extends clause extends Object, which is where methods such as toString() and equals(...) come from.
    • Inheritance is for "is-a". Use it when the child really is a kind of the parent. When one object merely has another, as a dog has a name, store it in a field instead.
    • The child may change inherited behavior. That is overriding, which the next lesson covers.

    Common mistakes

    • Omitting super(name). When the parent has no no-argument constructor, the child's constructor can't compile without an explicit super(...) call.
    • Putting super(...) second. It has to be the first statement in the constructor, before anything else.
    • Redeclaring the parent's field. Writing public String name; again in Puppy creates a second field that hides the first. Reuse the inherited one.
    • Copying methods instead of inheriting them. If Puppy defines its own bark with the same text, the duplication is what inheritance exists to avoid.
    • Extending more than one class. class Puppy extends Dog, Pet is not allowed in Java.

    Key takeaways

    • class Child extends Parent gives the child the parent's accessible fields and methods.
    • The child can add new fields and methods of its own.
    • A constructor is not inherited, and the child's constructor normally calls super(...) as its first statement.
    • A Puppy can be used wherever a Dog is expected.
    • Use inheritance for "is-a" relationships.
    Keep going with JavaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free