Java Inheritance – Matching Return Type with Subclass

inheritancejavareturn-type

I am rather inexperience in Java, and I'm having a problem in forming a subclass of a class I have created. The class I have made, called Vector2D, contains methods, such as add(Vector2D addend), that takes a Vector2D object as an argument, and returns a Vector2D object. This method in particular is designed to add two vectors, and return the sum.

Then, I started coding a subclass, called Position2D, which I intend to have all of the functionality of the Vector2D class, except have additional functions, and have any usage of Vector2D inside the preexisting classes, be it as an argument, return type, etc., replaced with Position2D, so that the add(Position2D addend) function adds two Position2D vectors together, and returns the sum as a Position2D.

The issue arises that, when Position2D inherits from Vector2D, such functions continue to work in terms of Vector2D objects, spitting out an error as soon as a Position2D object is passed through it.

The relevant code for the Vector2D class is as follows:

public class Vector2D{

    //Field Variables
    private double x; //The vector's x-coordinate
    private double y; //The vector's y-coordinate

    //Constructors
    public Vector2D(){
        //Constructs empty vector.
        setX(0);
        setY(0);
    }

    //Methods
    public void setX(double newX){
        //This method is not problematic when inherited for the subclass.
        x = newX;
    }

    public void setY(double newY){
        //This method is not problematic too.
        y = newY;
    }

    public Vector2D add(Vector2D addend){
        //Adds two vectors and returns the sum.
        //This method, however, does pose a problem.
        Vector2D sum = new Vector2D();
        sum.x = x + addend.x;
        sum.y = y + addend.y;
        return sum;
    }

}

The only work-around I can currently think of as to what the code in add(Position2D addend) in Position2D could be is:

public Position2D add(Position2D addend){
    //Adds two position vectors and returns the sum.
    Position2D sum = new Position2D();
    sum.x = x + addend.x;
    sum.y = y + addend.y;
    return sum;
}

i.e., repeat the method from Vector2D, and manually modify it. This, of course, is not efficient and wastes time, especially so whenever the same has to be done for similar methods, and more so whenever I intend to make more subclass, e.g. Velocity2D. Therefore, I am looking for a much cleaner and efficient means of doing this.

Best Answer

Remember inheritance defines a "is a" kind of relationship. The code

class Position2D extends Vector2D

tells the compiler that every Position2D is a Vector2D, but not vice versa.

Check out the following examples assuming that you already made the above declaration:

// obviously okay, type of instance matches reference type
Vector2D vecVecRef = new Vector2D();
Position2D posPosRef = new Position2D();
// this is okay because a Position2D is a Vector2D
Vector2D posVecRef = new Position2D();
// The compiler will not automatically convert a Vector2D to a Position2D
Position2D vecPosRef = new Vector2D(); //Compiler error!

A Position2D variable can never refer to a Vector2D object. If you try typecasting it, the compiler will say "fine...I trust you" but then the JVM will get angry when it actually finds out that you are trying to assign a Vector2D to a Position2D. It will raise a ClassCastException at runtime.

// compiles fine but raises ClassCastException in runtime
Position2D vecPosRef = (Position2D) new Vector2D();

This is because you can only Class cast a subclass into a superclass and not vice versa. So basically, you cannot cast Vector2D to Position2D and you cannot assign it without casting either.

The simplest solution to this problem is to have a constructor defined in your subclass that makes a Position2D object out of a given Vector2D object.

class Position2D extends Vector2D {
    Position2D() {
        // default stuff
    }

    Position2D(Vector2D v) {
        // you currently don't have the getX and getY methods
        // so define them in your superclass
        setX(v.getX());
        setY(v.getY());
    }
}

With that one simple and convenient constructor, you can use code like this:

public class Inheritance {
    public static void main(String[] args) {
        Position2D pos1 = new Position2D();
        Position2D pos2 = new Position2D();
        pos1.setX(3);
        pos1.setY(4);
        pos2.setX(5);
        pos2.setY(6);
        Position2D pos3 = new Position2D(pos1.add(pos2)); // using constructor
        System.out.println(pos3.getX()); // this prints 8.0
    }
}

As you can see, this way is much more extensible than rewriting all of the subclass methods.