Полиморфные нетуристические вызовы методов (adhoc polymorphism) в Java

Позвольте мне начать с примера.

Скажи у меня есть аннотация 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() метод к объекту типа Vehicle чей фактический тип может быть определен только во время выполнения, JVM применит правильную версию ride(),

То есть в вызове метода с карри v.ride()Полиморфизм работает ожидаемым образом.

Но что, если у меня есть внешняя реализация в форме метода, который принимает только подтип Vehicle в качестве аргумента? Итак, что если у меня есть repair(Bicycle b) а также repair(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 это абстрактный класс, из которого фактические узлы AST, такие как Assign, MethodCall, или же ReturnStmt унаследовать. body это полиморфный список Asts.

Фрагмент кода:

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) {

}

Мои единственные возможности достижения двойной диспетчеризации - это либо проверка класса и снижение рейтинга, либо правильная реализация шаблона посетителя, верно?

1 ответ

Решение

Ответ: в Java нет многократной отправки, и она может быть смоделирована instanceof или по шаблону посетителя.

Смотрите здесь: Перегрузка метода Java + двойная отправка

Смотрите также здесь: https://en.wikipedia.org/wiki/Multiple_dispatch

На sidenote, именно это возможно в C# с dynamic звонки: Как построить двойную диспетчеризацию, используя расширения

И это также возможно во многих языках, которые компилируются в байт-код JVM, например, был упомянут Groovy.

Другие вопросы по тегам