Search code examples
javaclasscastingtostring

Is it possible to recover a parent class's overridden method?


I'm playing around with objects right now and noticed something when I override toString() for readability. Observe these classes and the results.

    class Point {
        int x;
        int y;
        Point(int x, int y) {
            this.x = x; this.y = y;
        }
        public String toString() {
            return String.format("(%d,%d)",x,y);
        }
    }
    class Line extends Point {
        int l;
        Line(int x, int y, int l) {
            super(x,y);
            this.l = l;
        }
        public String toString() {
            return String.format("Length is %d", this.l);
        }
    }
JShell REPL:
> new Point(0,0)
==> (0,0)

> new Line(0,1,4)
==> Length is 4

> Point p = new Line(0,1,3);
p ==> Length is 3

> p.x
==> 0

> p.y
==> 1

> p.l
| Error    //Expected, p is a Point reference

> ((Line) p).l
==> 3

> Line l = (Line) p
l ==> Length is 3

> l.x
==> 0

> l.y
==> 1    //referencing x and y this way were surprising, but it makes sense

> ((Line) p).x
==> 0

> l.l
==> 3

> ((Point) l).toString()
==> "Length is 3"

An object instance must use the correct reference to get the methods in the desired class. So, why is it that toString() is treated differently? It appears that toString() is called for the class that it's constructed with, regardless of what type of reference I'm using.

Edit: Since toString() is being Overridden twice, how can I ever invoke Point.toString() through type casting?


Solution

  • It appears that toString() is called for the class that it's constructed with, regardless of what type of reference I'm using.

    Yes. This is what dynamic dispatch is all about in Java. Check What is dynamic method dispatch and how does it relate to inheritance? to learn more about it.

    Demo:

    public class Main {
        public static void main(String[] args) {
            Point p1 = new Point(10, 20);
            Object p2 = new Point(5, 15);
    
            Point l1 = new Line(3, 8, 7);
            Line l2 = new Line(10, 20, 20);
            Object l3 = new Line(5, 15, 25);
    
            System.out.println(p1);
            System.out.println(p2);
            System.out.println(l1);
            System.out.println(l2);
            System.out.println(l3);
        }
    }
    

    Output:

    (10,20)
    (5,15)
    Length is 7
    Length is 20
    Length is 25