我希望在对象列表中实现一个功能,因为我会在c#中使用扩展方法。
就像这样:
List<DataObject> list;
// ... List initialization.
list.getData(id);
在Java中怎么做呢?
我希望在对象列表中实现一个功能,因为我会在c#中使用扩展方法。
就像这样:
List<DataObject> list;
// ... List initialization.
list.getData(id);
在Java中怎么做呢?
Java没有这样的特性。 相反,你可以创建列表实现的常规子类或创建匿名内部类:
List<String> list = new ArrayList<String>() {
public String getData() {
return ""; // add your implementation here.
}
};
问题是调用这个方法。你可以“就地”做:
new ArrayList<String>() {
public String getData() {
return ""; // add your implementation here.
}
}.getData();
看起来防御方法(即默认方法)有可能加入Java 8。然而,据我所知,它们只允许接口的作者追溯性地扩展它,而不允许任意用户。
防御方法+接口注入将能够完全实现c#风格的扩展方法,但是AFAICS,接口注入甚至还没有出现在Java 8的路线图中。
这个问题有点晚了,但如果有人发现它有用,我只是创建了一个子类:
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);
}
}
}
扩展方法不仅仅是静态方法,也不仅仅是方便的语法糖,实际上它们是非常强大的工具。主要的事情是基于不同泛型的参数实例化重写不同方法的能力。这类似于Haskell的类型类,事实上,它们看起来像是在c#中支持c#的单子(即LINQ)。即使放弃LINQ语法,我仍然不知道如何在Java中实现类似的接口。
而且我认为在Java中实现它们是不可能的,因为Java的泛型参数的类型清除语义。
可以使用面向对象的装饰器设计模式。在Java的标准库中使用这种模式的一个例子是DataOutputStream。
下面是一些增强List功能的代码:
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);
}
}
附注:我是Kotlin的忠实粉丝。它有扩展方法,也运行在JVM上。
从技术上讲,c#扩展在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();
}
}
我们可以使用自Java 8以来可用的默认方法实现来模拟Java中c#扩展方法的实现。 首先定义一个接口,允许我们通过base()方法访问支持对象,如下所示:
public interface Extension<T> {
default T base() {
return null;
}
}
我们返回null,因为接口不能有状态,但是稍后必须通过代理来修复这个问题。
扩展的开发人员必须通过一个包含扩展方法的新接口来扩展这个接口。 假设我们想在List接口上添加一个forEach消费者:
public interface ListExtension<T> extends Extension<List<T>> {
default void foreach(Consumer<T> consumer) {
for (T item : base()) {
consumer.accept(item);
}
}
}
因为我们扩展了Extension接口,所以我们可以在扩展方法中调用base()方法来访问我们所附加的支持对象。
Extension接口必须有一个工厂方法,该方法将创建给定支持对象的扩展:
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;
}
}
}
我们创建一个代理来实现扩展接口和支持对象类型实现的所有接口。 给代理的调用处理程序会将所有调用分派给支持对象,除了“base”方法,它必须返回支持对象,否则它的默认实现将返回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);
}
}
Then, we can use the Extension.create() method to attach the interface containing the extension method to the support object. The result is an object which can be casted to the extension interface by which we can still access the support object calling the base() method. Having the reference casted to the extension interface, we now can safely call the extension methods that can have access to the support object, so that now we can attach new methods to the existing object, but not to its defining type:
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);
}
}
因此,这是一种通过向Java对象中添加新契约来模拟扩展对象的能力的方法,这允许我们对给定的对象调用额外的方法。
下面你可以找到扩展接口的代码:
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;
}
}
}
你可以通过(RE)实现Collections接口来创建一个类似c#的扩展/助手方法,并添加Java Collection的示例:
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;
}
在Java中没有扩展方法,但你可以通过以下方式来获得它:
你通过下面的例子定义字符串的“echo”方法,
@Extension
public class MyStringExtension {
public static void echo(@This String thiz) {
System.out.println(thiz);
}
}
在那之后,你可以在任何地方对字符串使用这个方法(echo),
"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"
你也可以看看这个样品,歧管样品