小蔡学Java

String str="aaa" & String str=new String("aaa")

2023-11-05 14:29 1495 0 Java基础 Java

什么是字符串常量池?

java中常量池的概念主要有三个:全局字符串常量池class文件常量池运行时常量池。我们现在所说的就是全局字符串常量池,对这个想弄明白的同学可以看这篇Java中几种常量池的区分。

jvm为了提升性能和减少内存开销,避免字符的重复创建,其维护了一块特殊的内存空间,即字符串 池,当需要使用字符串时,先去字符串池中查看该字符串是否已经存在,如果存在,则可以直接使用, 如果不存在,初始化,并将该字符串放入字符串常量池中。

字符串常量池的位置也是随着jdk版本的不同而位置不同。在jdk6中,常量池的位置在永久代(方法区)中,此时常量池中存储的是对象。在jdk7中,常量池的位置在堆中,此时,常量池存储的就是引用了。在jdk8中,永久代(方法区)被元空间取代了

String str="aaa"与 String str=new String(“aaa”)一样吗?new String(“aaa”);创建了几个字符串对象?

  • 使用String a = "aaa" ;,程序运行时会在常量池中查找"aaa"字符串,若没有,会将"aaa"字符串放进常量池,再将其地址赋给a若有,将找到的"aaa"字符串的地址赋给a

  • 使用String b = new String("aaa");,程序会在堆内存中开辟一片新空间存放新对象同时会将"aaa"字符串放入常量池相当于创建了两个对象,无论常量池中有没有"aaa"字符串,程序都会在堆内存中开辟一片新空间存放新对象。

具体分析,见以下代码:

 @Test
    public void test(){
        String s = new String("2");
        s.intern();
        String s2 = "2";
        System.out.println(s == s2);


        String s3 = new String("3") + new String("3");
        s3.intern();
        String s4 = "33";
        System.out.println(s3 == s4);
    }

jdk6
false
false

jdk7
false
true

这段代码在jdk6中输出是false false,但是在jdk7中输出的是false true。我们通过图来一行行解释。

先来认识下intern()函数:

  • 在JDK1.6中,intern的处理是** 先判断字符串常量是否在字符串常量池中,如果存在直接返回该常量,如果没有找到,则将该字符串常量加入到字符串常量池,也就是在字符串常量池建立该常量;**

  • 在JDK1.7中,intern的处理是 先判断字符串常量是否在字符串常量池中,如果存在直接返回该常量,如果没有找到,说明该字符串常量在堆中,则处理是把堆区该对象的引用加入到字符串常量池中,以后别人拿到的是该字符串常量的引用,实际存在堆中

JDK1.6


1. String s = new String("2");创建了两个对象,一个在堆中的StringObject对象,一个是在常量池中的"2"对象

  1. s.intern();在常量池中寻找与s变量内容相同的对象,发现已经存在内容相同对象"2",返回对象2的地址

  2. String s2 = "2";使用字面量创建,在常量池寻找是否有相同内容的对象,发现有,返回对象"2"的地址

  3. System.out.println(s == s2);从上面可以分析出,s变量和s2变量地址指向的是不同的对象,所以返回false


  1. String s3 = new String("3") + new String("3");创建了两个对象,一个在堆中的StringObject对象一个是在常量池中的"3"对象。中间还有2个匿名的new String("3")我们不去讨论它们。 s3.intern();在常量池中寻找与s3变量内容相同的对象,没有发现"33"对象,在常量池中创建"33"对象,返回"33"对象的地址。

  2. String s4 = "33";使用字面量创建,在常量池寻找是否有相同内容的对象,发现有,返回对象"33"的地址。

  3. System.out.println(s3 == s4);从上面可以分析出,s3变量和s4变量地址指向的是不同的对象,所以返回false

  4. s 被初始化为一个新的字符串对象,内容为 "2"。在 s 上调用 intern() 方法,但这个调用不会影响与 s2 的比较,因为** s2 是字符串字面量**,已经存在于字符串池中。因此,s == s2 的结果为 false

  5. s3 被初始化为两个内容为 "3" 的新字符串对象的连接。在 s3 上调用 intern() 方法,但同样地,这个调用不会影响与 s4 的比较,因为 s4 是字符串字面量,已经存在于字符串池中。因此,s3 == s4 的结果为 false

大家这块需要注意的是:JDK1.7之前的常量池在永久代中,JDK1.6的方法区的实现为永久代,所以上图中的堆和常量池是在俩个区域中,而JDK1.7以后,字符串常量池放在了堆中

JDK1.7


  1. String s = new String("2");创建了两个对象,一个在堆中的StringObject对象**,一个是在堆中的"2"对象,并在常量池中保存"2"对象的引用地址。**

  2. s.intern();在常量池中寻找与s变量内容相同的对象,发现已经存在内容相同对象"2",返回对象"2"的引用地址。

  3. String s2 = "2";使用字面量创建,在常量池寻找是否有相同内容的对象,发现有,返回对象"2"的引用地址。

  4. System.out.println(s == s2);从上面可以分析出,s变量和s2变量地址指向的是不同的对象,所以返回false


  1. String s3 = new String("3") + new String("3");创建了两个对象,一个在堆中的StringObject对象一个是在堆中的"3"对象,并在常量池中保存"3"对象的引用地址。中间还有2个匿名的new String(“3”)我们不去讨论它们。

  2. s3.intern();在常量池中寻找与s3变量内容相同的对象,没有发现"33"对象,将s3对应的StringObject对象的地址保存到常量池中,返回StringObject对象的地址。

  3. String s4 = "33";使用字面量创建,在常量池寻找是否有相同内容的对象,发现有,返回其地址,也就是StringObject对象的引用地址。

  4. System.out.println(s3 == s4);从上面可以分析出,s3变量和s4变量地址指向的是相同的对象,所以返回true

评论( 0 )

  • 博主 Mr Cai
  • 坐标 河南 信阳
  • 标签 Java、SpringBoot、消息中间件、Web、Code爱好者

文章目录