I’m trying to get my head round how Java selects which method is executed:
//Example 1 prints Square:add(Figure)
Figure fs = new Square();
fs.add(fs);
//Example 2 prints Square:add(Figure)
Rectangle rs = new Square();
rs.add(fs);
//Example 3 prints Rectangle:add(Rectangle). Expected Square:add(Square)
rs.add(new Square());
//Example 4 prints Rectangle:add(Rectangle). Expected Square:add(Figure)
Square ss = new Square();
ss.add(rs);
class Figure
{
public void add(Figure f){ System.out.println("Figure:add(Figure)"); }
}
class Rectangle extends Figure
{
@Override
public void add(Figure f){ System.out.println("Rectangle:add(Figure)"); }
public void add(Rectangle r){ System.out.println("Rectangle:add(Rectangle)"); }
}
class Square extends Rectangle
{
@Override
public void add(Figure f){ System.out.println("Square:add(Figure)"); }
public void add(Square s){ System.out.println("Square:add(Square)"); }
}
What I’ve learned here is
- Method signature gets determined based on compile time data types
- Actual method invoked depends on the dynamic type of the object the method is called on.
Based on that, the result of the first two calls is as expected. However, I don’t understand the result of example 3 and 4.
It seems to be specified in the java language specification, but I don’t understand it.
Okay, let’s look at them individually.
Example 3
The important parts are the compile-time types of the expressions
rsandnew Square().rsis only declared asRectangle, so the compiler will look at the methods declared byRectangleand its superclasses:The type of the expression
new Square()isSquare, so both methods are applicable – but the second one is more specific.So the compiler will call
add(Rectangle)on the object thatrsrefers to. That’s it for the compile-time side.At execution time, the value of
rsrefers to an instance ofSquare– butSquaredoesn’t overrideadd(Rectangle)so the method picked is the implementation inRectangle:Example 4
Again, let’s consider the compile-time types involved…
ssis of typeSquare, andrsis of typeRectangle(compile-time types, remember).The methods declared by
Squareand its superclasses are:As the compile-time type of
rsis onlyRectangle(notSquare), the first two methods are applicable, but the third isn’t. Therefore, again,add(Rectangle)is picked at compile time (as it’s more specific thanadd(Figure)).Again, the execution time type of
ssisSquare, which doesn’t overrideadd(Rectangle), so the implementation inRectangleis used.Let me know if anything in here is confusing – if you can be specific about which part, that would be great.