【发布时间】:2015-11-01 13:13:38
【问题描述】:
让我从一个例子开始。
假设我有一个抽象的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) 方法怎么办? uncurried 多态方法调用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 是 Asts 的多态列表。
代码sn-p:
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) {
}
我实现双重调度的唯一可能性是检查类并向下转换或正确实现访问者模式,对吗?
【问题讨论】:
-
无论如何,不要开启类名。如果你有一个
MountainBicycle是Bicycle的子类怎么办? -
你是对的!我没有想到这一点。那么,这将变成很多
if和else if形式的if(Bicycle.class.isAssignableFrom(v.getClass()))语句。 -
你的意思是
if v instanceof Bicycle... -
啊,当然!我最初认为子类不会成为
instanceof的一部分。 -
无论如何,关于你的实际问题,我怀疑你能否得到一个好的专家答案,因为通常这种情况的解决方案取决于实际的实际用例,而不是像“玩具类”
Vehicle,Car,Bicycle,或者除了打印什么都不做的玩具方法。如果您发布一个现实世界的问题,它会更容易回答(尽管即使那样它最终也可能只是“基于意见”)。
标签: java polymorphism overloading double-dispatch adhoc-polymorphism