即使存在,也不会调用重写的Java方法

时间:2017-01-17 15:23:54

标签: java forward-compatibility java-bridge-method

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

当我直接调用我的重写方法为if meTextField.text == "" { if errLabelNotBlank == false { errorLabel.isHidden = false errorLabel.text = "You must be playing!" errLabelNotBlank = true } } else if playersDict.count < 2 { errorLabel.isHidden = false errorLabel.text = "You need at least 2 players!" errLabelNotBlank = true } else { //Code to present the next VC here } 时,会调用超类方法。但是,当我通过调试器foo.bar("")的反射调用它时,它会按预期调用重写的方法。当它的返回类型缩小到相同类型的重写方法返回时,该方法被正确调用,它之前是一个子类型。

1 个答案:

答案 0 :(得分:2)

如果覆盖covariant return types,java编译器会生成桥接方法,它们与声明的对应方具有相同的效果,但返回类型为重写方法。这是必需的,因为JVM通过其名称,参数列表以及与Java编程语言不同的方式识别方法,返回类型。当且仅当它知道方法覆盖并且返回的类型是超类'方法返回的类型的子类型时,编译器才会执行此操作。 (请注意,该决定不依赖于@Override注释)。

在这种情况下,编译器不知道新添加的方法应该是一个覆盖(因为旧版本的依赖项根本不会声明它),因此无法知道协变的返回类型。因此,没有生成将JVM识别为覆盖的桥接方法,因此它最终会继续在继承树中搜索方法实现。

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

  • 确保以这种方式确保向前兼容性的覆盖方法具有与其父级相同的返回类型。因此,不需要桥接方法。
  • 针对新版本的依赖项构建,并致力于确保向后兼容性。这里最值得注意的缺点是支持的最小版本不是maven POM声明的版本。
  • 使用字节码操作显式生成桥接方法。我这里没有提供链接以阻止读者这样做。