Java等价于C#扩展方法

Java等价于C#扩展方法,java,extension-methods,Java,Extension Methods,我希望在对象列表中实现一个功能,就像在C#中使用扩展方法一样 大概是这样的: List<DataObject> list; // ... List initialization. list.getData(id); 列表; // ... 列表初始化。 list.getData(id); 在Java中如何做到这一点?Java不支持扩展方法 相反,您可以创建一个常规的静态方法,或者编写自己的类。Java没有这样的功能。 相反,您可以创建列表实现的常规子类或创建匿名内部类: List&

我希望在对象列表中实现一个功能,就像在C#中使用扩展方法一样

大概是这样的:

List<DataObject> list;
// ... List initialization.
list.getData(id);
列表;
// ... 列表初始化。
list.getData(id);

在Java中如何做到这一点?

Java不支持扩展方法


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

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

List<String> list = new ArrayList<String>() {
   public String getData() {
       return ""; // add your implementation here. 
   }
};
List List=new ArrayList(){
公共字符串getData(){
return“”;//在此处添加您的实现。
}
};
问题是调用这个方法。您可以“就地”完成:

newarraylist(){
公共字符串getData(){
return“”;//在此处添加您的实现。
}
}.getData();

看起来Defender方法(即默认方法)很有可能进入Java8。然而,据我所知,它们只允许
接口的作者追溯扩展它,而不允许任意用户


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

另一个选择是使用google guava库中的类。

在这个问题上有点晚了,但如果有人发现它有用,我只是创建了一个子类:

public class ArrayList2<T> extends ArrayList<T> 
{
    private static final long serialVersionUID = 1L;

    public T getLast()
    {
        if (this.isEmpty())
        {
            return null;
        }
        else
        {       
            return this.get(this.size() - 1);
        }
    }
}
公共类ArrayList 2扩展了ArrayList
{
私有静态最终长serialVersionUID=1L;
公共T getLast()
{
if(this.isEmpty())
{
返回null;
}
其他的
{       
返回this.get(this.size()-1);
}
}
}

Java
8现在支持,这与
C#
的扩展方法类似。

该语言是Java的超集,可编译为Java源代码,支持这一点。

扩展方法不仅仅是静态方法,也不仅仅是方便的语法糖,事实上它们是非常强大的工具。最主要的是能够基于不同泛型的参数实例化重写不同的方法。这类似于Haskell的类型类,事实上,看起来它们在C#中支持C#的单子(即LINQ)。即使放弃LINQ语法,我仍然不知道如何在Java中实现类似的接口

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

提供了一个注释,可以用来实现您所要求的功能

一个人可以用这个。Java标准库中使用的这种模式的一个例子是

下面是一些用于增强列表功能的代码:

public class ListDecorator<E> implements List<E>
{
    public final List<E> wrapee;

    public ListDecorator(List<E> wrapee)
    {
        this.wrapee = wrapee;
    }

    // implementation of all the list's methods here...

    public <R> ListDecorator<R> map(Transform<E,R> transformer)
    {
        ArrayList<R> result = new ArrayList<R>(size());
        for (E element : this)
        {
            R transformed = transformer.transform(element);
            result.add(transformed);
        }
        return new ListDecorator<R>(result);
    }
}
公共类ListDecorator实现列表
{
公开最终名单;
公共ListDecorator(ListWrapee)
{
this.wrapee=wrapee;
}
//这里所有列表方法的实现。。。
公共ListDecorator映射(转换转换器)
{
ArrayList结果=新的ArrayList(size());
对于(E元素:此)
{
R转换=变压器。转换(元素);
结果:添加(转换);
}
返回新的ListDecorator(结果);
}
}
顺便说一句,我是你的超级粉丝。它有扩展方法,也在JVM上运行。

为Java提供了C#风格和其他一些特性。与其他工具不同,流形没有任何限制,也不存在泛型、lambdas、IDE等方面的问题。流形提供了一些其他功能,如F#style、TypeScript样式和Javascript样式

此外,IntelliJ通过歧管为歧管提供全面支持

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

从技术上讲,C#扩展在Java中没有等价物。但是,如果您确实希望实现这样的功能以获得更清晰的代码和可维护性,那么您必须使用流形框架

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();
  }
}

我们可以使用Java 8提供的默认方法实现来模拟Java中C#扩展方法的实现。 我们首先定义一个接口,该接口允许我们通过base()方法访问support对象,如下所示:

public interface Extension<T> {

    default T base() {
        return null;
    }
}
公共接口扩展{
默认T基(){
返回null;
}
}
我们返回null,因为接口不能有状态,但这必须稍后通过代理修复

扩展的开发者必须通过一个包含扩展方法的新接口来扩展这个接口。 假设我们想在列表界面上添加forEach consumer:

public interface ListExtension<T> extends Extension<List<T>> {

    default void foreach(Consumer<T> consumer) {
        for (T item : base()) {
            consumer.accept(item);
        }
    }

}
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

public interface Extension<T> {

    public class ExtensionHandler<T> implements InvocationHandler {

        private T instance;

        private ExtensionHandler(T instance) {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if ("base".equals(method.getName())
                    && method.getParameterCount() == 0) {
                return instance;
            } else {
                Class<?> type = method.getDeclaringClass();
                MethodHandles.Lookup lookup = MethodHandles.lookup()
                    .in(type);
                Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
                makeFieldModifiable(allowedModesField);
                allowedModesField.set(lookup, -1);
                return lookup
                    .unreflectSpecial(method, type)
                    .bindTo(proxy)
                    .invokeWithArguments(args);
            }
        }

        private static void makeFieldModifiable(Field field) throws Exception {
            field.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        }

    }

    default T base() {
        return null;
    }

    static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
        if (type.isInterface()) {
            ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
            List<Class<?>> interfaces = new ArrayList<Class<?>>();
            interfaces.add(type);
            Class<?> baseType = type.getSuperclass();
            while (baseType != null && baseType.isInterface()) {
                interfaces.add(baseType);
                baseType = baseType.getSuperclass();
            }
            Object proxy = Proxy.newProxyInstance(
                    Extension.class.getClassLoader(),
                    interfaces.toArray(new Class<?>[interfaces.size()]),
                    handler);
            return type.cast(proxy);
        } else {
            return null;
        }
    }

}
公共接口ListExtension扩展{
默认void foreach(使用者){
对于(T项:base()){
消费者接受(项目);
}
}
}
因为我们扩展了扩展接口,所以我们可以在扩展方法中调用base()方法来访问附加到的支持对象

扩展接口必须具有工厂方法,该方法将创建给定支持对象的扩展:

public interface Extension<T> {

    ...

    static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
        if (type.isInterface()) {
            ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
            List<Class<?>> interfaces = new ArrayList<Class<?>>();
            interfaces.add(type);
            Class<?> baseType = type.getSuperclass();
            while (baseType != null && baseType.isInterface()) {
                interfaces.add(baseType);
                baseType = baseType.getSuperclass();
            }
            Object proxy = Proxy.newProxyInstance(
                    Extension.class.getClassLoader(),
                    interfaces.toArray(new Class<?>[interfaces.size()]),
                    handler);
            return type.cast(proxy);
        } else {
            return null;
        }
    }
}
公共接口扩展{
...
静态E创建(类类型,T实例){
if(type.isInterface()){
ExtensionHandler=新的ExtensionHandler(实例);
列表>();
接口。添加(类型);
Class baseType=type.getSuperclass();
while(baseType!=null&&baseType.isInterface(){
接口.add(baseType);
baseType=baseType.getSuperclass();
}
对象代理=proxy.newProxyInstance(
Extension.class.getClassLoader(),
interfaces.toArray(新类[interfaces.size()]),
经办人);
返回类型.cast(代理);
}否则{
返回null;
}
}
}
public class ExtensionHandler<T> implements InvocationHandler {

    private T instance;

    private ExtensionHandler(T instance) {
        this.instance = instance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if ("base".equals(method.getName())
                && method.getParameterCount() == 0) {
            return instance;
        } else {
            Class<?> type = method.getDeclaringClass();
            MethodHandles.Lookup lookup = MethodHandles.lookup()
                .in(type);
            Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
            makeFieldModifiable(allowedModesField);
            allowedModesField.set(lookup, -1);
            return lookup
                .unreflectSpecial(method, type)
                .bindTo(proxy)
                .invokeWithArguments(args);
        }
    }

    private static void makeFieldModifiable(Field field) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField
                .setInt(field, field.getModifiers() & ~Modifier.FINAL);
    }

}
public class Program {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "c");
        ListExtension<String> listExtension = Extension.create(ListExtension.class, list);
        listExtension.foreach(System.out::println);
    }

}
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

public interface Extension<T> {

    public class ExtensionHandler<T> implements InvocationHandler {

        private T instance;

        private ExtensionHandler(T instance) {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if ("base".equals(method.getName())
                    && method.getParameterCount() == 0) {
                return instance;
            } else {
                Class<?> type = method.getDeclaringClass();
                MethodHandles.Lookup lookup = MethodHandles.lookup()
                    .in(type);
                Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
                makeFieldModifiable(allowedModesField);
                allowedModesField.set(lookup, -1);
                return lookup
                    .unreflectSpecial(method, type)
                    .bindTo(proxy)
                    .invokeWithArguments(args);
            }
        }

        private static void makeFieldModifiable(Field field) throws Exception {
            field.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        }

    }

    default T base() {
        return null;
    }

    static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
        if (type.isInterface()) {
            ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
            List<Class<?>> interfaces = new ArrayList<Class<?>>();
            interfaces.add(type);
            Class<?> baseType = type.getSuperclass();
            while (baseType != null && baseType.isInterface()) {
                interfaces.add(baseType);
                baseType = baseType.getSuperclass();
            }
            Object proxy = Proxy.newProxyInstance(
                    Extension.class.getClassLoader(),
                    interfaces.toArray(new Class<?>[interfaces.size()]),
                    handler);
            return type.cast(proxy);
        } else {
            return null;
        }
    }

}
public class RockCollection<T extends Comparable<T>> implements Collection<T> {
private Collection<T> _list = new ArrayList<T>();

//###########Custom extension methods###########

public T doSomething() {
    //do some stuff
    return _list  
}

//proper examples
public T find(Predicate<T> predicate) {
    return _list.stream()
            .filter(predicate)
            .findFirst()
            .get();
}

public List<T> findAll(Predicate<T> predicate) {
    return _list.stream()
            .filter(predicate)
            .collect(Collectors.<T>toList());
}

public String join(String joiner) {
    StringBuilder aggregate = new StringBuilder("");
    _list.forEach( item ->
        aggregate.append(item.toString() + joiner)
    );
    return aggregate.toString().substring(0, aggregate.length() - 1);
}

public List<T> reverse() {
    List<T> listToReverse = (List<T>)_list;
    Collections.reverse(listToReverse);
    return listToReverse;
}

public List<T> sort(Comparator<T> sortComparer) {
    List<T> listToReverse = (List<T>)_list;
    Collections.sort(listToReverse, sortComparer);
    return listToReverse;
}

public int sum() {
    List<T> list = (List<T>)_list;
    int total = 0;
    for (T aList : list) {
        total += Integer.parseInt(aList.toString());
    }
    return total;
}

public List<T> minus(RockCollection<T> listToMinus) {
    List<T> list = (List<T>)_list;
    int total = 0;
    listToMinus.forEach(list::remove);
    return list;
}

public Double average() {
    List<T> list = (List<T>)_list;
    Double total = 0.0;
    for (T aList : list) {
        total += Double.parseDouble(aList.toString());
    }
    return total / list.size();
}

public T first() {
    return _list.stream().findFirst().get();
            //.collect(Collectors.<T>toList());
}
public T last() {
    List<T> list = (List<T>)_list;
    return list.get(_list.size() - 1);
}
//##############################################
//Re-implement existing methods
@Override
public int size() {
    return _list.size();
}

@Override
public boolean isEmpty() {
    return _list == null || _list.size() == 0;
}
@Extension
public class MyStringExtension {
    public static void echo(@This String thiz) {
        System.out.println(thiz);
    }
}
"Hello World".echo();   //prints "Hello World"
"Welcome".echo();       //prints "Welcome"
String name = "Jonn";
name.echo();            //prints "John"
@Extension
public class MyStringExtension {
    public static void echo(@This String thiz, String suffix) {
        System.out.println(thiz + " " + suffix);
    }
}
"Hello World".echo("programming");   //prints "Hello World programming"
"Welcome".echo("2021");              //prints "Welcome 2021"
String name = "John";
name.echo("Conor");                  //prints "John Conor"