Java:在覆盖方法时替换参数的子类/子类型?

时间:2010-12-11 17:23:48

标签: java generics parameters override subclass

所以我之前问了这个问题,但我在代码中遇到了一个错误,大多数人都接受了这个问题,而不是问题本身。

无论如何,我正在尝试覆盖类中的接口方法。但是,我希望重写方法中的参数类型是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,但如果可能的话,我正在寻找一个更优雅的解决方案。任何帮助,将不胜感激。谢谢。

3 个答案:

答案 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()。

因此,唯一的逻辑解决方案是接受父类参数,对其进行类型检查,然后将其强制转换为所需的子类型。