了解Javassist中的常量池
我正在使用Javassist在运行时扩展某些类。 在一些地方(在生成代码中),我需要创建Javassist了解Javassist中的常量池,java,javassist,Java,Javassist,我正在使用Javassist在运行时扩展某些类。 在一些地方(在生成代码中),我需要创建JavassistConstPool类的实例。 例如,为了将生成的类标记为synthetic,我编写了如下代码: CtClass ctClassToExtend = ... //class to extend CtClass newCtClass = extend(ctClassToExtend, ...); //method to create a new ctClass extending ctClass
ConstPool
类的实例。
例如,为了将生成的类标记为synthetic
,我编写了如下代码:
CtClass ctClassToExtend = ... //class to extend
CtClass newCtClass = extend(ctClassToExtend, ...); //method to create a new ctClass extending ctClassToExtend
SyntheticAttribute syntheticAttribute = new SyntheticAttribute(ctClassToExtend.getClassFile().getConstPool()); //creating a synthetic attribute using an instance of ConstPool
newCtClass.setAttribute(syntheticAttribute.getName(), syntheticAttribute.get()); //marking the generated class as synthetic
这是预期的工作,但我有一定的怀疑这是完全正确的。具体而言,我的主要问题是:
在本例中,调用CtClass.getClassFile().getConstPool()
是获取常量池的正确方法吗?。如果不是,那么在运行时使用Javassist创建新类时,获取常量池正确实例的一般正确方法是什么
另外,我对这里幕后发生的事情有点茫然:为什么我们需要一个常量池来创建合成属性的实例?或者一般来说,创建任何其他类型的类属性的实例
感谢您的澄清。不知道您是否对答案感兴趣,但至少可以帮助其他人 找到这个问题 首先,给每个开始创建/修改字节码的人一个小建议 而且需要更多关于JVM内部如何工作的深入信息,一开始可能看起来笨重可怕,但这是非常宝贵的帮助 在本例中,调用CtClass.getClassFile().getConstPool()是否是获取常量池的正确方法 是的。每个Java类都有一个常量池,因此每次需要访问该常量时都会使用basicali 对于给定的类,您可以执行
ctClass.getClassFile().getConstPool()
,但必须记住
以下:
CtClass
中的常量池字段是一个实例字段,这意味着如果您有两个CtClass
对象
表示同一个类时,将有两个不同的常量池实例(即使它们表示
实际类文件中的常量池)。修改一个CtClass
实例时,必须使用
关联的常量池实例,以便具有预期的行为
CtClass
,而是有CtMethod
或CtField
,它们不允许您回溯到CtClass
实例,在这种情况下,您可以使用CtMethod.getMethodInfo().getConstPool()
和CtField.getFieldInfo().getConstPool()
检索正确的常量池
既然我已经提到了CtMethod
和CtField
,请记住,如果要向其中任何一个添加属性,它不能通过ClassFile
对象,而是分别通过MethodInfo
和FieldInfo
来添加
javap -s -c -p -v SomeClassFile.class
Javap随javasdk一起提供,它是在这个级别分析类的一个很好的工具,解释了每个开关
- -s:打印内部类型签名
- -打印字节码
- -p:打印所有类成员(方法和字段,包括私有的)
- -v:要详细,将打印大头钉信息和类常量池
test.Test1
类的输出,它在类和injectedMethod
Classfile /C:/development/testProject/test/Test1.class
Last modified 29/Nov/2012; size 612 bytes
MD5 checksum 858c009090bfb57d704b2eaf91c2cb75
Compiled from "Test1.java"
public class test.Test1
SourceFile: "Test1.java"
Synthetic: true
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // test/Test1
#2 = Utf8 test/Test1
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Methodref #3.#9 // java/lang/Object."<init>":()V
#9 = NameAndType #5:#6 // "<init>":()V
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Ltest/Test1;
#14 = Utf8 SourceFile
#15 = Utf8 Test1.java
#16 = Utf8 someInjectedMethod
#17 = Utf8 java/lang/System
#18 = Class #17 // java/lang/System
#19 = Utf8 out
#20 = Utf8 Ljava/io/PrintStream;
#21 = NameAndType #19:#20 // out:Ljava/io/PrintStream;
#22 = Fieldref #18.#21 // java/lang/System.out:Ljava/io/PrintStream;
#23 = Utf8 injection example
#24 = String #23 // injection example
#25 = Utf8 java/io/PrintStream
#26 = Class #25 // java/io/PrintStream
#27 = Utf8 println
#28 = Utf8 (Ljava/lang/String;)V
#29 = NameAndType #27:#28 // println:(Ljava/lang/String;)V
#30 = Methodref #26.#29 // java/io/PrintStream.println:(Ljava/lang/String;)V
#31 = Utf8 RuntimeVisibleAnnotations
#32 = Utf8 Ltest/TestAnnotationToShowItInConstantTable;
#33 = Utf8 Synthetic
{
public com.qubit.augmentation.test.Test1();
Signature: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Ltest/Test1;
protected void someInjectedMethod();
Signature: ()V
flags: ACC_PROTECTED
Code:
stack=2, locals=1, args_size=1
0: getstatic #22 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #24 // String injection example
5: invokevirtual #30 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
RuntimeVisibleAnnotations:
0: #32()
Synthetic: true
}
Classfile/C:/development/testProject/test/Test1.class
最后修改日期:2012年11月29日;大小为612字节
MD5校验和858C0090BFB57D704B2EAF91C2CB75
从“Test1.java”编译而来
公共类test.Test1
源文件:“Test1.java”
合成的:真的
次要版本:0
主要版本:50
旗帜:ACC_公共、ACC_超级
固定池:
#1=类#2//测试/测试1
#2=Utf8测试/测试1
#3=类#4//java/lang/Object
#4=Utf8 java/lang/Object
#5=Utf8
#6=Utf8()V
#7=Utf8代码
#8=Methodref#3.#9//java/lang/Object.“:()V
#9=名称和类型#5:#6/“”:()V
#10=Utf8行号表
#11=Utf8 LocalVariableTable
#12=Utf8此
#13=Utf8 Ltest/Test1;
#14=Utf8源文件
#15=Utf8 Test1.java
#16=Utf8 someInjectedMethod
#17=Utf8 java/lang/System
#18=类#17//java/lang/System
#19=Utf8输出
#20=Utf8 Ljava/io/PrintStream;
#21=名称和类型#19:#20//out:Ljava/io/PrintStream;
#22=Fieldref#18.#21//java/lang/System.out:Ljava/io/PrintStream;
#23=Utf8注入示例
#24=字符串#23//注入示例
#25=Utf8 java/io/PrintStream
#26=类#25//java/io/PrintStream
#27=Utf8打印LN
#28=Utf8(Ljava/lang/String;)V
#29=名称和类型#27:#28//println:(Ljava/lang/String;)V
#30=Methodref#26.#29//java/io/PrintStream.println:(Ljava/lang/String;)V
#31=Utf8运行时访问说明
#32=Utf8 Ltest/TestAnnotationToShowitnconstanttable;
#33=Utf8合成
{
public com.qubit.augmentation.test.Test1();
签字:()五
旗帜:ACC_PUBLIC
有限公司