Java常量池的目的是什么?
我目前正在深入研究Java虚拟机的规范。 我一直在网上阅读JVM书籍 ,有一个令人困惑的抽象,我似乎无法把握:常量池。 这里是这本书的摘录:
对于加载的每种types,Java虚拟机必须存储常量池。 常量池是types常量的有序集合,包括文字(string,整数和浮点常量)以及对types,字段和方法的符号引用。 常量池中的条目被索引引用,就像数组中的元素一样。 由于它拥有对types使用的所有types,字段和方法的符号引用,所以常量池在Java程序的dynamic链接中起着核心作用
关于上述和CP总体上我有几个问题:
- CP是否位于每个types的
.class
文件中? - 作者所说的“象征性的参考”是什么?
- 常量池的目的是什么,用简单的英语?
我觉得理解框架如何使用图表构build会有所帮助。
该帧是操作数(操作指令)所在的位置,也是dynamic链接发生的地方。 这可以说是一个简短的方法,用常数池来跟踪class级和成员。
每个框架都包含对运行时常量池的引用。 该引用指向正在为该帧执行的方法的类的常量池。 此引用有助于支持dynamic链接。
通常将C / C ++代码编译为一个目标文件,然后将多个目标文件链接在一起以产生可用的工件,如可执行文件或DLL。 在链接阶段,每个目标文件中的符号引用被replace为相对于最终可执行文件的实际内存地址。 在Java中,这个链接阶段是在运行时dynamic完成的。
编译Java文件时,对variables和方法的所有引用都将作为符号引用存储在类的常量池中。 符号引用是逻辑引用,而不是实际指向物理内存位置的引用。
这里是一个链接到James Blooms JVM内部的更多细节。
常量池是.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!
string和#4
是对PrintStream.println(String)
方法的符号引用。
正如您所看到的,符号引用不仅仅是名称 – 例如,对该方法的符号引用还包含有关其参数( Ljava/lang/String;
)和返回types( V
表示void
)的信息。
您可以通过为该类运行javap -verbose
来检查类的常量池。
常量池的目的是什么,用简单的英语?
CP是一个非常独特的存储区域,常量值被存储以减less冗余:
System.err.println("Hello"); System.out.println("Hello");
在CP中,只有一个String对象“Hello”,编译器将两行replace为相同的引用。 您的.class文件只包含一个Hellostring。 (其他types相同)。
CP是否位于每个types的.Class文件中?
是的,看这里: http : //en.wikipedia.org/wiki/Java_class_file
先给示例先了解一下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将查找程序中的所有string文字。
3-首先find引用文字“prasad”的variabless ,并在内存中创build它
4-string“prasad”的引用将被放置在string常量池内存中。
5-然后它find另一个引用相同的string“prasad”的 variabless2 。
现在JVM已经find了string“prasad” , variabless和s2都会引用同一个对象,即“prasad” 。
我希望这会有所帮助