Полиморфные нетуристические вызовы методов (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
это полиморфный список Ast
s.
Фрагмент кода:
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.