我正在寻找一个与C#扩展方法功能相当的java。现在我一直在阅读Java 8的默认方法,但据我所知,我只能将它们添加到接口......
...是否有任何语言功能可以让我为没有实现接口的最终类编写扩展方法? (我不想把它包起来......)
答案 0 :(得分:23)
Java没有扩展方法。默认方法不是扩展方法。让我们看看每个功能。
问题解决了:
Java的默认方法是向接口添加默认实现的功能。因此扩展接口的对象不必实现该方法,他们可以使用默认方法。
interface IA { default public int AddOne(int i) { return i + 1; } }
任何实现IA的对象都不必实现AddOne,因为有一个默认方法可供使用。
public class MyClass implements IA { /* No AddOne implementation needed */ }
C#缺少此功能,通过添加此功能可以大大改善。 (更新:C#8中的功能)
问题解决了:
示例:类型字符串是C#中的密封类。密封时不能从字符串继承。但是您可以添加可以从字符串中调用的方法。
var a = "mystring";
a.MyExtensionMethed()
Java缺少此功能,并且通过添加此功能可以大大改善。
Java的默认方法和C#的扩展方法功能几乎没有相似之处。它们完全不同,解决了完全不同的问题。
答案 1 :(得分:22)
C#扩展方法只是静态方法的语法糖,它将扩展类型作为第一个参数。 Java默认方法是完全不同的。要模仿C#扩展方法,只需编写常用的静态方法。但是,你不会有合成糖; Java没有此功能。
Java默认方法是真正的虚拟方法。例如,它们可以被覆盖。考虑从接口X
继承的类I
,该类声明了默认的foo()
方法。如果X
或其任何超类声明没有自己的foo()
方法,那么X
将获得foo()
I
的实现。现在,Y
的子类X
可以像通常的方法一样覆盖X.foo()
。因此,默认方法不仅仅是语法糖。它们是方法覆盖和继承机制的真正扩展,无法被其他语言特征模仿。
默认方法甚至需要特殊的VM支持,因此它们甚至不是仅编译器的功能:在类加载期间,必须检查类的层次结构以确定它将继承哪些默认方法。因此,此决定是在运行时进行的,而不是在编译时进行的。关于它的一个很酷的事情是,当它继承的接口获得一个新的默认方法时,你不必重新编译一个类:VM将在类加载时将新方法分配给它。
答案 2 :(得分:21)
C#扩展方法是静态和 use-site ,而Java的默认方法是虚拟和声明 - 站点。
我相信你所希望的是能够将一个方法“猴子修补”到你无法控制的类中,但是Java并没有给你那个(通过设计;它被考虑和拒绝了。)
默认方法相对于C#方法的另一个好处是它们是可反射发现的,实际上从外部看,与“常规”接口方法没有任何不同。
C#的扩展方法优于Java默认方法的一个优点是,使用C#的具体泛型,扩展方法被注入类型,而不是类,因此您可以注入{ {1}}方法进入sum()
。
最重要的是,Java的默认方法和C#的扩展方法之间的主要哲学区别在于C#允许您将方法注入到您无法控制的类型(这对开发人员来说肯定是方便的),而Java的扩展方法是它们出现的API的第一类部分(它们在界面中声明,它们是可反射发现的等等)。这反映了几个设计原则;库开发人员应该能够保持对API的控制,并且库的使用应该是透明的 - 类型List<int>
上的调用方法x()
在任何地方都应该是相同的。
答案 3 :(得分:7)
可以使用一些技巧来扩展方法。
您可以尝试使用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样式扩展方法。值得一看:)