Mac*_*Mac 5 java reflection java-8 functional-interface
在我当前正在处理的一个 Java 项目中,我动态加载类,然后使用反射 API 来查找并执行那些具有某些注释的类的方法。
执行实际执行的代码专门根据 Java-8 功能接口工作(出于兼容性原因),因此我需要一个中间阶段,将Method
使用反射发现的实例转换为适当的功能接口。我使用MethodHandleProxies
类来实现这一点。
再次出于兼容性原因,所讨论的功能接口是通用接口。这会在使用该方法时导致“未经检查的转换”警告MethodHandleProxies.asInterfaceInstance
,因为该方法返回“裸”接口。
以下是一个简短的示例,重现了所涉及的主要步骤:
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleProxies;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.Arrays;
public class TestClass {
private String prefix;
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, SecurityException {
// Use reflection to find method.
Method method = Arrays.stream(TestClass.class.getDeclaredMethods()) // Stream over methods of ConsumerClass
.filter(m -> m.isAnnotationPresent(Marker.class)) // Retain only methods with @Marker annotation
.findFirst().get(); // Get first such method (there is only one in this case)
// Convert method to "MethodInterface" functional interface.
MethodHandle handle = MethodHandles.lookup().unreflect(method);
MethodInterface<TestClass, String> iface = MethodHandleProxies.asInterfaceInstance(MethodInterface.class, handle);
// Call "testMethod" via functional interface.
iface.call(new TestClass("A"), "B");
}
public TestClass(String prefix) {
this.prefix = prefix;
}
@Marker
public void testMethod(String arg) {
System.out.println(prefix + " " + arg);
}
@Retention(RUNTIME)
public @interface Marker { }
@FunctionalInterface
public interface MethodInterface<I,V> {
void call(I instance, V value);
}
}
Run Code Online (Sandbox Code Playgroud)
此代码可以编译并运行,但在分配给iface
.
使MethodInterface
非泛型可以解决这个特定问题,但意味着它将不再适用于任意类型的方法引用(这对于代码的其他部分来说是可取的)。
例如,使用上面的TestClass
和定义MethodInterface
,可以编译以下行:
MethodInterface<TestClass,String> iface = TestClass::testMethod;
Run Code Online (Sandbox Code Playgroud)
然而,更改为以下定义会MethodInterface
打破这一点:
@FunctionalInterface
public interface MethodInterface {
void call(Object inst, Object value);
}
Run Code Online (Sandbox Code Playgroud)
分配TestClass::testMethod
给该接口的实例无法编译,因为参数的类型错误。
在我看来,我有三个选择:
@SuppressWarnings
向作业添加注释。我尝试确保我的代码不会生成警告(以最大程度地减少出现错误的机会),因此我不热衷于选项 1。选项 2 感觉就像它只是“掩盖裂缝”,但如果绝对必要,也是可以接受的。所以我的首选选择是想出一种不同的方法。
是否有一种本质上类型安全的不同方法?
我发现有趣的是,您可以让函数将对象强制转换为特殊类型,以避免未经检查的警告,例如:
Class<MethodInterface> targetType = MethodInterface.class;
Function<Object,MethodInterface<TestClass,String>> casting=targetType::cast;
MethodInterface<TestClass, String> iface = casting.apply(
MethodHandleProxies.asInterfaceInstance(targetType, handle)
);
Run Code Online (Sandbox Code Playgroud)