所以我之前问了这个问题,但我在代码中遇到了一个错误,大多数人都接受了这个问题,而不是问题本身。
无论如何,我正在尝试覆盖类中的接口方法。但是,我希望重写方法中的参数类型是overriden方法中定义的参数类型的子类。
界面是:
public interface Observer {
public void update(ComponentUpdateEvent updateEvent) throws Exception;
}
虽然覆盖此方法的类是:
public class ConsoleDrawer extends Drawer {
//...
@Override
public void update(ConsoleUpdateEvent updateEvent) throws Exception {
if (this.componentType != updateEvent.getComponentType()) {
throw new Exception("ComponentType Mismatch.");
}
else {
messages = updateEvent.getComponentState();
}
}
//...
}
ConsoleUpdateEvent是ComponentUpdateEvent的子类。
现在,我可以让ConsoleDrawer中的update()方法将ComponentUpdateEvent作为参数,然后将其转换为ConsoleUpdateEvent,但如果可能的话,我正在寻找一个更优雅的解决方案。任何帮助,将不胜感激。谢谢。
答案 0 :(得分:8)
你做不到。这不是埃菲尔。问题是您可以使用接口以不兼容的类型调用实现方法。因此不允许使用协变参数。也不允许使用逆变参数,但更容易提供过载。允许协变返回类型(从1.5开始)。
您可以参数化界面:
public interface Observer<T extends ComponentEvent> {
void update(T event) throws Exception;
}
或者,使用更有意义的界面:
public interface ConsoleObserver {
void update(ConsoleEvent event) throws Exception;
}
答案 1 :(得分:2)
您可以尝试以下方法。如果编译器知道你将调用第一个方法而不是第二个方法,则@Deprecated会发出警告。
@Override @Deprecated
public void update(ComponentUpdateEvent updateEvent) {
// throws a ClassCastException if its not the right type.
update((ConsoleUpdateEvent) updateEvent);
}
public void update(ConsoleUpdateEvent updateEvent) {
messages = updateEvent.getComponentState();
}
BTW:你不应该只将抛出异常放在一切上。它当然不是最好的做法。
编辑:我已经为这个问题实现了一个不同的解决方案,它可以很好地与OSGi配合使用,但可以在任何地方使用。Observer向Broker注册自己,并期望找到带有注释的方法,例如ObserverCallback。
e.g。
public class ConsoleDrawer extends Drawer {
@ObserverCallback
public void onConsoleUpdateEvent(ConsoleUpdateEvent updateEvent) {
messages = updateEvent.getComponentState();
}
}
public class DeviceDrawer extends Drawer {
@ObserverCallback
public void onDeviceUpdateEvent(DeviceUpdateEvent updateEvent) {
// do something.
}
}
在第一种情况下,代理找到一个带有@ObserverCallback的方法,该方法接受一个参数。这是Broker传递它的唯一类型。第二类需要不同的类型。观察者可以有多种方法/类型,允许它们以适合该类型的不同方法处理不同的消息。您也知道您永远不会收到您不期望的数据类型。
答案 2 :(得分:2)
按照OOP原则,子类应该可以与父类完全相同的方式使用。 例如
Observer ob = new ConsoleDrawer();
ob.update(new ComponentUpdateEvent()); // This needs to work always.
但是,如果Java允许您在重写方法时使用参数的子类型,那么它会将代码暴露给重写方法(在子类中)将拒绝输入参数的情况(上面的ComponentUpdateEvent)案件)。因此,您永远不会确定在Observer引用上是否可以安全地调用update()。
因此,唯一的逻辑解决方案是接受父类参数,对其进行类型检查,然后将其强制转换为所需的子类型。