我能像在C#中创建扩展一样在Java中创建扩展吗?

3
我将提供一个与C#扩展使用相关的示例,以使我的问题更加清晰。我有一个简单的类称为Parameter,其中包含两个属性:键和值。我正在扩展Parameter列表,以便能够检查列表中是否包含某个键:
参数类:
public class Parameter
{
    private String key { get; set; }
    private String value { get; set; }
}

参数扩展类:

public static class ParameterListExtension
{
    public static bool contain(this List<Parameter> parameters, String key)
    {
        foreach (Parameter parameter in parameters) {
            if (parameter.key.Equals(key)) { return true; } }
        return false;
    }
}

扩展的用法:

List<Parameter> parameters = getParameters();
if (parameters.contain("myParameter")) { ... }

这个能用Java实现吗?


Java 无法完成此任务。 - Rohit Jain
Java 8似乎有一个同名但意义完全不同的东西:http://codingndesign.com/blog/?p=413 对我来说,这个接口看起来就像一个抽象类... - Daniel Hilgarth
4个回答

2
在Java 7及之前的版本中,无法如描述的那样操作。解决方案是使用其他答案中所描述的“helper”类。
在Java 8中,您可以使用"default"方法“有点”地实现这一点。请考虑以下内容:
public interface Parameter {
    // getters and setters
}

public class ParameterImpl implements Parameter {
    // Implements the getters and setters and the state variables.
}

现在假设我们将Parameter进行如下修改:
public interface Parameter {
    // getters and setters as before

    public default boolean contain(this List<Parameter> parameters, String key) {
        // (Do not copy this!  There are better ways to code this in Java 8 ...
        //  ... but that is beside the point.)
        for (Parameter parameter : parameters) {
            if (parameter.getKey().equals(key)) { 
                 return true; 
            } 
        }
        return false;
    }
}

我们��以对接口进行此更改(向前方向),而无需修改实现接口的类,并且不会破坏二进制兼容性。
当然,这仅适用于我们有先见之明创建了单独的接口和类。(但如果我们没有这样做,我认为修改Parameter类以添加扩展方法并不是“大问题”。)

这段代码无法编译。默认的方法签名应该是 default boolean contain(List<Parameter> parameters, String key) {。最好写成这样:static boolean contains(List<Parameter> parameters, String key) { return parameters.stream().anyMatch(p->p.getKey().equals(key)); } - ngreen
@ngreen - 我修复了编译错误。谢谢。 - Stephen C
在Java 8和C#中,方法参数中的this关键字是否用法相同? - Arturo Torres Sánchez

2

Java有一个扩展叫做Xtend,它增加了对扩展方法的支持(以及其他功能)。其中一些Xtend的特性应该在Java 8中提供。根据我的经验,在编写测试时使用Xtend有时很好,但Ecplise中的工具支持要比纯Java差得多。据我所知,没有其他IDE支持Xtend。


1
Java中没有这样的机制,可以扩展你无法控制的已定义类的行为。相反,可以定义并使用帮助器类和接口,尽管它们不能完全满足目的,特别是当可见性成为问题时。

扩展方法可以扩展一个类型,因此它们也可以用于扩展实现接口对象的行为。 - Tom Blodget

0
public class ParameterListExtension
{
  public static boolean contain(List<Parameter> parameters, String key)
  {
    for(Parameter parameter:parameters)
      if(parameter.key.equals(key)) return true;
    return false;
  }
}

import static ParameterListExtension.contain;
…
List<Parameter> parameters = getParameters();
if(contain(parameters, "myParameter")) { ... }

我不认为混淆方法来源并假装它是列表的实例方法有什么优势。


13
看一下LINQ,以及没有扩展方法的情况下它会是什么样子。这应该能够展示出优势。当然,这并不是关于混淆的问题。 - Daniel Hilgarth
1
Java 中没有 LINQ。而且 LINQ 的想法也是值得质疑的,但这超出了问题的范围。问题只涉及扩展方法,不涉及其他任何内容。 - Holger
2
“我不认为混淆方法来源并假装它是列表的实例方法有什么优势。”因为这样可以避免括号堆积和方法名称与其参数之间的距离,例如: import static ListExtensions.*; var unitNames = JoinUsing(Select(Where(list, a=>a.type == "unit"), a=>a.name), " ");与 C# 相比: using ListExtensions; var unitNames = list.Where(a=>a.type == "unit").Select(a=>a.name).JoinUsing(" "); - Venryx
@Venryx:告诉那些LISP开发者吧;-)说真的,如果你想要支持可链式操作(在Java中),你应该从第一个方法中返回一个自定义类型,而不是再次需要“扩展方法”的类型... - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接