什么是常量池
引用关于JVM 7规范的第4.4节
Java virtual machine instructions do not rely on the runtime layout of classes, interfaces, class instances, or arrays. Instead, instructions refer to symbolic information in the constant_pool table
大致意思:Java虚拟机指令不依赖于类、接口、类实例或数组的运行时布局。相反,指令引用 constant_pool 表中的符号信息。
所以,当我们创建属性相关实例时,都需要参数 constant_pool 。
如何获取常量池
方式一:通过ClassFile
ClassPool pool = ClassPool.getDefault();
//获取实体类
CtClass ctClass = pool.get(obj.getClass().getName());
ConstPool constPool = ctClass.getClassFile().getConstPool();
方式二:通过FieldInfo
ClassPool pool = ClassPool.getDefault();
//获取实体类
CtClass ctClass = pool.get(obj.getClass().getName());
//获取属性
CtField ctField = ctClass.getField(FieldName);
//获取属性字段信息
FieldInfo fieldInfo = ctField.getFieldInfo();
//获取常量池
ConstPool constPool = fieldInfo.getConstPool();
方式三:通过MethodInfo
ClassPool pool = ClassPool.getDefault();
//获取实体类
CtClass ctClass = pool.get(obj.getClass().getName());
//获取方法
CtMethod ctMethod = ctClass.getDeclaredMethod("foo","ceshi");
//获取方法信息
MethodInfo methodInfo = ctMethod.getMethodInfo();
//获取常量池
ConstPool constPool = methodInfo.getConstPool();
测试:
System.out.println("ConstPool=" + ctClass.getClassFile().getConstPool());
System.out.println("ConstPool=" + ctClass.getField(FieldName).getFieldInfo().getConstPool());
System.out.println("ConstPool=" + ctClass.getDeclaredMethod("foo").getMethodInfo().getConstPool());
if (fieldInfo.getConstPool().equals(ctClass.getClassFile().getConstPool())) {
System.out.println("true");
}
输出:
ConstPool=javassist.bytecode.ConstPool@7a07c5b4
ConstPool=javassist.bytecode.ConstPool@7a07c5b4
ConstPool=javassist.bytecode.ConstPool@7a07c5b4
true
测试发现,三种方式获取的 ConstPool 是一样的。每个Java类都有一个常量池,使用常量池需要注意:
- 在Javassist中,CtClass中的常量池字段是一个实例字段,这意味着如果您有两个 CtClass 对象代表同一个类,您将有两个不同的常量池实例(即使它们代表实际类文件中的常量池)。修改 CtClass 实例之一时,必须使用相关联的常量池实例,以具有预期的行为。
- 有时您可能没有 CtClass 而是 CtMethod 或 CtField,这不允许您回溯到CtClass实例,在这种情况下,可以使用ctMethod.getMethodInfo().getConstPool() 和 ctField.getFieldInfo().getConstPool() 获取常量池。