这是我正在处理的一段代码。我有一个可以返回指定超类型的Callback对象。 Vehicle
是这些课程中的一个。这些类在此处用作Car
和Train
等其他类的超类型。
interface CompletionCallBack<Result> {
void onCompletion(Result result);
}
class Vehicle {
Map<String, Object> attributes;
}
class Car extends Vehicle {
public String getMake(){
return attributes.get("make").toString();
}
}
class Train extends Vehicle {
public String getMake(){
return attributes.get("size").toString();
}
}
public class Main {
static void execute(CompletionCallBack<Vehicle> callBack) {
callBack.onCompletion(new Vehicle());
}
public static void main(String[] args) {
execute(new CompletionCallBack<Vehicle>() {
@Override
public void onCompletion(Vehicle result) {
Car car = (Car) result; //Exception
}
});
execute(new CompletionCallBack<Vehicle>() {
@Override
public void onCompletion(Vehicle result) {
Train train = (Train) result; //Exception
}
});
}
}
这里我得到ClassCastException,因为Vehicule无法直接转换为Car或Train。我想致电execute
给它类似Car
或Train
这样的类型:
public class Main {
static void executeGeneric(CompletionCallBack<? extends Vehicle> callBack) {
callBack.onCompletion(new Vehicle()); //compilation error
}
public static void main(String[] args) {
executeGeneric(new CompletionCallBack<Car>() {
@Override
public void onCompletion(Car car) {
//I receive a car here
}
});
}
}
我正在尝试这样做,因为在我的情况下,Vehicle
包含属性地图和Car
车辆,该车辆在该列表中具有一些键值对。火车有其他人。我的Car
和Train
对象提供了一个简单的getter,它知道从Map
检索数据的特定键。
我能够做到的唯一方法是删除父子关系,并为Vehicle
和Train
类的Car
周围构建一个装饰器。
答案 0 :(得分:4)
问题是你有一个适用于任何车辆的机制,而不区分汽车和火车 - 但你想要汽车和火车的不同行为。
所以有几种解决方案:
1)拆分机制,以便为Car and Train提供不同的,类型化的回调
2)使用多态 - 在Vehicle中提供方法,在Car和Train中以不同的方式覆盖,并在回调中调用它们。
3)如果所有其他方法都失败了,请使用instanceof
检测对象的实际类型,然后再将其投放到Car或Train。
答案 1 :(得分:1)
原样,你要求new Vehicle()
生成一个Car
- 没有编译器或演员可以使这个工作。
你可能想要的是:
interface CompletionCallback<C> {
Class<C> getType();
void onCompletion(C object);
}
您需要在调用回调之前检查类型:
for (CompletionCallback<?> c : callBacks) {
if (c.getType().isAssignableFrom(vehicle)) {
// Perform some ugly casting here
}
}
或者您可以使用instanceof
键入检入回调。
Javas EventListenerList
也做了类似的事情。同样,内部代码涉及丑陋的铸造。但API很不错,因为你会用类型注册回调:
addCallback(Car.class, new Callback<Car>() {...});
addCallback(Submarine.class, new Callback<Submarine>() { ... });
如果我没记错的话,它会在内部将类和回调存储在Object[]
数组中,并使用强制转换。但这种模式很好:注册类型。
答案 2 :(得分:0)
您可以使用instanceof
或YourClass.class.isInstance(OtherClass);
进行测试。也许您可以创建一个界面来获取所需的值并对其进行测试。