理解常量池

在理解常量值之前我们先了解几个基本概念。

1.字面量:可以理解为实际值,int a = 8中的8和String a = "hello"中的hello都是字面量。
2.符号引用:符号引用就是一个字符串。解析后就成了能直接定位到这个字符串要表示的内容的指针了。可参考JVM里的符号引用如何存储?。可以利用javap -verbose ByteCode.class看到上一篇文章的效果。
3.直接引用:是JVM(或其它运行时环境)所能直接使用的形式。

符号引用主要包括三种常量:
    1.类和接口的全限定名
    2.字段的名称和描述符
    3.方法的名称和描述符
直接引用可以是:
      1.直接指向目标的指针。(个人理解为:指向对象,类变量和类方法的指针)
      2.相对偏移量。      (指向实例的变量,方法的指针)
      3.一个间接定位到对象的句柄。

1.什么是常量池?

常量池的本质是缓存。不同的类共用一个运行时常量池
常量池分为:

  1. Class 文件常量池(非运行时常量池,本地文件)
  2. 运行时常量池(方法区内存中,元空间)
  3. 字符串常量池(堆内存)
1.1 Class 文件常量池(静态常量池)

Class常量池中存放的编译期生成的各种字面量和符号引用。这部分内容将在类加载后进入方法区的运行时常量池中存放。
接口A源码:

package com.xiaoer;

public interface A {
    default void defaultB() {
        System.out.println("defaultB");
    }

    static void staticA() {
        System.out.println("staticA");
    }
}

执行javap -verbose ByteCode.class查看class文件结构。

Classfile /E:/work_space/04 study/test01/target/classes/com/xiaoer/A.class
  Last modified 2019-9-19; size 448 bytes
  MD5 checksum 2dd9130ca78cd6781198832576a02832
  Compiled from "A.java"
public interface com.xiaoer.A
  minor version: 0
  major version: 54
  flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
   #1 = Fieldref           #17.#18        // java/lang/System.out:Ljava/io/PrintStream;
   #2 = String             #7             // defaultB
   #3 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #4 = String             #14            // staticA
   #5 = Class              #21            // com/xiaoer/A
   #6 = Class              #22            // java/lang/Object
   #7 = Utf8               defaultB
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/xiaoer/A;
  #14 = Utf8               staticA
  #15 = Utf8               SourceFile
  #16 = Utf8               A.java
  #17 = Class              #23            // java/lang/System
  #18 = NameAndType        #24:#25        // out:Ljava/io/PrintStream;
  #19 = Class              #26            // java/io/PrintStream
  #20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V
  #21 = Utf8               com/xiaoer/A
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/System
  #24 = Utf8               out
  #25 = Utf8               Ljava/io/PrintStream;
  #26 = Utf8               java/io/PrintStream
  #27 = Utf8               println
  #28 = Utf8               (Ljava/lang/String;)V
{
  public void defaultB();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #1                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #2                  // String defaultB
         5: invokevirtual #3                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 5: 0
        line 6: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lcom/xiaoer/A;

  public static void staticA();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #1                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #4                  // String staticA
         5: invokevirtual #3                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 8: 0
        line 9: 8
}
1.2 运行时常量池

静态常量池是针对每个被加载进入内存的class文件解析后,存放各个字面量值,符号引用的数据,而运行时常量区就是把所有的静态常量的数据汇总到一起(模糊来说)

1.3 字符串常量池

JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区。
DK1.7 以后字符串常量池被从方法区拿到了堆中,运行时常量池仍在方法区。

2.为什么需要常量池?

常量池其实就是跟数据库连接池的目的都是一样的。节省资源,提高效率。

3.String s1 = “Hello”,到底有没有在堆中创建对象?常量池存放的到底是对象还是对象引用?

是有的,所有创建的对象都在堆上。只是将字符串的引用放进字符串常量池。

参考资料:
1.Java的字面量和符号引用
2.Java系列20-字面量
3.走进java_符号引用与直接引用
4.JVM里的符号引用如何存储?
5.彻底弄懂java中的常量池
6.在Java虚拟机中,字符串常量到底存放在哪?
上面的资料都是从不明白到搞懂过程中筛选的,建议可以认真看看,串联起来就容易懂了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值