42.理解常量池(Class文件中的常量池与运行时常量池)

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

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值