gpt4 book ai didi

java - 在 Java 8 中转换 lambda

转载 作者:搜寻专家 更新时间:2023-10-30 19:42:11 26 4
gpt4 key购买 nike

Java 8 似乎可以生成表示 lambda 表达式的类。例如代码:

  Runnable r = app::doStuff;

大致表现为:

  // $FF: synthetic class
final class App$$Lambda$1 implements Runnable {
private final App arg$1;

private App$$Lambda$1(App var1) {
this.arg$1 = var1;
}

private static Runnable get$Lambda(App var0) {
return new App$$Lambda$1(var0);
}

public void run() {
this.arg$1.doStuff();
}
}

据我了解,代码是在运行时生成的。现在,假设有人想将代码注入(inject)到上述类的 run 方法中。迄今为止的实验产生了 NoClassDefFoundVerifyError 的混合:

java.lang.NoClassDefFoundError: App$$Lambda$2
at App$$Lambda$2/1329552164.run(Unknown Source)
at App.main(App.java:9)
Caused by: java.lang.ClassNotFoundException: App$$Lambda$2
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 2 more

这是针对:

$ java -version
java version "1.8.0_51"
Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)

这甚至是在将任何新的字节码推送到类中之前。

这是预期的吗?闻起来像 JDK 错误,但我很高兴自己错了!

这是一个 Github repo illustrating the behavior

最佳答案

对我来说,这似乎是 JVM 中的一个错误。系统类加载器尝试通过名称定位转换后的类。但是,lambda 表达式是通过匿名类加载来加载的,其中满足以下条件:

clazz.getClassLoader()
.loadClass(clazz.getName().substring(0, clazz.getName().indexOf('/')))

产生 ClassNotFoundException,导致 NoClassDefError。该类不被视为真正的类,例如,此类匿名类不会传递给重新转换之外的 ClassFileTransformer

总而言之,在处理匿名类时,我觉得检测 API 有点问题。类似地,LambdaForm传递给ClassFileTransformer,但是除了 classFileBuffer 之外的所有参数都设置为 null 是什么破坏了转换器类的契约。

对于您的示例,问题似乎是您返回了null;当返回 classFileBuffer 什么是空操作时,问题就消失了。然而,这不是 ClassFileTransformer 所建议的,返回 null 是推荐的做法:

a well-formed class file buffer (the result of the transform), or null if no transform is performed.

对我来说,这似乎是 HotSpot 中的一个错误。您应该向 OpenJDK 报告此问题。

总而言之,正如我在我的代码操作库中演示的那样,完全有可能检测匿名加载的类 Byte Buddy .与正常检测 相比,它需要一些不幸的调整,但运行时支持它。以下是在库中作为单元测试成功运行的示例:

Callable<String> lambda = () -> "foo";

Instrumentation instrumentation = ByteBuddyAgent.install();
ClassReloadingStrategy classReloadingStrategy = ClassReloadingStrategy.of(instrumentation)
.preregistered(lambda.getClass());
ClassFileLocator classFileLocator = ClassFileLocator.AgentBased.of(instrumentation,
lambda.getClass());

assertThat(lambda.call(), is("foo"));

new ByteBuddy()
.redefine(lambda.getClass(), classFileLocator)
.method(named("call"))
.intercept(FixedValue.value("bar"))
.make()
.load(lambda.getClass().getClassLoader(), classReloadingStrategy);

assertThat(lambda.call(), is("bar"));

关于java - 在 Java 8 中转换 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34162074/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com