1.什么是常量池?
1.字节码文件中有个constant pool
,就是常量池
2.当字节码文件被加载到内存中之后,方法区中会存放字节码文件的constant pool
相关信息,这时候就成为了运行时常量池
3.常量池保存了各种字面量和对类型、域和方法的符号引用。
4.常量池可以看做是一张表,虚拟机指令根据这张表找到要执行的方法名、类名、参数类型、字面量等类型。
2.为什么需要常量池?
1.一个java
源文件中的类、接口,编译后会产生一个字节码文件,而java
中的字节码文件需要其他的数据支撑,通常这种数据很大,不能直接存放到字节码里面。所以把对这些数据的引用存放到常量池,在真正需要使用的时候,通过动态链接将符号引用转换为直接引用。
例子:
package jvm;
import java.io.Serializable;
public class MethodInnerStrucTest extends Object implements Comparable<String>,Serializable {
//属性
public int num = 10;
private static String str = "测试方法的内部结构";
//构造器
//方法
public void test1(){
int count = 20;
System.out.println("count = " + count);
}
@Override
public int compareTo(String o) {
return 0;
}
}
使用javap -v MethodInnerStrucTest
反编译上面的java
代码产生的class
文件,得到下面的输出。
其中:Constant pool
就是常量池。
常量池中存储的符号引用,在程序运行的时候,会被转换为直接引用。
例如:test1()
方法的字节码 3: getstatic #30 // Field
, #30
就会引用到Constant pool
里面的 #30 = Fieldref #31.#33 //
,程序运行的时候,就会直接进行转换。
Classfile /Users/simple/Documents/IBM/JVM/JVM/bin/jvm/MethodInnerStrucTest.class
Last modified Jul 21, 2020; size 1250 bytes
MD5 checksum 640842329ae45580b8fa6414cdc50a03
Compiled from "MethodInnerStrucTest.java"
public class jvm.MethodInnerStrucTest extends java.lang.Object implements java.lang.Comparable<java.lang.String>, java.io.Serializable
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // jvm/MethodInnerStrucTest
#2 = Utf8 jvm/MethodInnerStrucTest
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Class #6 // java/lang/Comparable
#6 = Utf8 java/lang/Comparable
#7 = Class #8 // java/io/Serializable
#8 = Utf8 java/io/Serializable
#9 = Utf8 num
#10 = Utf8 I
#11 = Utf8 str
#12 = Utf8 Ljava/lang/String;
#13 = Utf8 <clinit>
...
{
public int num;
descriptor: I
flags: ACC_PUBLIC
...
public void test1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=1
0: bipush 20
2: istore_1
3: getstatic #30 // Field java/lang/System.out:Ljava/io/PrintStream;
6: new #36 // class java/lang/StringBuilder
9: dup
10: ldc #38 // String count =
12: invokespecial #40 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
15: iload_1
16: invokevirtual #43 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
19: invokevirtual #47 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #51 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
LineNumberTable:
line 12: 0
line 13: 3
line 14: 25
LocalVariableTable:
Start Length Slot Name Signature
0 26 0 this Ljvm/MethodInnerStrucTest;
3 23 1 count I
...
}
3.运行时常量池
掌握两点:
1.常量池指的是字节码文件中的Constant pool
部分。这部分内容被类加载之后,存放到方法区的运行时常量池中。
2.运行时常量池具有动态性。也就是在方法区中的运行时常量池是可以发生变化的。而常量池就不行,它是静态的,当编译生成字节码文件直接就不变了。
更多JVM文章请访问我的JVM专栏:
https://blog.csdn.net/u011069294/category_10113093.html