我目前正在尝试深入研究Java虚拟机的规范。我一直在阅读Inside the JVM book online并且有一个令人困惑的抽象我似乎无法理解:Constant Pool。这是本书的摘录:
对于它加载的每种类型,Java虚拟机必须存储一个常量池。常量池是类型使用的有序常量集,包括文字(字符串,整数和浮点常量)以及对类型,字段和方法的符号引用。常量池中的条目由索引引用,非常类似于数组的元素。因为它包含对类型使用的所有类型,字段和方法的符号引用,所以常量池在Java程序的动态链接中起着核心作用
关于上述内容和CP,我有几个问题:
.class
文件中?答案 0 :(得分:76)
常量池是.class
文件(及其内存中表示)的一部分,它包含运行该类代码所需的常量。
这些常量包括程序员指定的文字和编译器生成的符号引用。符号引用基本上是从代码引用的类,方法和字段的名称。 JVM使用这些引用将您的代码链接到它依赖的其他类。
例如,以下代码
System.out.println("Hello, world!");
生成以下字节码(javap
输出)
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String Hello, world!
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
#n
这里是对常量池的引用。 #2
是System.out
字段的符号引用,#3
是Hello, world!
字符串,#4
是PrintStream.println(String)
方法的符号引用。
如您所见,符号引用不仅仅是名称 - 例如,对方法的符号引用还包含有关其参数的信息(Ljava/lang/String;
)和返回类型(V
表示{{1} })。
您可以通过为该类运行void
来检查类的常量池。
答案 1 :(得分:64)
我认为理解如何使用图表构建框架会有所帮助。
帧是操作数(操作指令)所在的位置,也就是动态链接发生的位置。这是一种速记方式,可以说,使用常量池来跟踪班级及其成员。
每个帧都包含对运行时常量池的引用。该引用指向正在为该帧执行的方法的类的常量池。此参考有助于支持动态链接。
C / C ++代码通常被编译为目标文件,然后将多个目标文件链接在一起以产生可用的工件,例如可执行文件或dll。在链接阶段期间,每个目标文件中的符号引用被替换为相对于最终可执行文件的实际存储器地址。在Java中,这个链接阶段是在运行时动态完成的。编译Java文件时,对变量和方法的所有引用都存储在类的常量池中作为符号引用。符号引用是逻辑引用,而不是实际指向物理内存位置的引用。
以下是James Blooms JVM Internals的链接,了解更多详情。
答案 2 :(得分:9)
什么是Constant Pool的目的,用简单的英语?
CP是一个存储区域,存储非常独特的常量值以减少冗余:
System.err.println("Hello");
System.out.println("Hello");
在CP中只有一个String对象“Hello”,编译器将两行替换为相同的引用。您的.class文件只包含一个Hello字符串。 (其他类型相同)。
CP是否位于每种类型的.Class文件中?
答案 3 :(得分:0)
让Example First首先理解String常量池的含义
public class StringConstantPool {
public static void main(String[] args) {
String s = "prasad";
String s2 = "prasad";
System.out.println(s.equals(s2));
System.out.println(s == s2);
}
}
输出将是
true
true
这里一步一步发生的事情
1-调用JVM时加载类。
2- JVM将查找程序中的所有字符串文字。
3-首先,它找到 变量s ,它引用文字“prasad”,它将在内存中创建< / p>
4-文字“prasad”的引用将被放置在字符串常量池内存中。
5-然后它找到另一个 变量s2 ,它指的是相同的字符串文字“prasad”。
既然JVM已经找到一个字符串文字“prasad”,变量s和s2 都会引用相同的对象,即“prasad”< / em>的
我希望这会有所帮助
答案 4 :(得分:0)
它可能被解释为浏览器的浏览历史,从而减少了每次查找或构建的需求