[英]Generic Functional Interface that accepts and returns same type
我正在寻找一个满足以下两个要求的功能接口:
如果只是最初的要求,我可以创建一个简单的FunctionalInterface,如下所示:
@FunctionalInterface
public interface MonoFunction<T> {
T apply (T arg);
}
但是,这将需要在使用接口时指定类型。 但是,我想推断类型。 类似于下面的伪代码:
class A {
int a;
}
class B {
int b;
}
public static void main (String[] args) {
A a;
B b;
MonoFunction foo = (obj) -> {
system.out.println (obj)
return obj;
};
a = foo.apply (new A());
b = foo.apply (new B());
}
我如何实现这样的目标?
您可以使用UnaryOperator<T>
但必须预先定义所需的类型。
UnaryOperator<A> foo = a -> {
system.out.println(a);
return a;
};
否则,只需将结果转换为变量类型:
a = (A) foo.apply (new A());
b = (B) foo.apply (new B());
使用通用工厂方法返回函数:
static <T> UnaryOperator<T> getFooFunction() {
return obj -> {
System.out.println(obj);
return obj;
};
}
public static void main (String[] args) {
A a;
B b;
UnaryOperator<A> fooA = getFooFunction();
a = fooA.apply(new A());
UnaryOperator<B> fooB = getFooFunction();
b = fooB.apply(new B());
System.out.println(fooA==(Object)fooB);
}
请注意, getFooFunction()
给定的当前实现(HotSpot / OpenJDK), getFooFunction()
不仅在语义上返回相同的函数,甚至会是相同的对象,因为您可以通过fooA==(Object)fooB
轻松进行测试,因此没有牺牲通用类型安全性的原因。
使用UnaryOperator.identity()
时会发生相同的事情。
其他答案已经讨论了如何使用UnaryOperator<T>
。 尽管该方法提供了Java泛型的类型安全性,但是您仍然必须在创建UnaryOperator
时指定类型。 尽管我会在大多数情况下建议使用UnaryOperator
方法,但您特别地(在评论中)询问,即使必须放弃类型安全性,如何避免指定类型<T>
。
您可以按以下MonoFunction
实现MonoFunction
实现(不安全,通常不建议这样做):
public class MonoFunction {
private UnaryOperator<Object> func;
@SuppressWarnings("unchecked")
public <T> MonoFunction(UnaryOperator<T> func) {
this.func = (UnaryOperator<Object>) func;
}
@SuppressWarnings("unchecked")
public <T> T apply(T obj) {
return (T) func.apply(obj);
}
}
请注意,这不是 @FunctionalInterface
,因此必须将lambda表达式放入new MonoFunction(...)
调用中,如下所示:
public class MonoFunctionTest {
public static void main(String[] args) {
A a;
B b;
MonoFunction foo = new MonoFunction((obj) -> {
System.out.println(obj);
return obj;
});
a = foo.apply(new A()); // toString in A
b = foo.apply(new B()); // toString in B
MonoFunction bad = new MonoFunction((A obj) -> {
System.out.println(obj);
return obj;
});
a = bad.apply(a); // toString in A
b = bad.apply(b); // ClassCastException: B cannot be cast to A
}
}
class A {
public String toString() { return "toString in A"; }
}
class B {
public String toString() { return "toString in B"; }
}
我再次强调,这是不安全的,而且如所示,获得ClassCastException
也相对容易。
在功能接口内使用通用方法可以实现:
@FunctionalInterface
interface Identity {
< T > T apply( T input );
}
不幸的是,不能使用lambda函数实现这样定义的接口。 取而代之的是,它必须使用类以旧的方式完成,而最简洁的方法是使用匿名类:
Identity id = new Identity() {
public < T > T apply( T anyInput ){
// do something
return anyInput;
}
};
然后适用于任何输入:
class A {
int a = 1;
}
String outputString = id.apply( "one" );
int outputInteger = id.apply( 1 );
A outputClass = id.apply( new A() );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.