MethodHandle类的描述中显示的示例在使用以下描述WrongMethodTypeException的语句调用中抛出a mh.invokeExact("daddy",'d','n'): (CC)Ljava/lang/String; cannot be called with a different arity as ([Ljava/lang/Object;)Ljava/lang/Object;.
该MethodHandle对象mh具有对应于的符号类型描述符:(CC)Ljava/lang/String.但是当我们调用时mh.invokeExact("daddy",'d','n'),参数:d并n作为Object数组传递,然后它们与该类型的参数不匹配char.
我知道我可以使用invokeWithArguments而不是invokeExcat或者解决上述问题invoke,但是这个例子应该像MethodHandleJava 7 API 的描述中所说的那样工作.除此之外,它invokeWithArguments具有与invoke/ 相关的性能开销invokeExact.
我有这段代码可以正常工作:
Method getterMethod = Person.class.getDeclaredMethod("getName");
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
Class<?> declaringClass = getterMethod.getDeclaringClass();
Class<?> returnType = getterMethod.getReturnType();
CallSite getterSite = LambdaMetafactory.metafactory(lookup,
"apply",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class),
lookup.findVirtual(declaringClass, getterMethod.getName(), MethodType.methodType(returnType)),
MethodType.methodType(propertyType, declaringClass));
Function getterFunction = (Function) getterSite.getTarget().invokeExact();
Run Code Online (Sandbox Code Playgroud)
但是,如果该getterMethod方法来自从不同 ClassLoader 加载的类,则会抛出:
Caused by: java.lang.invoke.LambdaConversionException: Invalid caller: java.lang.Object
at java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:118)
at java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:155)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:299)
Run Code Online (Sandbox Code Playgroud)
如何将我的ClassLoader实例传递给LambdaMetafactory?
我要打印 hi GrandFather
但它似乎打印喜父亲。我不明白如何区分findSpecial和findVirtual
我想要有人可以帮助我。谢谢
class GrandFather{
void thinking(){
System.out.println("hi GrandFather");
}
}
class Father extends GrandFather{
void thinking(){
System.out.println("hi Father");
}
}
class Son extends Father{
void thinking(){
MethodType mt=MethodType.methodType(void.class);
//MethodHandle mh=MethodHandles.lookup().findVirtual(GrandFather.class,"thinking",mt).bindTo(this);
MethodHandle mh;
mh = MethodHandles.lookup().findSpecial(GrandFather.class,"thinking",mt,getClass());
mh.invoke(this);
}
}
public static void main(String[] args){
(new MethodHandleTest().new Son()).thinking();
}
Run Code Online (Sandbox Code Playgroud)

我正在利用ByteBuddy 对 Constant 的MethodHandle支持的支持。
我正在尝试(有效地)查找MethodHandle一个类,然后从 ByteBuddy 生成的子类中使用它。
(我知道我可以使用静态来做到这一点MethodHandle字段和类型初始值设定项来完成此操作,但我想使用此常量支持来尝试它。)
我有一个FieldDescription.Token代表第一类的领域,还有一个TypeDescription代表第一类。从这些我可以得到FieldDescription.InDefinedShape这样的:new FieldDescription.Latent(typeDescription, fieldDescriptionToken)。从中我可以得到这样的信息:JavaConstant.MethodHandleJavaConstant.MethodHandle.ofSetter(fieldDescriptionLatent)。这很好用。
然后我这样做:
\n// Call invokeExact() on the MethodHandle I looked up, but\n// call it on that MethodHandle as a constant pool entry.\nbuilder\n .intercept(MethodCall.invoke(INVOKE_EXACT)\n .on(new JavaConstantValue(javaConstantMethodHandle),\n MethodHandle.class)\n // etc.\nRun Code Online (Sandbox Code Playgroud)\n通过这样做,我使用了on采用 a 的重载StackManipulation,在本例中是JavaConstantValue包装 a 的重载JavaConstant,a 是 的超类JavaConstant.MethodHandle …
我试图检查是否可以使用MethodHandle :: invoke或MethodHandle :: invokeExact作为接受MethodHandle并返回通用输出的功能接口的方法引用.
(我知道invoke和invokeExact是签名多态,因此在InvokeExact中调用metafactory.但是,我想知道编译器是否能够忽略我必须做的事情来导出一个合适版本的invoke/invokeExact.)
invoke.InvokeExact0
package invoke;
import java.lang.invoke.MethodHandle;
import static java.lang.System.out;
import static java.lang.invoke.LambdaMetafactory.metafactory;
import static java.lang.invoke.MethodHandles.lookup;
import static java.lang.invoke.MethodType.methodType;
@FunctionalInterface
public interface InvokeExact0<OUTPUT> {
public OUTPUT invokeExact(MethodHandle methodHandle) throws Throwable;
public static <OUTPUT> InvokeExact0<OUTPUT> new_(InvokeExact0<OUTPUT> invokeExact) {
return invokeExact;
}
public static void main(String... arguments) throws Throwable {
out.println(
(InvokeExact0<String>) metafactory(
lookup(),
"invokeExact",
methodType(InvokeExact0.class),
methodType(
Object.class,
MethodHandle.class
),
lookup().findVirtual(
MethodHandle.class,
"invokeExact",
methodType(String.class)
),
methodType(
String.class,
MethodHandle.class
)
)
.getTarget()
.invokeExact()
);
out.println(InvokeExact0.new_(MethodHandle::invokeExact));
}
}
Run Code Online (Sandbox Code Playgroud)
结果
invoke.InvokeExact0$$Lambda$1/1878246837@5ca881b5 …Run Code Online (Sandbox Code Playgroud) 我有两个类A和B,都定义了foo()具有共同签名的方法(不接受任何内容,返回无效)。它们没有声明此方法的公共基类(或接口)。我想调用这个方法,不管是 As 还是 B,只要他们能响应这个调用。这种方法称为Duck Typing。
我知道有一个指令叫做invokedynamic:
调用动态指令的每个实例称为动态调用点。动态调用站点最初处于未链接状态,这意味着没有为调用站点指定要调用的方法。如前所述,动态调用站点通过引导方法链接到方法。动态调用站点的引导方法是编译器为动态类型语言指定的方法,JVM 调用一次以链接站点。从引导方法返回的对象永久确定调用站点的行为。
所以我尝试使用MethodHandles来实现这一点。这是示例:
public static class A {
public void foo() {
}
}
public static class B {
public void foo() {
}
}
public static void main(String[] args) throws Throwable {
final MethodHandle foo = MethodHandles.lookup()
.findVirtual(A.class, "foo", MethodType.methodType(void.class));
foo.invoke(new B());
}
Run Code Online (Sandbox Code Playgroud)
当然,我有:
Exception in thread "main" java.lang.ClassCastException: Cannot cast Main$B to Main$A
at sun.invoke.util.ValueConversions.newClassCastException(ValueConversions.java:461)
at sun.invoke.util.ValueConversions.castReference(ValueConversions.java:456)
at …Run Code Online (Sandbox Code Playgroud) 解释起来会有点复杂,但我会尝试。
假设你有一个泛型类:
static class Box<T extends Number> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Run Code Online (Sandbox Code Playgroud)
以及一种允许以getValue反射方式调用的方法:
// it's just an example, the real world scenario is slightly more involved
private static final Lookup LOOKUP = MethodHandles.lookup();
public static <T, R> T result(String methodName, Class<T> propertyClass, R instance) {
try {
/* line1 */
MethodHandle handle = LOOKUP.findVirtual(
instance.getClass(),
methodName,
MethodType.methodType(propertyClass)
);
/* line2 */
handle …Run Code Online (Sandbox Code Playgroud) 我知道这publicLookup()比lookup()公共方法更快,我想利用它。如果我要MethodHandles.publicLookup().unreflect(Method)在一个Method本来就不是公开的但我已经调用过的对象setAccessible(true)上使用,它会起作用吗?
我正在努力解决一个简单、基本的 Java 语言问题,但这个问题没有意义。我正在将 an 传递Object[]给需要 varargs 的方法Object...,但该方法似乎将请求解释为new Object[]{Object[]}. 也就是说,它似乎不是将 theObject[]视为等效于Object...,而是将 theObject[]作为可变参数的第一个元素传递,从而将 the 包装Object[]在另一个对象数组中。
我在 Java 17 中有以下内容:
\nFooImpl foo = goGetFooImpl();\nList<?> methodArgs = List.of(); //no method args\nObject[] invokeArgs = Stream.concat(Stream.of(foo, methodArgs.stream()).toArray();\n// this gives me the equivalent of `new Object[]{foo}`\n// logging `List.of(invokeArgs)` shows `[com.example.FooImpl@\xe2\x80\xa6]`\nMethodHandle barMethodHandle = goLookUpMethodHandle(foo, "bar");\nmethodHandle.invoke(invokeArgs); //expects varargs `foo, arg1, arg2, \xe2\x80\xa6`\nRun Code Online (Sandbox Code Playgroud)\n我得到:
\n\n\n …
java.lang.ClassCastException: Cannot cast [Ljava.lang.Object; to com.example.FooImpl
我正在使用 JDK 15。(我正在使用 ByteBuddy 1.10.16 生成一些类,但我认为,除了作为背景信息之外,它在这里几乎不相关。)
在这些生成的类之一中,我调用invokeExact()了一个我设法存储在生成的类中的MethodHandle 常量。它是通过 获得的“场地设置者” MethodHandles.Lookup#findSetter。
(下面我知道这个MethodHandles.privateLookupIn()方法。)
我注意到,MethodHandle所讨论的“字段设置器”在代表字段时会失败private。在大多数级别上,这并不令我感到惊讶:直接MethodHandle是,嗯,直接:虽然我并不假装对所有这些东西的内部结构了解很多,但在我看来,它肯定只是包装了一些没有的低级字节码访问检查。
但考虑到它的存在privateLookupIn()表明在某些情况下绕过访问检查是可能的,是否有一条路径可以让我MethodHandle从 A 类中“收获”一个可以读取private字段的“字段设置器”,然后将其作为常量存储在另一个字段中B类这样就invokeExact()一定会成功吗?
我相信我过去做过类似的事情(必须检查)涉及private方法,但在这些情况下我没有使用常量MethodHandle ,即我在使用结果并将结果存储在字段MethodHandle期间获取类初始化时间,然后调用该字段的内容。如果我必须继续走这条路,我会的,但常数在这里似乎很有吸引力,如果可以的话,使用它们会很好。<clinit>privateLookupIn()MethodHandleprivate static finalinvokeExact()MethodHandle
因此,我的问题的另一种表达方式是:表示 a 的常量形式MethodHandle是否能够存储其特权?或者是否有某种一次性方法可以“提高”作为MethodHandle常量存储的特权?或者,给定值存储为常量这一事实是否MethodHandle会阻止它始终访问除常规可访问的 Java 构造之外的任何内容? 我在相关部分的 JVM 规范中没有看到任何非常明显的内容。
java ×10
methodhandle ×10
java-8 ×4
jvm ×2
lambda ×2
reflection ×2
annotations ×1
arrays ×1
byte-buddy ×1
duck-typing ×1
invoke ×1
java-11 ×1
java-7 ×1