我坚持使用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添加的方法?
我在两天内尝试过很多东西但没有成功。你能帮帮我吗?
答案 0 :(得分:9)
Java类具有静态接口,这意味着,正如您可能已经知道的那样,Java在默认情况下并未设计为在运行时向类添加方法,因此它有点棘手,但并不难以实现您想要的。
您已经使用Javassist(字节码修饰符框架)来设计编译的类以添加更多代表新方法的字节码。您可以使用以下两种方案之一:
在这种情况下,在编译代码时,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[]{});
但这不是唯一的方法......
如果您编译了Car
类,请将其注入,然后 编写针对已编译类的代码(例如,在jar文件中具有Car
类)能够将您注入的方法称为任何其他常规方法。
进行以下练习:
Car
班级Car
实例的类,请注意您现在可以毫无困难地调用testPrint方法。你应该注意的一些事情:
java.lang.ClassFormatError
,并显示一条错误消息,指出您有一个Truncated Class文件。如果Javassist没有将所有字节码加载到内存并尝试对同一类文件进行写入和读取,则会发生这种情况,这会导致完全混乱。为避免这种情况,您可以写入其他路径,也可以确保在写入文件之前将所有字节码加载到内存中(使用toByteCode()
中的CtClass
)。答案 1 :(得分:0)
使用java反射来调用它,使用javassist进行类修改和加载...然后使用java反射来运行它(调用...)。