美文网首页
Java中的常量池

Java中的常量池

作者: 奔向学霸的路上 | 来源:发表于2020-11-30 18:29 被阅读0次

Java中的常量池分为三类:字符串常量池、class常量池、运行时常量池

字符串常量池

从1.7及其之后,字符串常量池从方法区移到了

字符串池的实现——StringTable

String类中并没有Integer中IntegerCache对象池,String中有native方法intern()。

intern
intern()方法作用是:若字符串常量池中存在(通过#equals(Object)来判定是否存在)该字符串,则直接返回,否则,将该String对象添加到池中并返回它的引用。

/**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     */
    public native String intern();

intern()

class常量池

class文件是一组以字节为单位的二进制数据流,当java代码被编译为.class文件格式时,二进制数据存放在磁盘中,其中就包括class文件常量池。

class常量池包含字面量符号引用

image.png
public class HelloWorld {
    public static void main(String[] args) {
        String s = "Hollis";
    }
}

javac 生成HelloWorld.class文件,然后javap -v HelloWorld.class

常量池内容如下:


image.png

Java代码在编译时,并不会“拼接”好完整执行文件,而是在虚拟机加载class文件时动态连接。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址中。

运行时常量池

Java1.7之前是在方法区,也处于永久代中;Java1.7因为使用永久代存在内存泄漏问题,将永久代中的运行时常量池移动到堆内存中;Java1.8是在元空间。

只有class文件中的常量池肯定是不够的,因为我们需要在JVM中运行起来。这时候就需要一个运行时常量池,为JVM的运行服务。
运行时常量池跟class文件的常量池一一对应,它是根据class常量池来构建的。

运行时常量池分两种类型:符号引用和静态常量

String s = "a";

s就是符号引用,需要在运行期进行解析,而a是静态常量,它是不会发生变化的。

静态常量详解

运行时常量池中的静态常量是从class文件中的constant_pool构建的,可以分为两部分:String常量和数字常量。

String常量
String常量是对String对象的引用,是从class中的CONSTANT_String_info结构构建的:

CONSTANT_String_info {
u1 tag;
u2 string_index;
}

tag是结构体的标记,string_index是string在class常量池中的index。
string_index对应的class常量池的内容是一个CONSTANT_Utf8_info结构体。

CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}

CONSTANT_Utf8_info是啥呢?它就是要创建的String对象的变种UTF-8编码。
我们知道unicode的范围是从0x0000 至 0x10FFFF。
变种UTF-8就是将unicode进行编码的方式。那是怎么编码呢?


image.png

上面这个图说实话,我没怎么看懂,TODO待学习

CONSTANT_String_info运行时String常量的规则(inter):

  • 如果String.intern之前被调用过,并且返回的结果和CONSTANT_String_info中保存的编码是一致的话,表示他们指向的是同一个String的实例。
  • 如果不同的话,那么会创建一个新的String实例,并将运行时String常量指向该String的实例。最后会在这个String实例上调用String的intern方法。调用inter方法主要是将这个String实例加入字符串常量池。

数字常量
数字常量是从class文件中的CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info和 CONSTANT_Double_info 构建的。

符号引用详解
符号引用也是从class中的constant_pool中构建的。
对class和interface的符号引用来自于CONSTANT_Class_info。
对class和interface中字段的引用来自于CONSTANT_Fieldref_info。
class中方法的引用来自于CONSTANT_Methodref_info。
interface中方法的引用来自于CONSTANT_InterfaceMethodref_info。
对方法句柄的引用来自于CONSTANT_MethodHandle_info。
对方法类型的引用来自于CONSTANT_MethodType_info。
对动态计算常量的符号引用来自于CONSTANT_MethodType_info。
对动态计算的call site的引用来自于CONSTANT_InvokeDynamic_info。

参考:https://cloud.tencent.com/developer/article/1450501
http://hollischuang.gitee.io/tobetopjavaer/#/basics/java-basic/class-contant-pool
https://www.cnblogs.com/natian-ws/p/10749164.html
http://hollischuang.gitee.io/tobetopjavaer/#/basics/java-basic/Runtime-Constant-Pool
https://www.cnblogs.com/flydean/p/jvm-run-time-constant-pool.html

相关文章

  • java基础类型、String类理解、版本对比、1.8新特性

    1、java基本数据类型及长度 2、jvm的常量池: JVM常量池浅析Java常量池理解与总结 Java中的常量池...

  • Java 内存—常量池

    Java中的常量池分为两种型态: 静态常量池 运行时常量池 静态常量池 所谓静态常量池是指class文件中的常量池...

  • 细说Java常量池

      Java中的常量池有:class常量池、运行时常量池、String常量池。 为什么要使用常量池?   避免频繁...

  • 常量池

    Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。 静态常量池 : *.class文件中的常量池,...

  • java__常量池

    java的常量池分为两种型态:静态常量池和运行常量池 静态常量池: 即class文件中的常量池,这种常量池主要用于...

  • JVM(六)JVM常量池

    1.常量池类型 Java中的常量池分为三种: 类文件常量池(静态常量池)(The Constant Pool)运行...

  • 常量池、运行时常量池、字符串常量池

    常量池、运行时常量池、字符串常量池 Java里包含各种常量池,经常傻傻分不清楚,下面就简单梳理下Java中的池们。...

  • 你对常量池够了解吗

    在 java 中,常量池分为以下三种: class 常量池 字符串常量池 运行时常量池 一、class 常量池 1...

  • Java中的常量池

    Java中的常量池分为三类:字符串常量池、class常量池、运行时常量池 字符串常量池 从1.7及其之后,字符串常...

  • String常量池

    java中有几种不同的常量池,以下的内容是对java中几种常量池的介绍以及重点研究一下字符串常量池。 class常...

网友评论

      本文标题:Java中的常量池

      本文链接:https://www.haomeiwen.com/subject/btqdiktx.html