覆盖的 Java 方法即使存在也未调用

Overridden Java method not called even though it exists

我需要确保我的应用程序与向我的应用程序扩展的超类引入新挂钩方法的依赖项的向前兼容性。当我开始定义 return 类型(声明类型的子类型)时,引入新添加方法的直接方法(被我构建并被新版本使用的旧版本忽略)就停止工作了。

当我直接调用我的覆盖方法时 foo.bar("") 一个超类方法被调用。但是,当我通过调试器 foo.getClass().getMethod("bar", String.class).invoke(foo, "") 的反射调用它时,它会按预期调用覆盖的方法。当其 return 类型缩小为相同类型的覆盖方法 return 时,该方法被正确调用,它之前是一个子类型。

如果使用 covariant return types 覆盖,java 编译器生成 桥接方法 ,其效果与其声明的对应方法相同,但具有 return 重写方法的类型。这是必需的,因为 JVM 通过其名称、参数列表以及不同于 Java 编程语言的 return 类型来识别方法。当且仅当编译器知道该方法覆盖并且 returned 类型是超类方法 returned 类型的子类型时,编译器才会这样做。 (请注意,该决定不取决于 @Override 注释)。

在这种情况下,编译器不知道新添加的方法应该是重写(因为旧版本的依赖项根本没有声明它)所以没有办法知道 return 类型协变的。结果,没有生成 JVM 将识别为重写的桥接方法,因此它最终在继承树的更上层搜索方法实现。

有几种方法可以解决这个问题。

  • 确保 overriding 方法以这种方式确保向前兼容性具有与其父级相同的 return 类型。所以不需要桥接方法。
  • 针对新版本的依赖构建并努力确保向后兼容性。这里最显着的缺点是支持的最小版本不是 maven POM 声明的版本。
  • 使用字节码操作显式生成桥接方法。我在这里提供 link 并不是为了阻止读者这样做。