java – 为什么我不能.invokeExact()在这里,即使MethodType是OK?
|
对于我的一个项目,我必须对构造函数进行动态调用.但由于这是 Java 7,而是使用“经典”反射API,我使用java.lang.invoke. 码: @ParametersAreNonnullByDefault
public class PathMatcherProvider
{
private static final MethodHandles.Lookup LOOKUP
= MethodHandles.publicLookup();
private static final MethodType CONSTRUCTOR_TYPE
= MethodType.methodType(void.class,String.class);
private final Map<String,Class<? extends PathMatcher>> classMap
= new HashMap<>();
private final Map<Class<? extends PathMatcher>,MethodHandle> handleMap
= new HashMap<>();
public PathMatcherProvider()
{
registerPathMatcher("glob",GlobPathMatcher.class);
registerPathMatcher("regex",RegexPathMatcher.class);
}
public final PathMatcher getPathMatcher(final String name,final String arg)
{
Objects.requireNonNull(name);
Objects.requireNonNull(arg);
final Class<? extends PathMatcher> c = classMap.get(name);
if (c == null)
throw new UnsupportedOperationException();
try {
return c.cast(handleMap.get(c).invoke(arg));
} catch (Throwable throwable) {
throw new RuntimeException("Unhandled exception",throwable);
}
}
protected final void registerPathMatcher(@Nonnull final String name,@Nonnull final Class<? extends PathMatcher> matcherClass)
{
Objects.requireNonNull(name);
Objects.requireNonNull(matcherClass);
try {
classMap.put(name,matcherClass);
handleMap.put(matcherClass,findConstructor(matcherClass));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException("cannot find constructor",e);
}
}
private static <T extends PathMatcher> MethodHandle findConstructor(
final Class<T> matcherClass)
throws NoSuchMethodException,IllegalAccessException
{
Objects.requireNonNull(matcherClass);
return LOOKUP.findConstructor(matcherClass,CONSTRUCTOR_TYPE);
}
public static void main(final String... args)
{
new PathMatcherProvider().getPathMatcher("regex","^a");
}
}
好的,这个工作. 我遇到的问题是这一行: return c.cast(handleMap.get(c).invoke(arg)); 如果我用invokeExact替换invoke,我得到这个堆栈跟踪: Exception in thread "main" java.lang.RuntimeException: Unhandled exception
at com.github.fge.filesystem.path.matchers.PathMatcherProvider.getPathMatcher(PathMatcherProvider.java:62)
at com.github.fge.filesystem.path.matchers.PathMatcherProvider.main(PathMatcherProvider.java:89)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.invoke.WrongMethodTypeException: expected (String)RegexPathMatcher but found (String)Object
at java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:350)
at java.lang.invoke.Invokers.checkExactType(Invokers.java:361)
at com.github.fge.filesystem.path.matchers.PathMatcherProvider.getPathMatcher(PathMatcherProvider.java:60)
我不太明白GlobPathMatcher和RegexPathMatcher都使用一个构造函数,其中一个String作为参数,因此,两者的MethodType都是在CONSTRUCTOR_TYPE中定义的.如果不是,我无法“抓住”MethodHandles. 但我得到一个WrongMethodTypeException.为什么? 编辑:这是我看完答案后的代码现在我不需要中间地图:我只需要有一个地图,将一个String映射到一个MethodHandle: @ParametersAreNonnullByDefault
public class PathMatcherProvider
{
private static final MethodHandles.Lookup LOOKUP
= MethodHandles.publicLookup();
private static final MethodType CONSTRUCTOR_TYPE
= MethodType.methodType(void.class,final String arg)
{
Objects.requireNonNull(name);
Objects.requireNonNull(arg);
final MethodHandle handle = handleMap.get(name);
if (handle == null)
throw new UnsupportedOperationException();
try {
return (PathMatcher) handle.invokeExact(arg);
} catch (Throwable throwable) {
throw new RuntimeException("Unhandled exception",@Nonnull final Class<? extends PathMatcher> matcherClass)
{
Objects.requireNonNull(name);
Objects.requireNonNull(matcherClass);
final MethodHandle handle;
final MethodType type;
try {
handle = LOOKUP.findConstructor(matcherClass,CONSTRUCTOR_TYPE);
type = handle.type().changeReturnType(PathMatcher.class);
handleMap.put(name,handle.asType(type));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException("cannot find constructor",e);
}
}
}
解决方法当编译器发出invokeExact调用时,它会将Object记录为预期的返回类型.从MethodHandle javadoc(强调我的):
在运行时,方法句柄实际上返回RegexPathMatcher,所以invokeExact失败了WrongMethodTypeException. 您需要使用(编译时)转换显式指定返回类型: return (RegexPathMatcher)handleMap.get(c).invokeExact(arg); 除了需要通过不同的PathMatcher实现之外,您需要转换方法句柄以使用asType返回PathMatcher,然后使用PathMatcher作为预期的返回类型. //in findConstructor MethodHandle h = LOOKUP.findConstructor(matcherClass,CONSTRUCTOR_TYPE); return h.asType(h.type().changeReturnType(PathMatcher.class)); //in getPathMatcher return (PathMatcher)handleMap.get(c).invokeExact(arg); (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
