VarHandle显示以下错误 -
Exception in thread "main" java.lang.NoSuchMethodError: VarHandle.compareAndSet(VarHandleExample,int,int)void
at java.base/java.lang.invoke.MethodHandleNatives.newNoSuchMethodErrorOnVarHandle(MethodHandleNatives.java:492)
at java.base/java.lang.invoke.MethodHandleNatives.varHandleOperationLinkerMethod(MethodHandleNatives.java:445)
at java.base/java.lang.invoke.MethodHandleNatives.linkMethodImpl(MethodHandleNatives.java:378)
at java.base/java.lang.invoke.MethodHandleNatives.linkMethod(MethodHandleNatives.java:366)
at j9.VarHandleExample.update(VarHandleExample.java:23)
at j9.VarHandleExample.main(VarHandleExample.java:14)
Run Code Online (Sandbox Code Playgroud)
我的计划是:
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class VarHandleExample {
public int publicTestVariable = 10;
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
VarHandleExample e= new VarHandleExample();
e.update();
}
public void update() throws NoSuchFieldException, IllegalAccessException {
VarHandle publicIntHandle = MethodHandles.lookup()
.in(VariableHandlesTest.class)
.findVarHandle(VarHandleExample.class, "publicTestVariable", int.class);
publicIntHandle.compareAndSet(this, 10, 100); // CAS
}
}
Run Code Online (Sandbox Code Playgroud) Java的MethodHandle.invokeExact(Object ... args)采用可变长度的参数列表.但是,当我尝试传递Object []而不是列表数组时,我收到错误.见下文:
private void doIt() throws Throwable {
Method meth = Foo.class.getDeclaredMethods()[0];
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(meth);
Foo foo = new Foo();
String myStr = "aaa";
Integer myInt = new Integer(10);
Object [] myArray = {foo, myStr, myInt};
mh.invokeExact(foo, myStr, myInt); // prints "Called aaa 10"
mh.invokeExact(myArray); // throws Exception
}
class Foo {
public void bar(String myStr, Integer myInt) {
System.out.println("Called " + myStr + " " + myInt);
}
}
Run Code Online (Sandbox Code Playgroud)
第二次调用invokeExact()会产生以下异常:
Exception in …Run Code Online (Sandbox Code Playgroud) Java 8引入了lambda表达式,这是一件好事.但现在考虑重写这段代码:
class B implements PropertyChangeListener {
void listenToA(A a) {
a.addPropertyChangeListener(this);
}
void propertyChange(PropertyChangeEvent evt) {
switch(evt.getPropertyName()) {
case "Property1":
doSomething();
break;
case "Property2":
doSomethingElse(); case "Property1":
doSomething;
break;
break;
}
void doSomething() { }
void doSomethingElse() { }
}
class A {
final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
}
Run Code Online (Sandbox Code Playgroud)
随着lambda表达式和方法的引用,它已不再是需要有B落实PropertyChangeListner,我们可以写
class B {
void listenToA(A a) {
// using method …Run Code Online (Sandbox Code Playgroud)
我试图让Java 8 Nashorn拥有完整的源代码(未经过检测).您可能知道,它使用Nasgen修改.classes,并输出输出JRE/lib/ext/nashorn.jar.
在拆卸输出时,使用javap:
0: aload_0
1: ldc #24 // String Function
3: ldc #31 // MethodHandle invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
5: getstatic #22 // Field $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap;
8: aconst_null
9: invokespecial #34 // Method jdk/nashorn/internal/objects/ScriptFunctionImpl."<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V
Run Code Online (Sandbox Code Playgroud)
可能被错误地写为
super("Function", NativeFunction.function, $nasgenmap$, (Specialization[]) null);
Run Code Online (Sandbox Code Playgroud)
,应该使用签名调用超级构造函数:
ScriptFunctionImpl(String, MethodHandle, PropertyMap, Specialization[]) { }
Run Code Online (Sandbox Code Playgroud)
我的问题是第二个参数NativeFunction.function,我没有可编译的源,MethodHandle在常量池中生成相同的,
#31 = MethodHandle #6:#30 // invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;
Run Code Online (Sandbox Code Playgroud)
仪表的这一部分是由ASM通过调用MethodVisitor.visitLdcInsn完成的.
那么,有没有办法从Java源构建这样的方法句柄,或者这是一个只能在字节码级别完成的功能?
完整的javap输出:
$javap -c -v NativeFunction$Constructor.class
Last modified …Run Code Online (Sandbox Code Playgroud) 我如何得到MethodHandle像数组构造函数int[]::new?
这不起作用:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class, int.class));
System.out.println(mh);
System.out.println(mh.invoke());
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
Exception in thread "main" java.lang.NoSuchMethodException: no such constructor: [I.<init>(int)void/newInvokeSpecial
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1382)
at java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:920)
at xx.main(xx.java:11)
Caused by: java.lang.NoSuchMethodError: java.lang.Object.<init>(I)V
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987)
... 3 more
Run Code Online (Sandbox Code Playgroud)
这也不是:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class));
System.out.println(mh); …Run Code Online (Sandbox Code Playgroud) 我试图使用Java的LambdaMetaFactory动态实现一个通用的拉姆达Handler<RoutingContext>:
public class RoutingContext {
// ...
}
@FunctionalInterface
public interface Handler<X> {
public void handle(X arg);
}
public class HomeHandler extends Handler<RoutingContext> {
@Override
public void handle(RoutingContext ctx) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的尝试LambdaMetaFactory:
try {
Class<?> homeHandlerClass = HomeHandler.class;
Method method = homeHandlerClass.getDeclaredMethod(
"handle", RoutingContext.class);
Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(method);
MethodType factoryMethodType = MethodType.methodType(Handler.class);
MethodType functionMethodType = mh.type();
MethodHandle implementationMethodHandle = mh;
Handler<RoutingContext> lambda =
(Handler<RoutingContext>) LambdaMetafactory.metafactory(
lookup,
"handle", …Run Code Online (Sandbox Code Playgroud) 上下文:我一直在对使用invokedynamic和手动生成字节码之间的差异进行基准测试(这是在决定面向 JVM 的编译器是应该发出更冗长的“传统”字节码还是只是invokedynamic使用巧妙的引导方法调用)的上下文中。在这样做时,将字节码映射到MethodHandles至少同样快的组合器是非常简单的,除了tableswitch.
问题:是否有模仿tableswitch使用的技巧MethodHandle?我试着用一个跳转表来模仿它:使用一个常量MethodHandle[],用 索引到它arrayElementGetter,然后用 调用找到的句柄MethodHandles.invoker。然而,当我通过 JMH 运行它时,它最终比原始字节码慢了大约 50%。
下面是生成方法句柄的代码:
private static MethodHandle makeProductElement(Class<?> receiverClass, List<MethodHandle> getters) {
MethodHandle[] boxedGetters = getters
.stream()
.map(getter -> getter.asType(getter.type().changeReturnType(java.lang.Object.class)))
.toArray(MethodHandle[]::new);
MethodHandle getGetter = MethodHandles // (I)H
.arrayElementGetter(MethodHandle[].class)
.bindTo(boxedGetters);
MethodHandle invokeGetter = MethodHandles.permuteArguments( // (RH)O
MethodHandles.invoker(MethodType.methodType(java.lang.Object.class, receiverClass)),
MethodType.methodType(java.lang.Object.class, receiverClass, MethodHandle.class),
1,
0
);
return MethodHandles.filterArguments(invokeGetter, 1, getGetter);
}
Run Code Online (Sandbox Code Playgroud)
这是初始字节码(我试图用一个invokedynamic调用替换它)
public java.lang.Object productElement(int); …Run Code Online (Sandbox Code Playgroud) 鉴于:
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.function.Function;
class Testcase
{
@FunctionalInterface
public interface MyBuilder1<R>
{
R apply(String message);
}
@FunctionalInterface
public interface MyBuilder2<R>
{
R apply(Object message);
}
public static void main(String[] args) throws Throwable
{
Class<?> clazz = IllegalArgumentException.class;
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findConstructor(clazz, MethodType.methodType(void.class, String.class));
MethodHandle myFunctionConstructor = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(Function.class),
mh.type().erase(),
mh,
mh.type()
).getTarget();
MethodHandle myBuilderConstructor1 = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(MyBuilder1.class),
mh.type().erase(),
mh,
mh.type()
).getTarget();
MethodHandle myBuilderConstructor2 = LambdaMetafactory.metafactory( …Run Code Online (Sandbox Code Playgroud) 假设我有MyPerson一个带有namegetter 和 setter 的简单 javabean:
public class MyPerson {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我正在运行这个主要代码,它只是获取和设置该name字段:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle getterMethodHandle = lookup.findGetter(MyPerson.class, "name", String.class);
MethodHandle setterMethodHandle = lookup.findSetter(MyPerson.class, "name", String.class);
MyPerson a = new MyPerson();
a.setName("Batman");
System.out.println("Name from getterMethodHandle: " + getterMethodHandle.invoke(a));
setterMethodHandle.invoke(a, "Robin");
System.out.println("Name after setterMethodHandle: " + a.getName()); …Run Code Online (Sandbox Code Playgroud) 我正在尝试用MethodHandle代替反射调用,但是varargs似乎无法处理。
我的反射调用程序当前如下所示:
public class Invoker {
private final Method delegate;
public Invoker(Method delegate) {
this.delegate = delegate;
}
public Object execute(Object target, Object[] args) {
return delegate.invoke(target, args);
}
}
Run Code Online (Sandbox Code Playgroud)
我当前的重写尝试如下所示(Invoker暴露的接口必须保持不变):
public class Invoker {
private final Method delegate;
private final MethodHandle handle;
public Invoker(Method delegate) {
this.delegate = delegate;
this.handle = MethodHandles.lookup().unreflect(delegate);
}
public Object execute(Object target, Object[] args) throws InvocationTargetException, IllegalAccessException {
Object[] allArgs = Stream.concat(Stream.of(target), Stream.of(args)).toArray(Object[]::new);
return handle.invokeWithArguments(allArgs);
}
}
Run Code Online (Sandbox Code Playgroud)
这在大多数情况下都可以正常工作。但是varargs破坏了一切。例如,具有以下方法:
public String test(int i, …Run Code Online (Sandbox Code Playgroud) methodhandle ×10
java ×9
reflection ×3
bytecode ×2
java-9 ×2
lambda ×2
decompiling ×1
eclipse ×1
java-7 ×1
java-8 ×1
jvm ×1
listener ×1
nashorn ×1