Java 字符串常量池详解

简介: Java 字符串常量池详解

概念


在JVM中,为了减少字符串对象的重复创建,维护了一块特殊的内存空间,这块内存空间就被称为字符串常量池。


在JDK1.6及之前,字符串常量池存放在方法区中。到JDK1.7之后,就从方法区中移除了,而存放在堆中。一下是《深入理解虚Java虚拟机》第二版原文:


对于HotSpot 虚拟机,根据官方发布的路线图信息,现在也有放弃永久代并逐步改为采用Native Memory来实现方法区的规划了,在目前已经发布的JDK1.7 的HotSpot中,已经把原本放在永久代的字符串常量池移出。


根据查阅的资料显示在JDK1.7以后的版本中字符串常量池移到堆内存区域;同时在jdk1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域。


用法解析


1. 直接使用双引号声明出来的String对象


String s1 = "abc"


创建过程:JVM会使用常量池来管理字符串直接量。在执行这句话时,JVM会先检查常量池中是否已经存有"abc",若没有则将"abc"存入常量池,否则就复用常量池中已有的"abc",将其引用赋值给变量a。


2. 使用new方法创建出来的String对象


可以使用String提供的intern方法。


String s2 = new String("abc");


在执行这句话时,JVM会先使用常量池来管理字符串直接量,String 先使用 intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中,即将"abc"存入常量池。然后再创建一个新的String对象,这个对象会被保存在堆内存中。并且,堆中对象的数据会指向常量池中的直接量。


例如下面代码进行对abc常量进行检测是否存在的测试:


String s1="abc";
String s2 = new String("abc");
System.out.println(s2.intern());



测试案例


运行如下代码:


public class Test{
    public class void main(String[] args){
    String s1 = "abc";
        String s2 = "abc";
        System.out.println("s1="+s1);//abc
        System.out.println(s1 == s2);//true
        System.out.println("=================");
        char[] charArray = {'a','b','c'};
        String s3 = new String(charArray);
        System.out.println("s3="+s3);//abc
        System.out.println(s1 == s3);//false
        System.out.println("=================");
        String s4 = new String("abc");
        System.out.println("s4="+s4);//abc
        System.out.println(s1==s4);
        System.out.println("=================");
​    }
}


运行结果如下:



虽然两个输出两个字符串的结果相同,都为abc,但比较两者时则不同,这是因为比较的规则为:


  • 引用类型比较时,比较的是其地址值;


  • 基本数据类型比较的是其数据值。


采用直接创建String类型对象的方法创建对象时,JVM首先会去字符串常量池中查找是否存在"abc" 这个对象,如果不存在,则在字符串常量池中创建”abc“这个对象,然后将池中”abc“对象的引用地址返回给对象s1,这样s1的地址就在常量池中;


如果存在,则不创建任何对象,直接将存在的“abc”的地址返回给对象s2。这就是为什么s1等于s2的原因。


而通过new方法创建的String对象,其创建的字符串是放在堆当中的,将堆当中的字符串地址返回赋值给s3,s1和s3的存放地址不相同,一个在字符串常量池中,一个在堆当中,字符串常量池外,因此返回的值是false。s4同样如此。


相关面试题


String a = “abc”; ,说一下这个过程会创建什么,放在哪里?


参考答案


JVM会使用常量池来管理字符串直接量。在执行这句话时,JVM会先检查常量池中是否已经存有"abc",若没有则将"abc"存入常量池,否则就复用常量池中已有的"abc",将其引用赋值给变量a。


new String(“abc”) 是去了哪里,仅仅是在堆里面吗?


参考答案


在执行这句话时,JVM会先使用常量池来管理字符串直接量,即将"abc"存入常量池。然后再创建一个新的String对象,这个对象会被保存在堆内存中。并且,堆中对象的数据会指向常量池中的直接量。


相关文章
|
3月前
|
安全 Java API
【Java字符串操作秘籍】StringBuffer与StringBuilder的终极对决!
【8月更文挑战第25天】在Java中处理字符串时,经常需要修改字符串,但由于`String`对象的不可变性,频繁修改会导致内存浪费和性能下降。为此,Java提供了`StringBuffer`和`StringBuilder`两个类来操作可变字符串序列。`StringBuffer`是线程安全的,适用于多线程环境,但性能略低;`StringBuilder`非线程安全,但在单线程环境中性能更优。两者基本用法相似,通过`append`等方法构建和修改字符串。
65 1
|
26天前
|
存储 安全 Java
Java零基础-字符串详解
【10月更文挑战第18天】Java零基础教学篇,手把手实践教学!
99 60
|
15天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
36 6
|
1月前
|
Java 数据库
案例一:去掉数据库某列中的所有英文,利用java正则表达式去做,核心:去掉字符串中的英文
这篇文章介绍了如何使用Java正则表达式从数据库某列中去除所有英文字符。
50 15
|
1月前
|
Java
JAVA易错点详解(数据类型转换、字符串与运算符)
JAVA易错点详解(数据类型转换、字符串与运算符)
50 4
|
2月前
|
Java 数据库
java小工具util系列1:日期和字符串转换工具
java小工具util系列1:日期和字符串转换工具
52 3
|
2月前
|
SQL Java 索引
java小工具util系列2:字符串工具
java小工具util系列2:字符串工具
18 2
|
2月前
|
存储 移动开发 Java
java核心之字符串与编码
java核心之字符串与编码
23 2
|
2月前
|
Java
Java实现:将带时区的时间字符串转换为LocalDateTime对象
通过上述方法,你可以将带时区的时间字符串准确地转换为 `LocalDateTime`对象,这对于处理不需要时区信息的日期和时间场景非常有用。
763 4
下一篇
无影云桌面