【问题标题】:Extension Methods in Java possible without breaking Binary Backwards Compatibility?Java 中的扩展方法可以在不破坏二进制向后兼容性的情况下实现吗?
【发布时间】:2020-05-12 16:28:36
【问题描述】:

几种语言都有扩展方法,例如 C#、Ruby、Smalltalk、Kotlin、Scala。这个想法是,您可以将方法添加到对扩展关闭的类中,例如系统类(如 String、Integer)或最终类(如 ArrayList)。

因此,您只需添加相应的扩展方法,而不是拥有所有这些 Util 类。因此,您可以调用“foo”.split(),而不是 StringUtils.split(...)。

Java 没有扩展方法。我的问题是是否可以在不破坏二进制向后兼容性的情况下将扩展方法添加到 Java 中,例如过去使用 Java8 lambda 或其他功能。问题仅在于是否可以在不制动向后兼容性的情况下完成。

在 C# 和 Kotlin 中,扩展方法被实现为静态方法。因此,与 Java 相同,StringUtils.split(...) 会有一些额外的语法,它会告诉 Java 编译器在编译时“foo”.split() 必须替换为 StringUtils.split( ...)。至少,我认为 C# 和 Kotlin 中会发生这种情况。

再次,我的问题只是关于 Java 中的扩展方法是否可以在不影响向后兼容性的情况下完成。就是这样。

【问题讨论】:

    标签: java extension-methods backwards-compatibility


    【解决方案1】:

    我不知道最终的答案,但这就是 Kotlin 的做法,这对于 Java 来说也是可能的。

    让我们考虑一个对String 的简单扩展:

    fun String.lengthSquare() = length * length
    

    Kotlin 编译器生成类似于以下的字节码(显示为对应的 Java 代码):

    public static final int lengthSquare(@NotNull String $this$lengthSquare) {
       Intrinsics.checkParameterIsNotNull($this$lengthSquare, "$this$lengthSquare");
       return $this$lengthSquare.length() * $this$lengthSquare.length();
    }
    

    所以基本上它只是创建一个接受String 的静态方法,就像我们从实用程序方法中知道的那样。我相信 Java 编译器可以做类似的事情。当然,这些扩展函数的所有调用点都会在 JVM 字节码中使用该静态方法。

    关于 Kotlin 扩展的更多信息

    扩展实际上并不修改它们扩展的类。通过定义扩展,您无需将新成员插入到类中,而只是使新函数可以使用这种类型的变量的点符号来调用。

    【讨论】:

    • 感谢您的回复,s1m0nw1。我很确定使用静态方法来模拟扩展方法,这些更改只在编译器中,并没有达到字节码级别。但我不完全确定。 Kotlin 中的示例很好,但 Kotlin 是一种从一开始就有扩展方法的新语言。因此,这并不表明 Java 中的扩展方法不会破坏向后兼容性。
    猜你喜欢
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 2011-11-10
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多