Java 8向类添加扩展/默认方法

我正在寻找一个等同于C#扩展方法function的java。 现在我一直在阅读Java 8的默认方法,但据我所知,我只能将它们添加到接口……

…是否有任何语言function允许我为没有实现接口的最终类​​编写扩展方法? (我宁愿不用包装……)

C#扩展方法只是静态方法的语法糖,它将扩展类型作为第一个参数。 Java默认方法完全不同。 要模仿C#扩展方法,只需编写常用的静态方法。 但是,你不会有合成糖; Java没有此function。

Java默认方法是真正的虚方法。 例如,它们可以被覆盖。 考虑一个inheritance自接口I的类X ,它声明了一个默认的foo()方法。 如果X或其任何超类声明没有自己的foo()方法,那么X将获得Ifoo()实现。 现在, X的子类Y可以像通常的方法一样覆盖X.foo() 。 因此,默认方法不仅仅是语法糖。 它们是方法重写和inheritance机制的真正扩展,无法通过其他语言function进行模仿。

默认方法甚至需要特殊的VM支持,因此它们甚至不是仅编译器的特性:在类加载期间,必须检查类的层次结构以确定它将inheritance哪些默认方法。 因此,此决定是在运行时进行的,而不是在编译时进行的。 关于它的一个很酷的事情是,当它inheritance的接口获得一个新的默认方法时,你不必重新编译一个类:VM将在类加载时将新方法分配给它。

C#扩展方法是静态使用站点 ,而Java的默认方法是虚拟声明站点

我相信你所希望的是将一个方法“修补”到一个你无法控制的类中的能力,但是Java并没有给你那个(通过设计;它被考虑并被拒绝了。)

默认方法相对于C#方法的另一个好处是它们是可reflection发现的,实际上从外部看,与“常规”接口方法没有任何不同。

与Java的默认方法相比,C#的扩展方法的一个优点是,使用C#的reifiedgenerics,扩展方法被注入到类型中 ,而不是类中 ,因此可以将sum()方法注入List

最重要的是,Java的默认方法和C#的扩展方法之间的主要哲学区别在于C#允许您将方法注入到您无法控制的类型中(这对于开发人员来说肯定是方便的),而Java的扩展方法是API的一流部分。它们出现在它们中(它们在界面中声明,它们是可reflection发现的等等)。这反映了几个设计原则; 库开发人员应该能够保持对API的控制,并且库的使用应该是透明的 – 在类型Y上调用方法x()应该在任何地方都是相同的。

Java没有扩展方法。 默认方法不是扩展方法。 我们来看看每个function。

Java的默认方法

问题解决了:

  1. 许多对象可以实现相同的接口,并且它们都可以对方法使用相同的实现。 基类可以解决此问题,但前提是接口实现者还没有基类,因为java不支持多重inheritance。
  2. API希望在不破坏API使用者的情况下向接口添加方法。 添加具有默认实现的方法可解决此问题。

Java的默认方法是向接口添加默认实现的function。 因此,扩展接口的对象不必实现该方法,它们只能使用默认方法。

 interface IA { default public int AddOne(int i) { return i + 1; } } 

任何实现IA的对象都不必实现AddOne,因为有一个默认方法可以使用。

 public class MyClass implements IA { /* No AddOne implementation needed */ } 

C#缺少此function,通过添加此function可以大大改善。 (更新:C#8中的function)

C#的扩展方法

问题解决了:

  1. 能够向密封类添加方法。
  2. 能够在不强制inheritance的情况下从第三方库向类添加方法。
  3. 能够在由于约定原因而不允许模型类中的方法的环境中向模型类添加方法。
  4. 智能感知能够向您呈现这些方法。

示例:类型字符串是C#中的密封类。 密封时不能从字符串inheritance。 但是您可以添加可以从字符串调用的方法。

 var a = "mystring"; a.MyExtensionMethed() 

Java缺少此function,并且通过添加此function可以大大改进。

结论

Java的默认方法和C#的扩展方法function几乎没有相似之处。 它们完全不同,解决了完全不同的问题。

可以使用一些技巧来扩展方法。

您可以试试Lombok或XTend。 虽然扩展方法没有开箱即用的Java实现,但Lombok和XTend都提供了完全可行的解决方案。

Lombok是一个简单的独立代码处理框架,它使大多数批评的Java特定麻烦不那么痛苦,包括扩展方法: https : //projectlombok.org/features/experimental/ExtensionMethod.html

Xtend http://www.eclipse.org/xtend/向前迈进了几步,并实现了一种语言,它结合了现代语言的最佳部分,例如Java和Java类型系统上的Scala。 这允许在同一个项目中在Xtend中实现某些类,在Java中实现其他类。 Xtend代码符合有效的Java代码,因此没有JVM魔法发生在幕后。 另一方面,如果只缺少扩展方法,那就太多了。

JPropel https://github.com/nicholas22/jpropel-light使用Lombok在Java中实现LINQ样式扩展方法。 这可能值得一看:)