我正在使用Javassist在运行时扩展某些类。
在几个地方(在生成代码中)我需要创建Javassist 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在运行时创建新类时,获取常量池的正确实例的一般正确方法是什么?
另外,关于窗帘背后发生的事情,我有点迷失:为什么我们需要一个常量池来创建一个合成属性的实例?或者一般来说,还有其他任何类属性的实例?
感谢您的任何澄清。
答案 0 :(得分:9)
不知道你是否仍然对答案感兴趣,但至少可能会帮助其他人 找到这个问题。
首先,向每个开始创建/修改字节码的人提出一个小建议 并且需要有关JVM内部如何工作的更深入的信息,JVM's specification documentation起初可能看起来笨重而且可怕,但它是非常宝贵的帮助!
对CtClass.getClassFile()。getConstPool()的调用是否是在此示例中获取常量池的正确方法?
是的,确实如此。每个Java类都有一个常量池,因此每次需要访问常量时都是基本的
你可以做ctClass.getClassFile().getConstPool()
给定班级的游泳池,虽然你必须记住
以下内容:
在javassist中,来自CtClass
的常量池字段是一个实例字段,这意味着如果您有两个CtClass
个对象
代表同一个类,你将有两个不同的常量池实例(即使它们代表
实际类文件中的常量池)。修改其中一个CtClass
实例时,必须使用
关联的常量池实例,以便具有预期的行为。
有些时候您可能没有CtClass
,而是CtMethod
或CtField
不允许您回溯到CtClass
实例,在这种情况下,您可以使用ctMethod.getMethodInfo().getConstPool()
和ctField.getFieldInfo().getConstPool()
来检索正确的常量池。
由于我已经提到了CtMethod
和CtField
,请注意,如果您想为其中任何一个添加属性,则无法通过{{1} }对象,但分别通过ClassFile
和MethodInfo
。
为什么我们需要一个常量池来创建合成属性的实例?或者一般来说,是否需要任何其他类属性的实例?
要回答这个问题,我将开始引用section 4.4 regarding JVM 7 specs(就像我说的,这个文档非常有用):
Java虚拟机指令不依赖于类,接口,类实例或数组的运行时布局。相反,指令引用constant_pool表中的符号信息。
考虑到这一点,我认为了解这个主题的最好方法是查看类文件转储。我们可以通过运行以下命令来实现此目的:
FieldInfo
Javap附带java SDK,它是分析这个级别的类的好工具,每个开关的解释
这里是我通过javassist修改的javap -s -c -p -v SomeClassFile.class
类的输出,以便在类和test.Test1
injectedMethod
请注意,类和方法都具有属性 Synthetic:true ,这意味着它们是Synthetic但是,合成符号也必须存在于常量池中(检查#33)。 / p>
关于使用常量池和类/方法属性的另一个示例是使用运行时保留策略添加到someInjectedMethod的注释。该方法的字节码只能引用常量池#32符号,只有在那里你才能学到这一点 注释来自类型test / TestAnnotationToShowItInConstantTable;
希望现在事情变得更清楚了。