Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:在覆盖方法时替换参数的子类/子类型?_Java_Generics_Parameters_Overriding_Subclass - Fatal编程技术网

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

Java:在覆盖方法时替换参数的子类/子类型?,java,generics,parameters,overriding,subclass,Java,Generics,Parameters,Overriding,Subclass,所以我以前问过这个问题,但是我在代码中犯了一个错误,大多数人都会犯这个错误,而不是问题本身 无论如何,我试图重写类中的接口方法。但是,我希望重写方法中的参数类型是重写方法中定义的参数类型的子类 界面为: public interface Observer { public void update(ComponentUpdateEvent updateEvent) throws Exception; } 而重写此方法的类是: public class ConsoleDrawer extends

所以我以前问过这个问题,但是我在代码中犯了一个错误,大多数人都会犯这个错误,而不是问题本身

无论如何,我试图重写类中的接口方法。但是,我希望重写方法中的参数类型是重写方法中定义的参数类型的子类

界面为:

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,但如果可能的话,我正在寻找一个稍微优雅一点的解决方案。任何帮助都将不胜感激。谢谢。

您可以尝试以下方法。如果编译器知道您将调用第一个方法而不是第二个方法,@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(); 
}
顺便说一句:你不应该对每件事都置之不理。这当然不是最佳做法

编辑:我已经为这个问题实现了一个不同的解决方案,它与OSGi配合得很好,但可以在任何地方工作

观察者向代理注册自己,并期望找到带有注释(如ObserverCallback)的方法

e、 g


在第一种情况下,代理找到带有@ObserverCallback的方法,该方法使用一个参数。这是代理将传递的唯一类型。第二个类需要不同的类型。观察者可以有多种方法/类型,允许他们用适合该类型的不同方法处理不同的消息。您还知道,您永远不会收到您不期望的数据类型。

您不能。这不是埃菲尔。问题是您可以使用接口调用不兼容类型的实现方法。所以协变参数是不允许的。也不允许使用逆变参数,但更容易提供重载。允许使用协变返回类型(从1.5开始)

您可以参数化接口:

public interface Observer<T extends ComponentEvent> {
    void update(T event) throws Exception;
}
public interface ConsoleObserver {
    void update(ConsoleEvent event) throws Exception;
}

按照OOP原则,子类的可用方式应该与父类完全相同。 e、 g

但是,如果Java允许您在重写方法时使用参数的子类型,那么它会将代码暴露在重写方法(在子类中)拒绝输入参数的情况下(在上述情况下为ComponentUpdateEvent)。因此,您永远无法确定对观察者引用调用update()是否安全


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

我认为这是不可能的,因为它违背了接口的原则(即实现接口的类将完全匹配接口指定的所有方法签名)。但是,我会关注这个问题,因为我很有兴趣看看是否有人会证明我错了。我个人(和我交谈过的许多其他人)不喜欢将不推荐使用的标记用于除原意之外的任何事情:标记方法,这些方法过去是有效的,但现在已经不推荐了。将它用于其他类似的操作会让人感觉像黑客一样。@DGH,该方法过去是有效的(对于父类),但对于此类不再有效。;)不过我同意你的观点。理想情况下,会有一个产生编译器错误的标记。更好的方法是设计update()方法,以便所有实现都遵守契约。感谢您的建议。使用第一种解决方案;我将第二个更新方法重命名为private void addEventMessages(ConsoleUpdateEvent){/…},这似乎工作得相当好。
public interface ConsoleObserver {
    void update(ConsoleEvent event) throws Exception;
}
Observer ob = new ConsoleDrawer();
ob.update(new ComponentUpdateEvent()); // This needs to work always.