例から始めましょう。
抽象Vehicle
クラスがあるとします。
public abstract class Vehicle {
public Vehicle() {}
public abstract void ride();
}
そして、この抽象クラスを継承するクラスCar
と。Bicycle
public class Car extends Vehicle {
public Car() {}
@Override
public void ride() {
System.out.println("Riding the car.");
}
}
public class Bicycle extends Vehicle {
public Bicycle() {}
@Override
public void ride() {
System.out.println("Riding the bicycle.");
}
}
実際の型が実行時にしか決定できないride()
型のオブジェクトにメソッドを適用すると、JVM は正しいバージョンの を適用します。Vehicle
ride()
つまり、一種のカリー化されたメソッド呼び出しではv.ride()
、ポリモーフィズムが期待どおりに機能します。
Vehicle
しかし、引数として のサブタイプのみを受け入れるメソッドの形式で外部実装がある場合はどうなるでしょうか? では、repair(Bicycle b)
andrepair(Car c)
メソッドがある場合はどうなるでしょうか。カリー化されていないポリモーフィック メソッドの呼び出しrepair(v)
は機能しません。
例:
import java.util.ArrayList;
import java.util.List;
public class Main {
private static void playWithVehicle() {
List<Vehicle> garage = new ArrayList<Vehicle>();
garage.add(new Car());
garage.add(new Car());
garage.add(new Bicycle());
garage.forEach((v) -> v.ride()); // Works.
garage.forEach((v) -> {
/* This would be nice to have.
repair(v.castToRuntimeType());
*/
// This is an ugly solution, but the obvious way I can think of.
switch (v.getClass().getName()) {
case "Bicycle":
repair((Bicycle) v);
break;
case "Car":
repair((Car) v);
break;
default:
break;
}
});
}
private static void repair(Bicycle b) {
System.out.println("Repairing the bicycle.");
}
private static void repair(Car c) {
System.out.println("Repairing the car.");
}
public static void main(String[] args) {
playWithVehicle();
}
}
クラス名とダウンキャストを確認する必要があります。これに対するより良い解決策はありますか?
編集:私の実際の目的は、抽象構文ツリーをトラバースすることであり、たまたま二重ディスパッチが必要であることに気付きました。
Ast
Assign
、MethodCall
、またはReturnStmt
継承などの実際の AST ノードからの抽象クラスです。body
s の多相リストですAst
。
コードスニペット:
List<Ast> body;
body.parallelStream().forEach((ast) -> {
// This one won't work.
visit(ast);
// This one will work.
if (ast instanceof Assign) {
visit((Assign) ast);
} else if (ast instance of MethodCall) {
visit((MethodCall) ast);
} else if (ast instance of ReturnStmt) {
visit((ReturnStmt) ast);
}
// etc. for other AST nodes
});
private void visit(Assign ast) {
}
private void visit(MethodCall ast) {
}
private void visit(ReturnStmt ast) {
}
ダブルディスパッチを達成する唯一の可能性は、クラスをチェックしてダウンキャストするか、ビジターパターンを適切に実装することですよね?