The problem is that method signatures are binded at compile time in Java, so the declared type determines which method is called.
See also the puzzler "Making a Hash of It" in the book Java Puzzlers.
You could use double-dispatching and the Visitor pattern. It would look something like this:
Num_int A = new Num_int( );
Num B = new Num_int( );
Num C = new Num_double( );
Num_printer p = new Num_printer();
A.accept(p);
B.accept(p);
C.accept(p);
The Num_int.accept(...)
and Num_double.accept(...)
methods would both look like this:
public class Num_int extends Num {
public void accept(Num_visitor v) {
v.visit(this); // from this scope, `this` has a declared type of `Num_int`
// so at compile time this is binded to signature visit(Num_double)
}
}
public class Num_double extends Num {
public void accept(Num_visitor v) {
v.visit(this); // from this scope, `this` has a declared type of `Num_double`
// so at compile time this is binded to signature visit(Num_double)
}
}
Even though these methods are almost identical, it's important that the method isn't extracted into the parent class. I'd go so far as to make it abstract in the parent class:
public class Num {
public abstract void accept(Num_visitor);
}
From within class Num
, this
is of declared type Num
. If the accept
method were defined here, the compile-time binding would be to signature visit(Num)
- giving you the same original problem all over again.
Lastly, the Num_printer
would look like this:
public class Num_printer implements Num_visitor {
public void visit(Num_int n) {
System.out.println("int");
}
public void visit(Num_double n) {
System.out.println("double");
}
}