Javassist添加方法并调用

Kor*_*kig 7 java javassist

我坚持使用javassist.我在运行时向对象类添加了一个新方法.

我的对象类:

package tmp3;

public class Car {
    public Car(){}
}
Run Code Online (Sandbox Code Playgroud)

我的考试班:

package tmp3;

import java.lang.reflect.Method;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

public class TestMain {
    public static void main(String[] args) {
        try {

            CtClass ctclass = ClassPool.getDefault().get("tmp3.Car");
            CtMethod newmethod = CtNewMethod.make("public void testPrint() { System.out.println(\"test ok\"); }",ctclass);
            ctclass.addMethod(newmethod);
            ctclass.writeFile();

            for(Method me: ctclass.toClass().getDeclaredMethods()){ //test print, ok
                System.out.println(me.getName());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

但在那之后,我不知道如何调用(调用)它.我已经读过javassist没有能力调用方法.那我怎么能调用我刚刚用javassist添加的方法呢?

我在两天内尝试过很多东西但没有成功.你能帮帮我吗?

pab*_*tes 9

Java类具有静态接口,这意味着,正如您可能已经知道的那样,Java在默认情况下并未设计为在运行时向类添加方法,因此它有点棘手,但并不难以实现您想要的.

您已经使用Javassist(字节码修饰符框架)来设计编译的类以添加更多代表新方法的字节码.您可以拥有以下两种方案之一:

场景1:在注入之前与您的Car类一起编译的代码

在这种情况下,在编译代码时,Java编译器只知道Car接口而不进行任何注入.所以你不能直接调用注入的方法,如下所示:

 Car car = new Car();
 car.testPrint();
Run Code Online (Sandbox Code Playgroud)

你必须像@Scorpion这样的反思正确评论:

 Car car = new Car();
 Method method = car.getClass().getMethod("testPrint", new Class[]{});
 method.invoke(car,new Object[]{});
Run Code Online (Sandbox Code Playgroud)

但这不是唯一的方法......

场景2:使用编译和注入的类的代码

如果你编译你的Car类,注入它,然后针对编译的类编写代码(例如Car在jar文件中有类),你将能够调用你的注入方法,就像它是任何其他常规方法一样.

做以下练习:

  1. 编译你的Car课程
  2. 运行你的TestMain,它将进行注射
  3. 在IDE中创建另一个项目并向该项目的类路径添加带有注入类的目录创建一个仅包含注入类的jar并将该jar添加到类路径
  4. 在新项目中创建一个创建新Car实例的类,注意您现在可以毫无困难地调用testPrint方法.

你应该注意的一些事情:

  • 如果您使用注入的类覆盖原始类,则最终可能会出现一个无效的类,从而导致出现一条java.lang.ClassFormatError错误消息,指出您有一个Truncated Class文件.如果Javassist没有将所有字节码加载到内存并尝试对同一类文件进行写入和读取,则会发生这种情况,这会导致完全混乱.为避免这种情况,您可以写入其他路径,也可以确保在写入文件之前将所有字节码加载到内存中(使用toByteCode()from CtClass).
  • 如果您有两个类文件,一个包含注入的代码,另一个包含原始代码,请记住在类路径中只有一个.