- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在使用 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 创建新类时获取常量池正确实例的一般正确方法是什么?
另外,我对这里幕后发生的事情有点迷茫:为什么我们需要一个常量池来创建合成属性的实例?或者一般来说,任何其他类型的类属性的实例?
感谢任何澄清。
最佳答案
不知道您是否仍然对答案感兴趣,但至少可以帮助其他人找到这个问题。
首先,给开始创建/修改字节码的每个人一个小建议并且需要关于 JVM 内部如何工作的更深入的信息,JVM's specification documentation起初可能看起来笨重和可怕,但它是无价的帮助!
Is the call to CtClass.getClassFile().getConstPool() the correct way to get a constant pool in this example?.
是的,是的。每个 Java 类都有一个常量池,所以基本上每次你需要访问常量对于给定类的池,您可以执行 ctClass.getClassFile().getConstPool()
,但您必须牢记以下:
在 javassist 中,CtClass
中的常量池字段是一个实例字段,这意味着如果您有两个 CtClass
对象代表同一个类,你将有两个不同的常量池实例(即使它们代表实际类文件中的常量池)。修改其中一个 CtClass
实例时,您必须使用关联的常量池实例,以便具有预期的行为。
有时您可能没有 CtClass
,而是 CtMethod
或 CtField
,它们不允许您使用回溯到 CtClass
实例,在这种情况下,您可以使用 ctMethod.getMethodInfo().getConstPool()
和 ctField.getFieldInfo().getConstPool()
以检索正确的常量池。
因为我已经提到了 CtMethod
和 CtField
,请记住,如果您想向其中任何一个添加属性,则不能通过 >ClassFile
对象,但是分别通过MethodInfo
和FieldInfo
。
Why do we need a constant pool to create a instance of a synthetic attribute ?, or in general, of any other kind of class attributes ?
为了回答这个问题,我将开始引用 section 4.4 regarding JVM 7 specs (就像我说的,这个文档很有帮助):
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.
考虑到这一点,我认为阐明这个主题的最好方法是查看类文件转储。我们可以通过运行以下命令来实现:
javap -s -c -p -v SomeClassFile.class
Javap自带java SDK,是分析这一层类的好工具,各个开关的解释
这是我通过 javassist 修改的 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
}
请注意,类和方法都具有属性 Synthetic: true,这意味着它们是合成的,但是合成符号也必须存在于常量池中(检查 #33)。
关于常量池和类/方法属性的使用的另一个示例是添加到具有运行时保留策略的 someInjectedMethod 的注释。该方法的字节码只有对常量池#32 符号的引用,只有在那里你才知道注释来自类型 test/TestAnnotationToShowItInConstantTable;
希望您现在对事情有了更清楚的了解。
关于java - 了解 Javassist 中的常量池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12248897/
最近,我们将专用 SQL 池部署到生产中的 Synapse 工作区。在开发中,我们可以访问无服务器 SQL 池和专用 SQL 池。但是,在生产中,我们可以访问无服务器 SQL 池,但无法访问专用 SQ
假设您从一个项目公开 WCF 服务,并使用“添加服务引用”(在本例中为 Framework 3.5 WPF 应用程序)在另一个项目中使用它。 当您重新实例化 ClientBase 派生代理时,Clie
我有一个函数,它使用 multiprocessing.Pool 并行处理一个数据集中的所有数据。 from multiprocessing import Pool ... def func():
我正在尝试使用进程对象在 python 中使用工作池。每个 worker (一个进程)进行一些初始化(花费大量时间),传递一系列作业(理想情况下使用 map()),并返回一些东西。除此之外,不需要任何
我是软件工程师,最近我构建了我的 Linux 机器,想探索更多系统管理员类型的任务。我已经探索并阅读了很多关于 ZFS 的内容,但我越来越困惑,因为每篇文章对它的描述都不一样。 Everything
我有 zfs 池: $ sudo zpool status lxd pool: lxd state: ONLINE scan: none requested config: NAME
我有一个基于 Actor 的项目,对于其中的一部分,我必须使用一些接收消息的 Actor ,然后一个 Actor 分别分配给每个请求,每个 Actor 负责执行其消息请求,所以我需要类似线程的东西我的
我已经使用 QEMU 模拟器成功地将 FreeBSD 安装到原始图像文件中。我已经使用 ZFS 文件系统 (ZFS POOL) 格式化了图像文件。 使用下面的命令我已经成功地挂载了准备好由 zpool
我正在使用 multiprocessor.Pool并行处理一些文件。该代码等待接收文件,然后使用 Pool.apply_async 将该文件发送给工作人员。 ,然后处理文件。 这段代码应该一直在运行,
我正在使用带有光滑的 Bonecp 数据源。并发现池包含关闭的连接所以我总是遇到这个异常 java.sql.SQLException: Connection is closed! at com
我有apartment gem的 Multi-Tenancy Rails应用程序,我可以使用apartment-sidekiq在每个工作程序中成功切换数据库租户。但是,sidekiq worker 正
ZFS 池可能由数据集(文件系统、快照等)或卷组成。 ZFS 卷就像 block 设备,但我不明白池和文件系统之间的区别。当我通过 zpool create pool1 sda sdb sdc 创建
我在 docker 容器上运行了 airflow。我正在使用 airflow 2.0.2 版。 我知道我实际上可以通过 UI 创建池。但我正在寻找一种通过 pools.json 文件在 docker
我在tomcat中有一个jdbc池,用于建立数据库连接。我在使用后没有显式关闭连接对象。我的“maxActive”参数设置为100。应用程序运行了一段时间,但随后失败进行数据库查询。它会等待无限时间来
阅读 PostgreSQL 文档 here我读了以下内容: As well, connections requested for users other than the default config
我在 docker 容器上运行了 airflow。我正在使用 airflow 2.0.2 版。 我知道我实际上可以通过 UI 创建池。但我正在寻找一种通过 pools.json 文件在 docker
我正在读取一个大的 URL 文件并向服务发出请求。该请求由返回 ListenableFuture 的客户端执行。现在我想保留一个 ListenableFuture 池,例如最多同时执行 N 个 Fut
我想使用队列来保存结果,因为我希望消费者(串行而不是并行)在工作人员产生结果时处理工作人员的结果。 现在,我想知道为什么以下程序挂起。 import multiprocessing as mp imp
我正在开发一个单页应用程序,目前正在构建一个 JQuery、ajax 函数,以便我的所有调用都能通过。 对于一个典型的页面,我可能有 3 个 ajax 调用。我的想法是,如果用户互联网出去将这些 aj
我有一个单位类及其一些子类(弓箭手、剑客等)。我怎样才能创建一个回收所有单元类型子类的池? 最佳答案 这是不可能的,因为池只能包含一种特定类型的对象。否则你可能会遇到这样的情况: Pool unitP
我是一名优秀的程序员,十分优秀!