如何在java中重新定义lambda匿名类

如何在java中重新定义lambda匿名类,java,lambda,java-8,javaagents,Java,Lambda,Java 8,Javaagents,JDK8将lambda表达式转换为中的匿名类 InnerClassLambdaMetafactory.spinInnerClass() { return UNSAFE.defineAnonymousClass(targetClass, classBytes, null); } 我正在编写一个javaagent,使用asm修改classBytes(添加一个方法)并将其传递给defineAnonymousClass,但该方法最终得到了这个匿名类的ClassNotFoundException

JDK8将lambda表达式转换为中的匿名类

InnerClassLambdaMetafactory.spinInnerClass() {
    return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
}

我正在编写一个javaagent,使用asm修改
classBytes
(添加一个方法)并将其传递给
defineAnonymousClass
,但该方法最终得到了这个匿名类的ClassNotFoundException。有什么方法可以修改匿名类字节的内容吗?

转换匿名加载的类很棘手。是否重新格式化表示此类类的已加载类?如果是这样,请注意
Class::getName
不会返回类的实际二进制名称,而是添加一个随机散列,例如
my.DefinedType/12345
,您需要在其中去除最新的数字

此外,您不能直接从另一个类引用此类类,但需要直接从反射API或理想情况下的方法句柄引用它们。您无法从类加载器中查找此类类,这就是它们被称为匿名类的原因

最后,在安装类文件转换器时,此类匿名类的加载不会在转换器中注册。处理此类类的最简单方法是修补负责创建lambda类型的lambda元工厂。例如,您可以使用以下工具轻松创建代理:

new AgentBuilder.Default()
  .with(LambdaTransformationStrategy.ENABLED)
  .type(someMatcher)
  .transform(someTransformer)
  .installOn(instrumentation);

在封面下调用此函数,Byte Buddy将重写JVM的默认lambda元工厂类,并在可能进行此类插装的情况下使用其自己的代码生成来替换它。

其他类可以直接引用匿名类,如果它们也是匿名类并且具有修补的常量池(这是
defineAnonymousClass
的第三个参数)。在这种情况下,他们使用的名称也无关紧要。这是事实。但这不适用于描述lambda表达式的类。谢谢你的回答,我不是在尝试重新定义已加载的类,而是在创建匿名类之前修改其字节。仍然不知道它为什么不起作用。关于通过
targetClass.getClassLoader.defineClass(modifyedAnonymousClassBytes)定义匿名类
?有任何副作用吗?@nzomkxia:当您试图在加载时更改类的字节码时,您必须在
ClassFileTransformer
的实现中进行更改。在这种情况下,您应该既不调用
defineClass
也不调用
defineAnonymousClass
,只需返回修改后的字节码即可。将字节码传递给targetClass的
defineClass
方法
ClassLoader
很少起作用。首先,匿名类可以访问目标类的
private
方法,这对于普通类是不允许的,其次,
targetClass
可能是一个引导类,具有
null
类装入器.