0

例から始めましょう。

抽象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 は正しいバージョンの を適用します。Vehicleride()

つまり、一種のカリー化されたメソッド呼び出しでは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();
}

}

クラス名とダウンキャストを確認する必要があります。これに対するより良い解決策はありますか?


編集:私の実際の目的は、抽象構文ツリーをトラバースすることであり、たまたま二重ディスパッチが必要であることに気付きました。

AstAssignMethodCall、またはReturnStmt継承などの実際の AST ノードからの抽象クラスです。bodys の多相リストです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) {

}

ダブルディスパッチを達成する唯一の可能性は、クラスをチェックしてダウンキャストするか、ビジターパターンを適切に実装することですよね?

4

1 に答える 1

0

回答: Java には複数のディスパッチはなく、ビジター パターンまたはビジター パターンによってシミュレートできますinstanceof

ここを参照してください: Javaメソッドのオーバーロード+ダブルディスパッチ

ここも参照してください: https://en.wikipedia.org/wiki/Multiple_dispatch#Examples_of_emulating_multiple_dispatch

dynamic補足として、これは呼び出しを使用した C# で正確に可能です:拡張機能を使用して二重ディスパッチを構築する方法

これは、JVM バイトコードにコンパイルされる多くの言語でも可能です。たとえば、Groovy が言及されました。

于 2015-11-01T15:26:18.967 に答える