简体   繁体   English

使用 javassist 匿名内部 class 时如何访问外部 class 的实例变量?

[英]When using javassist anonymous inner class how to access instance variables of outer class?

Below is the anonymous inner class definition:下面是匿名内部 class 定义:

package com.demo;

public class OuterClass {

    private static int staticNum = 1;

    private int instanceNum  = 2;

    public Runnable redefineMe() {
        return new Runnable() {
            @Override
            public void run() {
                System.out.printf("staticNum %d, instanceNum %d \n", staticNum, instanceNum);
            }
        };
    }
}

Below is the running example:下面是运行示例:

package com.demo;

import javassist.*;

public class Test {
    public static void main(String[] args) throws NotFoundException, CannotCompileException {
        ClassPool pool = ClassPool.getDefault();
        CtClass outerClass = pool.get("com.demo.OuterClass");
        CtClass[] nestedClasses = outerClass.getNestedClasses();
        CtMethod run = nestedClasses[0].getDeclaredMethod("run");

        run.setBody("{" +
                "System.out.println(\"staticNum: \" + com.demo.OuterClass.staticNum);" +  // print: staticNum: 1
                // I tried to use the following code to access instance variables, but a compilation error occurred
                // "System.out.println(\"staticNum: \" + instanceNum);" +  // [source error] no such field: instanceNum
                // "System.out.println(\"staticNum: \" + com.demo.OuterClass.this.instanceNum);" +  // [source error] missing member name
                // "System.out.println(\"staticNum: \" + com.demo.OuterClass.access$100(com.demo.OuterClass.this));" +  // [source error] missing member name
                "}");
        nestedClasses[0].toClass();
        outerClass.toClass();
        new OuterClass().redefineMe().run();
    }
}

I want to redefine the body of the run method, but I cannot access the instance variables of the outer class in the body我想重新定义run方法的主体,但是无法访问主体中外层class的实例变量

According to the manual , Javassist does not support inner class generation, but claims to support to read and modify them:根据手册,Javassist 不支持内部 class 生成,但声称支持读取和修改它们:

  • Inner classes or anonymous classes are not supported.不支持内部类或匿名类。 Note that this is a limitation of the compiler only.请注意,这只是编译器的限制。 It cannot compile source code including an anonymous-class declaration.它不能编译包含匿名类声明的源代码。 Javassist can read and modify a class file of inner/anonymous class. Javassist 可以读取和修改内部/匿名 class 的 class 文件。

I guess the compiler support ends where you want to do use inner-class-specific syntactic sugar in source code compiled by Javassist, though.不过,我猜编译器支持会在您想要在 Javassist 编译的源代码中使用特定于内部类的语法糖的地方结束。 A simple workaround would be to use "sacred knowledge" as follows:一个简单的解决方法是使用“神圣知识”,如下所示:

$ javap classes/com/demo/OuterClass\$1.class
Compiled from "OuterClass.java"
class com.demo.OuterClass$1 implements java.lang.Runnable {
  final com.demo.OuterClass this$0;
  com.demo.OuterClass$1(com.demo.OuterClass);
  public void run();
}

Oh look, this$0 : Let us try that:哦,看, this$0 :让我们尝试一下:

run.setBody("{" +
  "System.out.println(\"staticNum: \" + com.demo.OuterClass.staticNum);" +
  "System.out.println(\"instanceNum: \" + this$0.instanceNum);" +
  "}");

Now we get the console output:现在我们得到控制台 output:

staticNum: 1
instanceNum: 2

I do not know, how stable and reliable this workaround is across Java releases and compiler flavours.我不知道,这种解决方法在 Java 版本和编译器风格中的稳定性和可靠性如何。

PS: If you change the anonymous inner class to a lambda , the class file looks completely different and you are lost again. PS:如果您将匿名内部 class 更改为lambda ,则 class 文件看起来完全不同,您又迷路了。 I found nothing in the Javassist repository even mentioning lambdas, only a few open issues reporting problems.我在 Javassist 存储库中没有发现任何关于 lambda 的内容,只有一些未解决的问题报告了问题。


Update: I created Javassist issue #358 in order to track this.更新:我创建了Javassist 问题 #358来跟踪它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM