一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述符信息外,还包含一项信息就是常量池表(Constant Pool Table),包括各种字面量和对类型、域和方法的符号引用
为什么需要常量池一个 java 源文件中的类、接口,编译后产生一个字节码文件。而 Java 中的字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码里,换另一种方式,可以存到常量池,这个字节码包含了指向常量池的引用。在动态链接的时候会用到运行时常量池,之前有介绍。
比如:如下的代码:
public class SimpleClass { public void sayHello() { System.out.println("hello"); } }虽然上述代码只有 194 字节,但是里面却使用了 String、System、PrintStream 及 Object 等结构。这里的代码量其实很少了,如果代码多的话,引用的结构将会更多,这里就需要用到常量池了。
常量池中有什么数量值
字符串值
类引用
字段引用
方法引用
例如下面这段代码
public class MethodAreaTest2 { public static void main(String args[]) { Object obj = new Object(); } }将会被翻译成如下字节码
new #2 dup invokespecial 小结常量池、可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型
运行时常量池运行时常量池(Runtime Constant Pool)是方法区的一部分。
常量池表(Constant Pool Table)是 Class 文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
运行时常量池,在加载类和接口到虚拟机后,就会创建对应的运行时常量池。
JVM 为每个已加载的类型(类或接口)都维护一个常量池。池中的数据项像数组项一样,是通过索引访问的。
运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。此时不再是常量池中的符号地址了,这里换为真实地址。
运行时常量池,相对于 Class 文件常量池的另一重要特征是:具备动态性。
String.intern()
运行时常量池类似于传统编程语言中的符号表(symboltable),但是它所包含的数据却比符号表要更加丰富一些。
当创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则 JVM 会抛 OutOfMemoryError 异常。
方法区使用举例如下代码
public class MethodAreaDemo { public static void main(String args[]) { int x = 500; int y = 100; int a = x / y; int b = 50; System.out.println(a+b); } }字节码执行过程展示
首先现将操作数500放入到操作数栈中
然后存储到局部变量表中
然后重复一次,把 100 放入局部变量表中,最后再将变量表中的 500 和 100 取出,进行操作
将 500 和 100 进行一个除法运算,在把结果入栈
在最后就是输出流,需要调用运行时常量池的常量