Java相当于C#扩展方法

Fab*_*iro 166 java extension-methods

我希望在C#中使用扩展方法实现对象列表中的功能.

像这样的东西:

List<DataObject> list;
// ... List initialization.
list.getData(id);
Run Code Online (Sandbox Code Playgroud)

我如何用Java做到这一点?

SLa*_*aks 186

Java不支持扩展方法.

相反,您可以创建常规静态方法,或编写自己的类.

  • 我在使用扩展方法后被宠坏了 - 但静态方法也可以解决问题. (55认同)
  • 但是语法非常好,并且使程序更容易理解:)我也喜欢Ruby允许你做几乎相同的事情,除了你可以实际修改内置类并添加新方法. (27认同)
  • 与其他类的额外静态方法相比,扩展方法可以使代码更加优雅.几乎所有更现代的语言都允许某种现有的类扩展:C#,php,objective-c,javascript.Java肯定会在这里展示它的时代.想象一下,您想要将JSONObject写入磁盘.你打电话给jsonobj.writeToDisk()或someunrelatedclass.writeToDisk(jsonobj)? (27认同)
  • @Ken:是的,这就是重点!为什么用Java编写而不是直接用JVM字节代码编写?这不仅仅是"语法问题"吗? (17认同)
  • 讨厌Java的原因在不断增长.几年前我停止寻找他们...... (7认同)
  • 值得指出的是,C#的扩展方法是一回事.正如这个答案所提到的,C#编译器用一个静态方法的调用替换了扩展方法.简而言之:这只是语法问题. (4认同)
  • 我在同一条船上.开始编写Android应用程序.我的lambdas,extentions,linq在哪里?Lambda扩展程度要好得多,不是我要为sort,orderby等编写每个算法.我猜它的好习惯. (3认同)
  • @DarVar:错了.接口方法的默认实现不如扩展方法灵活. (3认同)
  • 使用扩展方法只是更具可读性。它主要是语法糖,对于编译器来说实际上是同一件事,但是将其打印出来并阅读它会更好。 (2认同)
  • 我真的想要重构的扩展方法。它们不仅方便。它让我可以取出一个太大的对象并重构其中的逻辑,而无需更改使用该对象的所有位置。我可以将新提取的代码包装在扩展旧对象的扩展方法中。这样现有的调用不会改变,并且对象会变小。使用 Java 中的扩展方法,我的工作效率会显着提高。 (2认同)

use*_*250 55

扩展方法不仅仅是静态方法,而不仅仅是方便语法糖,实际上它们是非常强大的工具.主要的是能够根据不同的泛型参数实例化覆盖不同的方法.这类似于Haskell的类型类,事实上,它们看起来像是在C#中支持C#的Monads(即LINQ).即使删除LINQ语法,我仍然不知道在Java中实现类似接口的任何方法.

而且我认为不可能在Java中实现它们,因为Java的泛型参数的类型擦除语义.

  • 这整个答案是错误的.C#中的扩展方法只是语法糖,编译器重新排列一点,将方法调用的目标移动到静态方法的第一个参数.您无法覆盖现有方法.不要求扩展方法是monad.它实际上只是一种调用静态方法的更方便的方法,它给出了向类添加实例方法的外观.[如果您同意这个答案,请阅读此内容](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods) (17认同)
  • 那些说它“只是”语法糖的人可能永远不需要管理大量代码或进行审查。“可读性”是当今编程中最重要的事情,除非您在汇编器或 GPU 级别上执行繁重的性能任务。我有很多代码需要维护,我没有时间去跟踪所有那些不可读的静态方法调用。如果你将它们与 java lambda 结合起来,你的代码看起来会很糟糕。有些 lambda 看起来很糟糕而且很复杂,你最好使用旧的 `foreach` 来代替。如果java没有改进,将来我什至会将堆栈从java更改为C#。 (4认同)
  • 好,在这种情况下,定义语法糖是什么,我将语法糖称为内部宏语法,对于扩展方法,编译器必须至少查找扩展方法所要替代的静态类。答案中没有关于该方法应为无意义的monad的信息。另外,您可以将其用于重载,但它不是扩展方法功能,它是基于普通参数类型的重载,与直接调用该方法时的工作方式相同,并且在Java中的许多有趣情况下均不起作用由于泛型类型参数擦除。 (3认同)
  • 它们还允许您继承多种行为(无多态性)。您可以实现多个接口,并随之而来的是它们的扩展方法。它们还允许您实现想要附加到类型的行为,而无需将其与系统范围内的类型全局关联。 (2认同)
  • @user1686250可以用Java实现(“Java”我假设你指的是在JVM上运行的字节码)...Kotlin,它编译为字节码有扩展。它只是静态方法的语法糖。您可以使用 IntelliJ 中的反编译器来查看等效的 Java 是什么样子。 (2认同)

Tho*_*ger 17

Project Lombok提供了一个注释@ExtensionMethod,可用于实现您要求的功能.

  • [Manifold](http://manifold.systems/) 为 **Java** 提供全面、无缝的 C# 风格 **扩展方法** 支持,允许您向不受控制的类添加方法,例如`java。 lang.String`。演示:[http://manifold.systems/images/ExtensionMethod.mp4](http://manifold.systems/images/ExtensionMethod.mp4) (3认同)

Sam*_*ays 8

XTEND语言-这是一个超级的Java,并编译成Java源代码1  -支持这一点.


M.L*_*ida 8

从技术上讲,C#Extension在Java中没有等效功能。但是,如果您确实想实现这样的功能以获得更清晰的代码和可维护性,则必须使用Manifold框架。

package extensions.java.lang.String;

import manifold.ext.api.*;

@Extension
public class MyStringExtension {

  public static void print(@This String thiz) {
    System.out.println(thiz);
  }

  @Extension
  public static String lineSeparator() {
    return System.lineSeparator();
  }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*exR 6

Java没有这样的功能.相反,您可以创建列表实现的常规子类或创建匿名内部类:

List<String> list = new ArrayList<String>() {
   public String getData() {
       return ""; // add your implementation here. 
   }
};
Run Code Online (Sandbox Code Playgroud)

问题是调用此方法.你可以"到位"做到:

new ArrayList<String>() {
   public String getData() {
       return ""; // add your implementation here. 
   }
}.getData();
Run Code Online (Sandbox Code Playgroud)

  • 这是无用的. (109认同)
  • @Goran:所有这一切都允许你做的是定义一个方法,然后立即调用它,_once_. (22认同)
  • @Slaks:好的,点了.与有限的解决方案相比,编写命名类会更好. (3认同)
  • @Slaks:为什么呢?这是你自己提出的"写自己的课". (2认同)

Ara*_*ram 6

另一个选择是使用google-guava库中的ForwardingXXX类.


Sco*_*ott 6

Manifold为Java提供C#样式的扩展方法和其他一些功能。与其他工具不同,Manifold没有限制,并且不会遇到泛型,lambda,IDE等问题。Manifold提供了其他一些功能,例如F#样式自定义类型,TypeScript样式结构接口和Javascript样式expando类型

此外,IntelliJ还通过Manifold 插件为Manifold提供了全面的支持。

Manifold是可在github上获得的一个开源项目。


Jör*_*tag 5

看起来 Defender 方法(即默认方法)有可能进入 Java 8。但是,据我了解,它们只允许an 的作者interface追溯扩展它,而不允许任意用户。

Defender 方法 + 接口注入将能够完全实现 C# 风格的扩展方法,但 AFAICS、接口注入甚至还没有出现在 Java 8 路线图上。


Fur*_*ürk 5

有没有在java扩展方法,但你可以把它歧管如下,

您可以通过以下示例为字符串定义“echo”方法,

@Extension
public class MyStringExtension {
    public static void echo(@This String thiz) {
        System.out.println(thiz);
    }
}
Run Code Online (Sandbox Code Playgroud)

之后,您可以在任何地方使用此方法(回声)处理字符串,例如,

"Hello World".echo();   //prints "Hello World"
"Welcome".echo();       //prints "Welcome"
String name = "Jonn";
name.echo();            //prints "John"
Run Code Online (Sandbox Code Playgroud)

当然,你也可以有这样的参数,

@Extension
public class MyStringExtension {
    public static void echo(@This String thiz, String suffix) {
        System.out.println(thiz + " " + suffix);
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用,

"Hello World".echo("programming");   //prints "Hello World programming"
"Welcome".echo("2021");              //prints "Welcome 2021"
String name = "John";
name.echo("Conor");                  //prints "John Conor"
Run Code Online (Sandbox Code Playgroud)

您也可以查看此示例,Manifold-sample