我希望在C#中使用扩展方法实现对象列表中的功能。
这样的事情:
List<DataObject> list;
// ... List initialization.
list.getData(id);
我如何用Java做到这一点?
答案 0 :(得分:173)
Java不支持扩展方法。
相反,您可以创建常规静态方法,或编写自己的类。
答案 1 :(得分:48)
扩展方法不仅仅是静态方法而且不仅仅是方便语法糖,实际上它们是非常强大的工具。主要的是能够根据不同的泛型参数实例化覆盖不同的方法。这类似于Haskell的类型类,事实上,看起来它们在C#中支持C#的Monads(即LINQ)。即使删除LINQ语法,我仍然不知道在Java中实现类似接口的任何方法。
我认为用Java实现它们是不可能的,因为Java的泛型参数的类型擦除语义。
答案 2 :(得分:15)
Project Lombok提供了一个注释@ExtensionMethod
,可用于实现您要求的功能。
答案 3 :(得分:7)
答案 4 :(得分:6)
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();
答案 5 :(得分:6)
另一种选择是使用google-guava库中的ForwardingXXX类。
答案 6 :(得分:5)
Manifold为Java提供了C#-style extension methods和其他一些功能。与其他工具不同,Manifold没有限制,也没有suffer来自泛型,lambdas,IDE等问题.Manifold提供了其他一些功能,如F#-style custom types,TypeScript-style structural interfaces和Javascript风格的expando types。
此外,IntelliJ通过Manifold plugin为Manifold提供全面支持。
Manifold是github上提供的一个开源项目。
答案 7 :(得分:4)
看起来Defender方法(即默认方法)可能会进入Java 8的可能性很小。但是,据我所知,他们只允许{em> author 一个{ {1}}追溯性地扩展它,而不是任意用户。
Defender Methods + Interface Injection将能够完全实现C#风格的扩展方法,但AFAICS,Interface Injection甚至还没有在Java 8路线图上。
答案 8 :(得分:4)
从技术上讲,C#扩展在Java中没有等效功能。但是,如果您确实想实现这样的功能以获得更清晰的代码和可维护性,则必须使用Manifold框架。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App15"
x:Class="App15.MainPage">
<Grid>
<ScrollView>
<StackLayout Padding="30" Spacing="2" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
<Label Text="company" />
<Entry x:Name="companyEntry" Placeholder="company" />
<Label Text="Username" />
<Entry x:Name="usernameEntry" Placeholder="username" />
<Label Text="Password" />
<Entry x:Name="passwordEntry" IsPassword="true" />
<Button Text="Login" Clicked="OnLoginButtonClicked" />
<Label x:Name="messageLabel" />
<Button Text="Add" Clicked="OnAddContactClick" />
</StackLayout>
</ScrollView>
<!-- The '{Binding IsBusy}' is going to search the 'IsBusy' property inside the 'BindingContext'. In our case, is the code behind -->
<ActivityIndicator x:Name="activityIndicator" IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}" VerticalOptions="Center" HorizontalOptions="Center" Color="Blue" />
</Grid>
</ContentPage>
答案 9 :(得分:4)
Java 中没有扩展方法,但您可以通过 manifold 获得,如下所示,
您可以通过以下示例为字符串定义“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"
您也可以查看此示例,Manifold-sample
答案 10 :(得分:3)
在这个问题上迟到了派对,但是如果有人发现它有用,我只是创建了一个子类:
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);
}
}
}
答案 11 :(得分:2)
我们可以使用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()方法来访问附加到我们的支持对象。
扩展接口必须具有工厂方法,该方法将创建给定支持对象的扩展:
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);
}
}
然后,我们可以使用Extension.create()方法将包含扩展方法的接口附加到支持对象。 结果是一个可以强制转换为扩展接口的对象,通过该接口我们仍然可以访问调用base()方法的支持对象。 将引用转换为扩展接口后,我们现在可以安全地调用可以访问支持对象的扩展方法,以便现在我们可以将新方法附加到现有对象,而不附加到其定义类型:
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对象添加新协定来模拟其在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;
}
}
}
答案 12 :(得分:1)
可以使用decorator object-oriented design pattern。 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);
}
}
P.S。我是Kotlin的忠实粉丝。它有扩展方法,也可以在JVM上运行。
答案 13 :(得分:0)
您可以通过(RE)实现Collections接口并为Java Collection添加示例来创建类似于C#的扩展/帮助器方法:
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;
}
答案 14 :(得分:-7)
Java
8现在支持 default methods ,它类似于C#
的扩展方法。