简体   繁体   English

覆盖的Java方法即使存在也不会被调用

[英]Overridden Java method not called even though it exists

I need to ensure forward compatibility of my application with a dependency that introduced new hook methods to the superclass my application extends. 我需要确保应用程序的向前兼容性与将新的钩子方法引入应用程序扩展的超类的依赖关系。 The straightforward approach of introducing the newly added methods (to be ignored by the old version I build against and utilized by the new one) stopped working as soon as I started to define return types that are subtypes of declared ones. 刚开始定义返回的类型(已声明的方法的子类型)时,引入新添加的方法(被我针对的旧版本忽略并被新方法使用)的直接方法就停止了工作。

When I call my overridden method directly as foo.bar("") a superclass method gets called. 当我直接以foo.bar("")调用覆盖的方法时,将调用超类方法。 However, when I invoke it through reflection from debugger foo.getClass().getMethod("bar", String.class).invoke(foo, "") , it calls the overridden method as expected. 但是,当我通过调试器foo.getClass().getMethod("bar", String.class).invoke(foo, "")反射调用它时,它会按预期调用重写的方法。 The method gets called correctly when its return type is narrowed to the same type overridden methods return, it was a subtype before. 当方法的返回类型缩小为与该方法相同的类型时,它会被正确调用,而重写的方法返回以前是子类型。

In case of overrides with covariant return types , java compiler generates bridge methods that has the same effects as their declared counterparts but have the return type of overridden method. 如果使用协变量返回类型进行覆盖,则Java编译器会生成桥方法 ,该方法与声明的对应方法具有相同的效果,但具有覆盖方法的返回类型。 This is needed as JVM identifies methods by its name, argument list and, unlike Java programing language, its return type. 这是必需的,因为JVM通过其名称,参数列表以及与Java编程语言不同的返回类型来标识方法。 Compiler will do this if and only if it is aware that the method overrides and the returned type is a subtype of the type returned by superclass' method. 当且仅当知道方法被覆盖并且返回的类型是超类的方法返回的类型的子类型时,编译器才会执行此操作。 (Note that the decision does not depend on @Override annotation). (请注意,该决定不取决于@Override注释)。

In this case, compiler is not aware the newly added method is supposed to be an override (because old version of dependency does not declare it at all) so there is no way to know the return type of covariant. 在这种情况下,编译器不会知道新添加的方法应该被重写(因为旧版本的依赖项根本没有声明它),因此无法知道协变量的返回类型。 As a result, there is no bridge method generated that would JVM identify as override so it ends up searching for method implementation further up the inheritance tree. 结果,没有生成将JVM标识为覆盖的桥接方法,因此最终会在继承树上进一步搜索方法实现。

There are several ways to workaround this. 有几种方法可以解决此问题。

  • Make sure the overriding methods ensuring forward compatibility this way have the same return type as their parents. 确保以这种方式确保前向兼容性的重载方法与其父级具有相同的返回类型。 So no bridge methods are needed. 因此,不需要桥接方法。
  • Build against new version of dependency and work on ensuring backwards compatibility. 针对新版本的依赖关系进行构建,并努力确保向后兼容。 The most notable downside here is that the minimal supported version is not the one declared by, say, maven POM. 这里最明显的缺点是,受支持的最低版本不是maven POM声明的版本。
  • Use bytecode manipulation to generate the bridge methods explicitly. 使用字节码操作显式生成桥接方法。 I am not providing a link here to discourage readers to do so. 我没有在此处提供链接以阻止读者这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM