[英]Method signature of generic Functional Interface of Method References
假设你有一个方法
void m(String s) {}
通过使用新的方法引用,您可以从中创建Consumer
Consumer<String> c = Class::m;
如果您现在通过反射查看创建的Consumer的类,您将看到它唯一声明的方法是
void accept(Object)
如果通过创建匿名内部类以旧方式创建了Consumer
Consumer<String> c = new Consumer<String>() {
public void accept(String s){}
}
会有bridge方法void accept(Object)
以及void accept(String)
。
现在让我们说我们必须通过这个消费者,从而松开它的通用类型。 如果你有一个Consumer<String>
的实现而不是Lambda表达式,你可以通过查看使用relfection访问它的方法来获取它。 由于通过方法引用创建的使用者只有通用方法,因此不起作用。 有没有办法获取方法引用创建的使用者的参数类型?
对不起,我之前没有看到这个问题。 如果您在Oracle或OpenJDK上运行,则可以使用TypeTools从lambda或方法引用中解析泛型类型信息。 例如:
Consumer<String> c = this::m;
Class<?> type = TypeResolver.resolveRawArgument(Consumer.class, c.getClass());
assert type == String.class;
很简单。 告诉你的朋友 :)
调用原始使用者(没有通用类型)总是会产生警告。 你不应该这样做,因为你不知道类型。 原始类型没有类型。 Java 8没有改变。
接口Consumer具有泛型类型,但您不知道它在运行时。 甚至不是为了lambdas。 有些类可能实际上有信息,但这对你没有帮助。 如果您确实需要知道类型,那么只需创建这样的接口。
@FunctionalInterface
public static interface StringConsumer {
void consume(String s);
}
public static void main(String[] args) throws Throwable {
StringConsumer sc = System.out::println;
sc.consume("Hello");
Method m = StringConsumer.class.getMethods()[0]; // only one: "consume"
m.invoke(sc, m.getParameters()[0].getType().getSimpleName());
}
下面是一些示例代码和输出,以查看有哪些方法以及如何调用它们:
package com.example.foo;
import static java.util.Arrays.asList;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public class SomeClass {
@FunctionalInterface
static interface FI {
public void m(String s);
}
static final class MyRegularClass {
@SuppressWarnings("static-method")
public void m(String s) {
System.out.println("MyRegularClass: " + s);
};
}
static final class MyGenericClass<T> {
public void m(T s) {
System.out.println("MyGenericClass: " + s);
};
}
public static void main(String[] args) throws Exception {
Consumer<String> c1 = (s) -> {
System.out.println("Lambda: " + s);
};
Consumer<String> c2 = new Consumer<String>() {
public void accept(String s) {
System.out.println("Anonym: " + s);
}
};
Consumer<String> c3 = new MyRegularClass()::m;
Consumer<String> c4 = new MyGenericClass<String>()::m;
for (Consumer<String> c : asList(c1, c2, c3, c4)) {
c.accept("regular invocation of accept(String)");
for (Method m : c.getClass().getDeclaredMethods()) {
String n = m.getName() + "(" + m.getParameters()[0].getType().getSimpleName() + ")";
try {
m.invoke(c, n);
} catch (Exception e) {
System.out.println("Did not accept String: " + n + " => " + e);
}
try {
m.setAccessible(true);
m.invoke(c, new StringBuilder("StringBuilder of ").append(n));
} catch (Exception e) {
System.out.println("Did not accept StringBuilder: " + n + " => " + e);
}
}
System.out.println("-----");
}
}
}
/* ==========================================
Output:
Lambda: regular invocation of accept(String)
Lambda: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
-----
Anonym: regular invocation of accept(String)
Anonym: accept(String)
Did not accept StringBuilder: accept(String) => java.lang.IllegalArgumentException: argument type mismatch
Anonym: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
-----
MyRegularClass: regular invocation of accept(String)
MyRegularClass: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
Did not accept String: get$Lambda(MyRegularClass) => java.lang.IllegalAccessException: Class com.example.foo.SomeClass can not access a member of class com.example.foo.SomeClass$$Lambda$2/1175962212 with modifiers "private static"
Did not accept StringBuilder: get$Lambda(MyRegularClass) => java.lang.IllegalArgumentException: argument type mismatch
-----
MyGenericClass: regular invocation of accept(String)
MyGenericClass: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
Did not accept String: get$Lambda(MyGenericClass) => java.lang.IllegalAccessException: Class com.example.foo.SomeClass can not access a member of class com.example.foo.SomeClass$$Lambda$3/617901222 with modifiers "private static"
Did not accept StringBuilder: get$Lambda(MyGenericClass) => java.lang.IllegalArgumentException: argument type mismatch
-----
*/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.