您的位置:首页 > 编程语言 > Java开发

javassist学习三

2015-07-16 14:20 549 查看
这里举个简单的例子,来记录下如何用CtClass创建一个类,并且往这个类里面新加方法,

下面是代码,可以直接运行:

Java代码


package seeeyou.app.test;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import javassist.CannotCompileException;

import javassist.ClassPool;

import javassist.CtClass;

import javassist.CtMethod;

import javassist.CtNewMethod;

import javassist.NotFoundException;

/**

*

* @author seeeyou

*

*/

public class TestHelloWorld2 {

public static void main(String[] args) throws NotFoundException,

IOException, CannotCompileException, InstantiationException,

IllegalAccessException, SecurityException, NoSuchMethodException,

IllegalArgumentException, InvocationTargetException {

// 用于取得字节码类,必须在当前的classpath中,使用全称

ClassPool pool = ClassPool.getDefault();

/**

* makeClass() cannot create a new interface; makeInterface() in

* ClassPool can do. Member methods in an interface can be created with

* abstractMethod() in CtNewMethod. Note that an interface method is an

* abstract method.

*/

CtClass ccClass = pool.makeClass("Point");

String bodyString = "{System.out.println(\"Call to method \");}";

//为新创建的类新加一个方法execute,无任何参数

CtMethod n1 = CtNewMethod.make(CtClass.voidType, "execute", null, null,

bodyString, ccClass);

ccClass.addMethod(n1);

/**

* 这里无法用new的形式来创建一个对象,因为已经classloader中不能有两个相同的对象,否则会报异常如下:

*Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader):

*attempted duplicate class definition for name: "Point"

**/

Object oo = ccClass.toClass().newInstance();

Method mms = oo.getClass().getMethod("execute", null);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, null));

System.out.println("---------------------------------------------");

//这一行代码将class冻结了,下面无法再对类多编辑或者修改,下面的setName会报异常如:

//Exception in thread "main" java.lang.RuntimeException: Point class is frozen

ccClass.freeze();

try{

ccClass.setName("Point2");

}catch (Exception e) {

System.out.println(e);

}

//对已经冻结的class解冻之后还可以继续编辑修改

ccClass.defrost();

<span style="color: #ff0000;"> System.out.println("------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------");</span>

//第二个方法

bodyString = "public int getNumber(Integer num){System.out.println(\"Point2 Call to method \");return 10+num;}";

CtMethod n2 = CtNewMethod.make(bodyString, ccClass);//直接创建一个方法,带有一个int的参数和返回值

ccClass.addMethod(n2);

Class[] params = new Class[1];

Integer num = new Integer(15);

params[0] = num.getClass();

mms = oo.getClass().getMethod("getNumber", params);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, 100));

System.out.println("---------------------------------------------");

}

}

Java代码


上面的结果是:new class name is : Point

Call to method

new class's method is : null

---------------------------------------------

java.lang.RuntimeException: Point class is frozen

---------------------------------------------

Exception in thread "main" java.lang.NoSuchMethodException: Point.getNumber(java.lang.Integer)

at java.lang.Class.getMethod(Class.java:1605)

at seeeyou.app.test.TestHelloWorld2.main(TestHelloWorld2.java:66)

错误的原因其实和简单,因为我第二次新加一个方法后,没有再次实例化一个对象,所以oo还是原来的对象,他的成员函数肯定没有新加的方法。

那我可以再次实例化下试试,代码和结果如下:

Java代码


package seeeyou.app.test;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import javassist.CannotCompileException;

import javassist.ClassPool;

import javassist.CtClass;

import javassist.CtMethod;

import javassist.CtNewMethod;

import javassist.NotFoundException;

/**

*

* @author seeeyou

*

*/

public class TestHelloWorld2 {

public static void main(String[] args) throws NotFoundException,

IOException, CannotCompileException, InstantiationException,

IllegalAccessException, SecurityException, NoSuchMethodException,

IllegalArgumentException, InvocationTargetException {

// 用于取得字节码类,必须在当前的classpath中,使用全称

ClassPool pool = ClassPool.getDefault();

/**

* makeClass() cannot create a new interface; makeInterface() in

* ClassPool can do. Member methods in an interface can be created with

* abstractMethod() in CtNewMethod. Note that an interface method is an

* abstract method.

*/

CtClass ccClass = pool.makeClass("Point");

String bodyString = "{System.out.println(\"Call to method \");}";

//为新创建的类新加一个方法execute,无任何参数

CtMethod n1 = CtNewMethod.make(CtClass.voidType, "execute", null, null,

bodyString, ccClass);

ccClass.addMethod(n1);

/**

* 这里无法用new的形式来创建一个对象,因为已经classloader中不能有两个相同的对象,否则会报异常如下:

*Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader):

*attempted duplicate class definition for name: "Point"

**/

Object oo = ccClass.toClass().newInstance();

Method mms = oo.getClass().getMethod("execute", null);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, null));

System.out.println("---------------------------------------------");

//这一行代码将class冻结了,下面无法再对类多编辑或者修改,下面的setName会报异常如:

//Exception in thread "main" java.lang.RuntimeException: Point class is frozen

ccClass.freeze();

try{

ccClass.setName("Point2");

}catch (Exception e) {

System.out.println(e);

}

//对已经冻结的class解冻之后还可以继续编辑修改

ccClass.defrost();

System.out.println("------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------");

//第二个方法

bodyString = "public int getNumber(Integer num){System.out.println(\"Point2 Call to method \");return 10+num;}";

CtMethod n2 = CtNewMethod.make(bodyString, ccClass);//直接创建一个方法,带有一个int的参数和返回值

ccClass.addMethod(n2);

Class[] params = new Class[1];

Integer num = new Integer(15);

params[0] = num.getClass();//就多了下面这个实例化,但是这样会导致一个错误

oo = ccClass.toClass().newInstance();

mms = oo.getClass().getMethod("getNumber", params);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, 100));

System.out.println("---------------------------------------------");

}

}

Java代码


这也会导致一个错误:new class name is : Point

Call to method

new class's method is : null

---------------------------------------------

java.lang.RuntimeException: Point class is frozen

------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------

Exception in thread "main" javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "Point"

at javassist.ClassPool.toClass(ClassPool.java:1051)

at javassist.ClassPool.toClass(ClassPool.java:994)

at javassist.ClassPool.toClass(ClassPool.java:952)

at javassist.CtClass.toClass(CtClass.java:1079)

at seeeyou.app.test.TestHelloWorld2.main(TestHelloWorld2.java:66)

Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "Point"

at java.lang.ClassLoader.defineClass1(Native Method)

at java.lang.ClassLoader.defineClass(ClassLoader.java:621)

at java.lang.ClassLoader.defineClass(ClassLoader.java:466)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at javassist.ClassPool.toClass2(ClassPool.java:1063)

at javassist.ClassPool.toClass(ClassPool.java:1045)

... 4 more

Java代码


原因也很简单,一个classloader里面怎么有两个重复的对象呢,除非是两个不同的classloader。。所以爆了个重复加载类的错误

Java代码


对的方式是只实例化一次:如下:

Java代码


package seeeyou.app.test;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import javassist.CannotCompileException;

import javassist.ClassPool;

import javassist.CtClass;

import javassist.CtMethod;

import javassist.CtNewMethod;

import javassist.NotFoundException;

/**

*

* @author seeeyou

*

*/

public class TestHelloWorld3 {

public static void main(String[] args) throws NotFoundException,

IOException, CannotCompileException, InstantiationException,

IllegalAccessException, SecurityException, NoSuchMethodException,

IllegalArgumentException, InvocationTargetException {

// 用于取得字节码类,必须在当前的classpath中,使用全称

ClassPool pool = ClassPool.getDefault();

/**

* makeClass() cannot create a new interface; makeInterface() in

* ClassPool can do. Member methods in an interface can be created with

* abstractMethod() in CtNewMethod. Note that an interface method is an

* abstract method.

*/

CtClass ccClass = pool.makeClass("Point");

String bodyString = "{System.out.println(\"Call to method \");}";

//为新创建的类新加一个方法execute,无任何参数

CtMethod n1 = CtNewMethod.make(CtClass.voidType, "execute", null, null,

bodyString, ccClass);

ccClass.addMethod(n1);

//新加第二个方法

bodyString = "public Integer getNumber(Integer num);";

CtMethod n2 = CtNewMethod.make(bodyString, ccClass);//直接创建一个方法,带有一个int的参数和返回值

n2.setBody("{System.out.println(\"Point Call to method \");return $1;}");

ccClass.addMethod(n2);

/**

* 这里无法用new的形式来创建一个对象,因为已经classloader中不能有两个相同的对象,否则会报异常如下:

*Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader):

*attempted duplicate class definition for name: "Point"

**/

Object oo = ccClass.toClass().newInstance();

Method mms = oo.getClass().getMethod("execute", null);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, null));

System.out.println("---------------------------------------------");

//这一行代码将class冻结了,下面无法再对类多编辑或者修改,下面的setName会报异常如:

//Exception in thread "main" java.lang.RuntimeException: Point class is frozen

ccClass.freeze();

try{

ccClass.setName("Point2");

}catch (Exception e) {

System.out.println(e);

}

//对已经冻结的class解冻之后还可以继续编辑修改

ccClass.defrost();

System.out.println("------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------");

Class[] params = new Class[1];

Integer num = new Integer(0);

params[0] = num.getClass();

mms = oo.getClass().getMethod("getNumber",params);

System.out.println("new class name is : " + oo.getClass().getName());

System.out.println("new class's method is : " + mms.invoke(oo, 100));

System.out.println("---------------------------------------------");

}

}

Java代码


结果如下:new class name is : Point

Call to method

new class's method is : null

---------------------------------------------

java.lang.RuntimeException: Point class is frozen

------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------

new class name is : Point

Point2 Call to method

new class's method is : 100

---------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: