跳转至
内容字体
东观体
上图东观体
OPPO Sans
江城黑体
霞鹜臻楷
代码字体
DejaVu Sans Mono
DejaVu Sans Mono
Google Sans Code
JetBrains Mono
主题切换
返回顶部

了解Java字符串常量池

约 471 个字 27 行代码 1 张图片 预计阅读时间 2 分钟

问题回顾与池化技术介绍

回顾在Java.lang中的String类和StringBuilder类介绍和常用方法提到的代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Demo04String {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abc";
        String s3 = new String("abc");
        System.out.println(s1==s2); //true
        System.out.println(s1==s3); //false
        System.out.println(s2==s3); //false
    }
}

当时只是简单得进行了解释:在Java程序中,类似于"abc"等字面类型的常量经常频繁使用,为了使程序的运行速度更快、更节省内存,Java为8种基本数据类型和String类都提供了常量池

为了节省存储空间以及程序的运行效率,Java中引入了:

  1. Class文件常量池:每个.java源文件编译后生成.class文件中会保存当前类中的字面常量以及符号信息
  2. 运行时常量池:在.class文件被加载时,.class文件中的常量池被加载到内存中称为运行时常量池,运行时常 量池每个类都有一份
  3. 字符串常量池

关于上面的内容,后序在讲JVM时会详细阐述

字符串常量池

字符串常量池在JVM中是StringTable类,实际是一个固定大小的HashTable,不同JDK版本下字符串常量池的位置以及默认大小是不同的:

JDK版本 字符串常量池位置 大小设置
Java6 (方法区)永久代 固定大小:1009
Java7 堆中 可设置,没有大小限制,默认大小:60013
Java8 堆中 可设置,有范围限制,最小是1009

以下面的代码为例:

Java
1
2
3
4
5
6
7
8
public class Demo05StringPool {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        String s3 = new String("world");
        String s4 = new String("world");
    }
}

底层如下图所示:

从上图可以得出一个结论:只要是new的对象,都是唯一的

通过上面例子可以看出:使用常量串创建String类型对象的效率更高,而且更节省空间。用户也可以将创建的字符串对象通过intern方式添加进字符串常量池中,例如下面的代码:

Java
1
2
3
4
5
6
7
8
9
public class Test {
    public static void main(String[] args) {
        char[] ch = new char[]{'a', 'b', 'c'};
        String s1 = new String(ch); // s1对象本身并不在常量池中
        s1.intern(); // intern方法调用之后,会将s1对象的引用放入到常量池中
        String s2 = "abc"; // "abc"在常量池中存在了,s2创建时直接用常量池中"abc"的引用
        System.out.println(s1 == s2);
    }
}