重写的Java方法即使存在也未被调用
我需要确保我的应用程序与一个依赖项的前向兼容性,该依赖项向我的应用程序扩展的超类引入了新的钩子方法。当我开始定义返回类型时,引入新添加方法的简单方法(被我构建的旧版本忽略并被新版本使用)就停止了工作,返回类型是声明的返回类型的子类型 当我以重写的Java方法即使存在也未被调用,java,forward-compatibility,java-bridge-method,Java,Forward Compatibility,Java Bridge Method,我需要确保我的应用程序与一个依赖项的前向兼容性,该依赖项向我的应用程序扩展的超类引入了新的钩子方法。当我开始定义返回类型时,引入新添加方法的简单方法(被我构建的旧版本忽略并被新版本使用)就停止了工作,返回类型是声明的返回类型的子类型 当我以foo.bar(“”)的形式直接调用重写的方法时,会调用一个超类方法。但是,当我从调试器foo.getClass().getMethod(“bar”,String.class).invoke(foo,”)通过反射调用它时,它会按预期调用重写的方法。当方法的返回
foo.bar(“”)的形式直接调用重写的方法时,会调用一个超类方法。但是,当我从调试器foo.getClass().getMethod(“bar”,String.class).invoke(foo,”)
通过反射调用它时,它会按预期调用重写的方法。当方法的返回类型缩小到相同类型的重写方法return时,该方法会正确调用,它以前是一个子类型。如果使用重写,则java编译器生成的桥接方法与声明的对应项具有相同的效果,但返回类型为重写方法。这是必要的,因为JVM通过名称、参数列表以及返回类型(与Java编程语言不同)来标识方法。当且仅当编译器知道方法重写并且返回的类型是超类方法返回的类型的子类型时,才会执行此操作。(请注意,该决定不取决于@覆盖
注释)
在这种情况下,编译器不知道新添加的方法应该是重写(因为旧版本的依赖项根本没有声明它),所以无法知道协变函数的返回类型。结果是,没有生成将JVM标识为重写的桥接方法,因此它最终会在继承树的更上层搜索方法实现
有几种方法可以解决这个问题
- 确保以这种方式确保前向兼容性的重写方法具有与其父级相同的返回类型。因此,不需要桥接方法
- 根据新版本的依赖关系构建,并致力于确保向后兼容性。这里最值得注意的缺点是,受支持的最低版本不是maven POM声明的版本
- 使用字节码操作显式生成桥接方法。我在这里提供的链接并不是为了阻止读者这样做
在使用重写的情况下,java编译器生成的桥接方法与声明的对应方法具有相同的效果,但返回类型为重写方法。这是必要的,因为JVM通过名称、参数列表以及返回类型(与Java编程语言不同)来标识方法。当且仅当编译器知道方法重写并且返回的类型是超类方法返回的类型的子类型时,才会执行此操作。(请注意,该决定不取决于@覆盖
注释)
在这种情况下,编译器不知道新添加的方法应该是重写(因为旧版本的依赖项根本没有声明它),所以无法知道协变函数的返回类型。结果是,没有生成将JVM标识为重写的桥接方法,因此它最终会在继承树的更上层搜索方法实现
有几种方法可以解决这个问题
- 确保以这种方式确保前向兼容性的重写方法具有与其父级相同的返回类型。因此,不需要桥接方法
- 根据新版本的依赖关系构建,并致力于确保向后兼容性。这里最值得注意的缺点是,受支持的最低版本不是maven POM声明的版本
- 使用字节码操作显式生成桥接方法。我在这里提供的链接并不是为了阻止读者这样做