Method Overrides

Every class inherits methods from its parent class. These methods can be called in the child class and can also be overridden.

Shape Class

This is the same shape class from before.

public class Shape {
    protected String name;
    private int length;
    private int width;

    // Default constructor
    public Shape() {
        this.name = "shape";
        this.length = 10;
        this.width = 5;
    }

    // Parameterized constructor
    public Shape(String name, int length, int width) {
        this.name = name;
        this.length = length;
        this.width = width;
    }

    // Getter methods
    public String get_name() {
        return this.name;
    }

    public int get_length() {
        return this.length;
    }

    public int get_width() {
        return this.width;
    }

    // Setter methods
    public void set_name(String n) {
        this.name = n;
    }

    public void set_length(int a) {
        this.length = a;
    }

    public void set_width(int b) {
        this.width = b;
    }

    // Method to calculate the area
    public double calc_area() {
        return this.length * this.width;
    }

    // Method to calculate the perimeter
    public double calc_perimeter(){
        return 2*this.length + 2*this.width;
    }

    // Method to print the shape
    public void print_shape() {
        System.out.println("Shape: " + this.name);
    }

    // Additional method to print something
    public void print_something() {
        System.out.println("This is a shape");
    }
}

public class Driver {
    public static void main(String[] args) {
        Shape s1 = new Shape();
    }
}

Creating a Triangle:

Currently Our shape class only takes in length and width parameters. This works fine for squares and rectangles, but what if we wanted to make a different shape? To define a Triangle we can use the 3 side lengths. while still inheriting the same behavior from the base Shape class.

public class Triangle extends Shape {
    private int side1;
    private int side2;
    private int side3;


    public Triangle() {
        this.name = "triangle";
        this.side1 = 1;
        this.side2 = 2;
        this.side3 = 3;
    }

    // Constructor that takes a name and three side lengths
    public Triangle(String name, int s1, int s2, int s3) {
        super(name, 0, 0); // Call to Shape constructor to set the name
        this.name = "triangle";
        this.side1 = s1;
        this.side2 = s2;
        this.side3 = s3;
    }
}

Here’s our Triangle

As seen above, we’re creating a new child class: Triangle This class inherits name parameter from the parent shape class and takes in 3 new side length paramiters to define the triangle’s geometry.

Lets try to create a new triangle with the side lengths 3, 4, and 5. We can also check to see if we inherited correctly from shape by callign the calc_area and print_shape methods.

Triangle t1 = new Triangle(“triangle”, 3, 4, 5); t1.print_shape(); System.out.println(“Area of t1 = “ + t1.calc_area());

We have a problem…

We were able to make a new triangle from the inherited triangle class, however, our area is not being calculated correctly. We inherited the default shape class’ calc_area method:

area = length x width

This is defaulting to an area of 0 when we create a new triangle without specifying the length and width. Instead, we can use Heron’s formula to calculate the area of a triangle given 3 side lengths.

area = sqrt(s(s-s1)(s-s2)(s-s3)) where s is the semi-perimiter (s1+s2+s3)/2

Popcorn Hack 1

Lets re-define the Triangle class but this time override the default area method with the Heron’s formula

public class Triangle extends Shape {
    private int side1;
    private int side2;
    private int side3;


    public Triangle() {
        this.name = "triangle";
        this.side1 = 1;
        this.side2 = 2;
        this.side3 = 3;
    }

    // Constructor that takes a name and three side lengths
    public Triangle(String name, int s1, int s2, int s3) {
        super(name, 0, 0); // Call to Shape constructor to set the name
        this.name = "triangle";
        this.side1 = s1;
        this.side2 = s2;
        this.side3 = s3;
    }

    @Override
    public double calc_area() {
        double area = 0.0;
        //Write Code Here
        return area;
        //expected output 6
    }
    
}

The @Override annotation tells Java that the following method will be a method override. If the following method does not override an existing method the compiler will throw an error. This is useful to catch mistakes in method name spelling and ensuring that a method override takes place. The annotation is not necessary, but is good practice.

*Note it is essential to type the name of the function to be overridden exactly

Triangle t1 = new Triangle("triangle", 3, 4, 5);
t1.print_shape();
System.out.println("Area of t1 = " + t1.calc_area());
Shape: triangle


Area of t1 = 0.0

If done correctly the area of Triangle t1 should be 6.

Important things to note

  1. using the final keyword in the parent method will make that method unable to be overridden
  2. methods can be overidden to give more access but cannot restrict acces: private -> public, but not public -> private
  3. use of @Override is highly encouraged

Popcorn Hack 2

re-write the Triangle sublcass so that it also overrides the calc_perimeter()

public class Triangle extends Shape {
    private int side1;
    private int side2;
    private int side3;


    public Triangle() {
        this.name = "triangle";
        this.side1 = 1;
        this.side2 = 2;
        this.side3 = 3;
    }

    // Constructor that takes a name and three side lengths
    public Triangle(String name, int s1, int s2, int s3) {
        super(name, 0, 0); // Call to Shape constructor to set the name
        this.name = "triangle";
        this.side1 = s1;
        this.side2 = s2;
        this.side3 = s3;
    }

    @Override
    public double calc_area() {
        double area = 0;
        //your previous area code
        return area;
    }

    // Add perimeter method override here
    //expected output 12
    
}
Triangle ti84 = new Triangle("triangle", 3, 4, 5);
System.out.println(ti84.calc_area());
System.out.println(ti84.calc_perimeter());
0.0


0.0

Super keyword

What if we wanted to create our child triangle class, but also use overridden methods from the parent shape class? For example, what if we wanted to print out not only that our shape is a triangle, but also that it is a shape. We could accomplish this with the super keyword.

public class Triangle extends Shape {
    private int side1;
    private int side2;
    private int side3;


    public Triangle() {
        this.name = "triangle";
        this.side1 = 1;
        this.side2 = 2;
        this.side3 = 3;
    }

    // Constructor that takes a name and three side lengths
    public Triangle(String name, int s1, int s2, int s3) {
        super(name, 0, 0); // Call to Shape constructor to set the name
        this.name = "triangle";
        this.side1 = s1;
        this.side2 = s2;
        this.side3 = s3;
    }
    public void print_shape() {
        super.print_something();
        print_something();
        System.out.println("Shape: " + this.name);
    }


    @Override
    public void print_something() {
        System.out.println("This is a triangle");
    }

}

Triangle t2 = new Triangle("triangle", 3, 4, 5);
t2.print_shape();
This is a shape
This is a triangle
Shape: triangle

The Super Keyword

As seen above, using the super.method calls the parent class’ method. Something to note is that calling a super method inside annother method will first complete the parent method before moving on to the next line.

As seen above, the parent print something is called first, then the triangle’s print something, and lastly print shape.

Something to be aware of is not to call a method in itself without the super keyword. This will cause an error/

public class Triangle extends Shape {
    private int side1;
    private int side2;
    private int side3;


    public Triangle() {
        this.name = "triangle";
        this.side1 = 1;
        this.side2 = 2;
        this.side3 = 3;
    }

    // Constructor that takes a name and three side lengths
    public Triangle(String name, int s1, int s2, int s3) {
        super(name, 0, 0); // Call to Shape constructor to set the name
        this.name = "triangle";
        this.side1 = s1;
        this.side2 = s2;
        this.side3 = s3;
    }
    public void print_shape() {
        print_shape();
    }


    @Override
    public void print_something() {
        System.out.println("This is a triangle");
    }

}

Triangle t2 = new Triangle("triangle", 3, 4, 5);
t2.print_shape();

As seen above, this results in an infinite loop