ClassPool

1、简介

ClassPool是缓存CtClass对象的容器,所有的CtClass对象都在ClassPool中。所以,CtClass对象很多时,ClassPool会消耗很大的内存,为了避免内存的消耗,创建ClassPool对象时可以使用单例模式,或者对于CtClass对象,调用detach方法将其从ClassPool中移除。

2、创建ClassPool对象

(1)构造函数1

public ClassPool()
创建一个根ClassPool对象

(2)构造函数2

public ClassPool(boolean useDefaultPath)
创建一个根ClassPool对象,当参数为true时,appendSystemPath将被调用。

(3)构造函数3

public ClassPool(ClassPool parent)
创建一个指定根的ClassPool对象,若无根,则参数为null。
(4)单例

public static ClassPool getDefault()
创建默认的ClassPool对象,该方法是单例的。当调用该方法时,等同于下面代码的调用。

ClassPool cp = new ClassPool(); cp.appendSystemPath();


3、修改生成的类

   首先生成一个类:

public class ClassGeneratedByJavassist {

	public static void main(String[] args) throws Exception {

		ClassPool pool = ClassPool.getDefault();

		CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");

		// 添加一个参数
		CtField ctField = new CtField(CtClass.intType, "id", ctClass);
		ctField.setModifiers(Modifier.PUBLIC);
		ctClass.addField(ctField);

		// 把生成的class文件写入文件
		byte[] byteArr = ctClass.toBytecode();
		FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
		fos.write(byteArr);
		fos.close();
		System.out.println("over!!");
	}
}


通过XJad反编译,结果如下:

// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   MyCC.java

package com.study.javassist;


public class MyCC
{

	public int id;

	public MyCC()
	{
	}
}

下面对MyClass.java再添加一个name属性,如下:

public class ClassGeneratedByJavassist {

	public static void main(String[] args) throws Exception {

		ClassPool pool = ClassPool.getDefault();

		CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");

		// 添加一个参数
		CtField ctField = new CtField(CtClass.intType, "id", ctClass);
		ctField.setModifiers(Modifier.PUBLIC);
		ctClass.addField(ctField);

		// 把生成的class文件写入文件
		byte[] byteArr = ctClass.toBytecode();
		FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
		fos.write(byteArr);
		fos.close();
		System.out.println("over!!");

		
		// 为了测试ctClass是否能够再修改,再添加一个域
		CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",
				ctClass);
		ctField2.setModifiers(Modifier.PUBLIC);
		ctClass.addField(ctField2);
		byteArr = ctClass.toBytecode();
		fos = new FileOutputStream(new File("D://MyCC.class"));
		fos.write(byteArr);
		fos.close();
		System.out.println(1111);
	}
}


当执行时,抛出如下异常:

Exception in thread "main" java.lang.RuntimeException: com.study.javassist.MyCC class is frozen
	at javassist.CtClassType.checkModify(CtClassType.java:286)
	at javassist.CtField.setModifiers(CtField.java:239)
	at com.study.javassist.ClassGeneratedByJavassist.main(ClassGeneratedByJavassist.java:36)



原因解释如下:

   当CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后,Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class文件,所以不允许对其修改。

  因此,若想对CtClass对象进行修改,必须对其进行解冻,通过defrost()方法进行,如下所示:

public class ClassGeneratedByJavassist {

	public static void main(String[] args) throws Exception {

		ClassPool pool = ClassPool.getDefault();

		CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");

		// 添加一个参数
		CtField ctField = new CtField(CtClass.intType, "id", ctClass);
		ctField.setModifiers(Modifier.PUBLIC);
		ctClass.addField(ctField);

		// 把生成的class文件写入文件
		byte[] byteArr = ctClass.toBytecode();
		FileOutputStream fos = new FileOutputStream(new File("D://MyCC.class"));
		fos.write(byteArr);
		fos.close();
		System.out.println("over!!");

		// 解冻CtClass对象
		ctClass.defrost();
		
		// 为了测试ctClass是否能够再修改,再添加一个域
		CtField ctField2 = new CtField(pool.get("java.lang.String"), "name",
				ctClass);
		ctField2.setModifiers(Modifier.PUBLIC);
		ctClass.addField(ctField2);
		byteArr = ctClass.toBytecode();
		fos = new FileOutputStream(new File("D://MyCC.class"));
		fos.write(byteArr);
		fos.close();
		System.out.println(1111);
	}
}

通过反编译,结果如下:

// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   MyCC.java

package com.study.javassist;


public class MyCC
{

	public int id;
	public String name;

	public MyCC()
	{
	}
}



4、类名操作

(1)获取类名

  ClassPool pool = ClassPool.getDefault();
  CtClass ctClass = pool.makeClass("com.study.javassist.MyCC");
  System.out.println(ctClass.getName());
结果如下:

com.study.javassist.MyCC

(2)改变类名

   ctClass.setName("com.study.javassist.MyCC2");
   System.out.println(ctClass.getName());
结果:

com.study.javassist.MyCC2

(3)通过重命名冻结类定义新类

当CtClass对象通过writeFile( )或者toBytecode( )方法转为class文件后,javassist不允许对CtClass对象作后续修改,因此当通过调用setName修改类名时是不允许的。

 可以通过ClassPool的getAndRename(oldName, newName)方法实现。

如下示例:

                ClassPool pool = ClassPool.getDefault();
		CtClass ct1 = pool.get("com.study.javassist.TestName");
		System.out.println(ct1.getName());
		ct1.writeFile();
		CtClass ct2 = pool.getAndRename("com.study.javassist.TestName", "com.study.javassist.TestName2");
		System.out.println(ct2.getName());
结果如下:

com.study.javassist.TestName
com.study.javassist.TestName2






 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值