7

我被javassist困住了。我在运行时向我的对象类添加了一个新方法。

我的对象类:

package tmp3;

public class Car {
    public Car(){}
}

我的测试课:

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();
        }

    }
}

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

我在两天内尝试了很多东西,但没有成功。你能帮我解决这个问题吗?

4

2 回答 2

9

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

您使用了字节码修饰符框架 Javassist 来设计编译的类以添加更多表示新方法的字节码。您可以有以下两种情况之一:

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

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

 Car car = new Car();
 car.testPrint();

你必须通过像@Scorpion 正确评论的反思来做到这一点:

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

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

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

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

做以下练习:

  1. 编译你的Car
  2. 运行您的 TestMain 它将进行注入
  3. 在您的 IDE 中创建另一个项目并将注入类的目录添加到该项目的类路径中,或者创建一个仅包含注入类的 jar 并将该 jar 添加到类路径中
  4. 在新项目中创建一个创建新Car实例的类,注意您现在可以轻松调用 testPrint 方法。

您应该注意的几件事:

  • 如果你用注入的类覆盖你的原始类,你最终可能会得到一个无效的类,从而导致java.lang.ClassFormatError一条错误消息表明你有一个截断的类文件。如果 Javassist 没有将所有字节码加载到内存并尝试在同一个类文件中写入和读取,则会发生这种情况,这会导致完全混乱。为避免这种情况,您可以写入不同的路径或确保在写入文件之前将所有字节码加载到内存(使用toByteCode()from CtClass)。
  • 如果您有两个类文件,一个带有注入代码,一个带有原始代码,请记住在您的 classpath 中只有一个
于 2012-12-10T09:51:55.953 回答
0

使用java反射来调用它,javassist用于类修改和加载......然后使用java反射来运行它(调用......)。

于 2015-08-10T21:53:08.127 回答