HomepageTeaching PageResearch PageResources Page

Java Tutorial for Python Programmers

Subclasses and Inheritance

Declaring a subclass

Inheritance is a useful tool in Java just as in Python. It's very easy to create a subclass. First create the following Mammal.java class:

public class Mammal {

    //age in years
    private int age;
    
    public Mammal(int age) {
        this.age = age;
        if (this.age < 0) {
            //avoid negative ages!
            this.age = 0;
        }
    }
    
    public String toString() {
        return "A " + age + " year old mammal with a four-chamber heart.";
    }
    
} //end of Mammal.java
        

Now, create a new file, Mouse.java. We can declare this as a subclass by using the following class signature:

public class Mouse extends Mammal {

} //end of Mouse.java
        

Inheritance

Since the Mouse class extends Mammal, it inherits all of Mammal's members. That means it already has the age field (even though it's private). Let's add a constructor to Mouse.java and set the age field in there. We want a constructor with signature

    public Mouse(int age) {
        //body of the constructor goes here
    }
        

There are three common ways to do this, from worst to best:

  1. Change the age field in Mammal to be protected:

        protected int age;
                    

    Now the Monkey constructor can be written just like the one in Mammal.

  2. Leave the age private, and add a setAge method to Mammal.java (not Monkey.java) similar to the one we did for Monkey:

        public void setAge(int age) {
            if (age >= 0) {
                //change the age if positive
                this.age = age;
            }
        }
                    

    Now the Monkey constructor can invoke the setAge method:

        public Mouse(int age) {
            this.setAge(age);
        }
                    
  3. Invoke the superclass's constructor. It is common for constructors of subclasses to call the constructor in the super class. This must be done in the first line:

        public Mouse(int age) {
            super(age);
        }
                    

    This last version is considered the best because it avoids adding extra code to Mammal.java for Monkey.java's sake. Sometimes you only have access the the .class file for the superclass, not the source code (the .java), thus you can't modify the superclass implementation.

For all three solutions, the code can be tested by adding the following to CodeToRun.java.

    public static void main(String[] args) {
        Mouse mouse = new Mouse(2);
        System.out.println("mouse: " + mouse);
    }
        

Since Mammal has implemented toString, that will be invoked, giving us the following output when tested:

$ javac *.java
Note: CodeToRun.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ java CodeToRun
mouse: A 2 year old mammal with a four-chamber heart.
$
        

Overriding Methods

Just like in Python, we might decide that a superclass's method is inappropriate for the subclass. We can solve this problem by overriding the method, implementing the desired method body inside the subclass. Add a toString method to Mouse.java:

    
    public String toString() {
        return "A tiny mouse that is " + this.getAge() + " years old.";
    }
        

Test this code out and notice that the subclass's method is invoked.

Declared Types

We can declare variables to have types of any supertype. Add the following to CodeToRun.java:

    public static void main(String[] args) {
        Mouse mouse = new Mouse(2);
        Mammal mammal = new Mouse(3);
        Object object = new Mouse(4);
    }
        

Object is automatically a superclass of all other classes. The above code compiles happily because the values stored in the three variables all have the correct types: any value is of it's own type and all supertypes. Thus, each Mouse is also a Mammal and an Object.

The reverse is not true, however. The following code does not compile:

    public static void main(String[] args) {
        Mouse mouse = new Mammal(5);
    }
        

Polymorphism

All object-oriented languages must implement polymorphism: where objects act as their own type, not their declared type. Let's go back to the main code with three mice of different declared types, then add three print statements that will invoke toString methods:

    public static void main(String[] args) {
        Mouse mouse = new Mouse(2);
        Mammal mammal = new Mouse(3);
        Object object = new Mouse(4);
        System.out.println("mouse: " + mouse);
        System.out.println("mammal: " + mammal);
        System.out.println("object: " + object);
    }
        

Which version of toString will be invoked in each line? If the declared types' (Mouse, Mammal, then Object) versions are called, then we'll see three different types of messages. Is that what happens? Try it out!

$ javac *.java
Note: CodeToRun.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ java CodeToRun
mouse: A tiny mouse that is 2 years old.
mammal: A tiny mouse that is 3 years old.
object: A tiny mouse that is 4 years old.
$
        

The compiler only knows that mammal is a Mammal, not that it's a Mouse. The same is true for object. At run-time, though, Java takes the time to determine the actual type of the value in the variable to choose which method to invoke. (This is called dynamic method invocation.) Choosing the most specific method at the time of invocation is vital to polymorphism.

Abstract classes and Interfaces

Abstract classes and interfaces are just slightly beyond the scope of this tutorial. I'll add a link you can check out later.

Test Your Understanding


Tutorial Table of Contents

  1. Intro
  2. Java Files and Classes
  3. Running Java Code
  4. Statements and Printing
  5. Comments
  6. Types and Variables
  7. Conditionals
  8. Static Methods
  9. Strings
  10. Loops
  11. Arrays
  12. ArrayLists
  13. Classes
  14. Subclasses
  15. Generic Types
  16. Javadoc
  17. Final Exam
  18. What's Next?