Java创建字符串分析

字符串常量池

字符串常量池:在jdk1.8中是堆空间的一个常量池,用于存放已经创建的字符串。在字符串池中的每个字符串对象只有唯一的一份,可以被多个引用所指向,避免了重复创建内容相同的字符串;通过字面值赋值创建的字符串对象存放在字符串池中,通过关键字new出来的字符串对象存放在堆中(也在常量池中创建该字符串的常量,只是返回的是地址是指向堆中的对象)。

创建字符串分析

使用字面量方式创建

        String s1 = "A";//会直接在字符串常量池中创建常量"A",然后返回

        String s2 = "A";//会直接返回字符串常量池中的常量"A",

        System.out.println(s1 == s2);

        //将字符串常量池中"AA"对应的成堆中的引用

        String s3 = new String("A") + new String("A");

        System.out.println(s3 == s3.intern()); //true,此时字符串常量池存在"AA"对应的堆引用

        String s4="AA";

        System.out.println(s3==s4);//true

JVM会判断字符串常量池中是否存在该常量,如果存在该常量,那么会直接返回字符串常量池中的常量;如果存在该常量在堆中的引用,那么会返回该引用(指向堆中的对象);如果字符串常量池中不存在该字符串字面量,那么会在常量池中创建该字符串的常量,并返回字符串池中的常量。

上述代码因为s1、s2储存的都是常量池中"A"这个常量对象的地址,所以,s1==s2返回true。

该方法最多只会创建一次对象。堆空间不存在对象,字符串常量池可能会创建一个常量。

用该方式创建的对象s1,只会在字符串常量池中。

使用new关键字方式创建

        String s5=new String("A");

        String s6=new String("A");

        System.out.println(s5==s6);//false

1.无论堆上是否存在相同字面量的对象,JVM会先在堆上创建一个对象。

2.JVM会判断字符串常量池中是否存在该字符串对象的字面量,如果存在(不管是存在常量还是存在堆中的引用),就什么也不做。如果不存在,那么会在常量池中创建该字符串的常量。

3.返回该字符串在堆中创建对象的引用。

上述代码因为s3、s4储存的是堆空间新分配的地址,所以,s3==s4返回false。

该方法最多会创建两次对象,肯定会在堆空间中创建,还可能会在字符串常量池中创建一次常量。

用该方式创建的对象s5,会在堆空间和字符串常量池中。

使用字面量相加方式创建

		//常量池上存在常量AB
        String s6 = "AB";
        String s7 = "A" + "B";
        System.out.println(s6 == s7); //true

        //常量池上存在引用CD
        String s8 = new String("C") + new String("D");
        s8.intern();
        String s9 = "C" + "D";
        System.out.println(s8 == s9); //true

和使用字面量方式创建类似。

1.JVM会分别判断字符串常量池中是否存在"A"、"B"常量,如果存在(不管是存在常量还是存在堆中的引用),那就什么也不做;如果不存在,那么会在常量池中创建其字符串的常量。

2.JVM会分别判断字符串常量池中是否存在"AB"常量,如果存在该常量,那么会直接返回字符串常量池中的常量;如果存在该常量在堆中的引用,那么会返回该引用(指向堆中的对象);如果字符串常量池中不存在该字面量,那么会在常量池中创建该字符串的常量,并返回字符串池中的常量。

s7在创建时最多会在字符串池中创建三个常量。

用该方式创建的对象s7,只会在字符串常量池中。

使用new关键字相加方式创建

        String s10 = new String("AA") + new String("B");

        String s11 = new String("AA");

        System.out.println(s11 == s11.intern());//false
        System.out.println(s10 == s10.intern());//true

1.无论堆上是否存在相同字面量的对象,JVM会先在堆上分别创建"AA"、“B”、"AAB"三个对象。

2.JVM会分别判断字符串常量池中是否存在"AA"、"B"对象的字面量,如果存在(不管是存在常量还是存在堆中的引用),那么不做任何操作。如果不存在,那么会在常量池中创建其字符串的常量。

3.返回堆空间中"AAB"对象的引用。

s10在创建时最多会创建五个对象,其中堆中三个肯定有,还可能会在字符串常量池中创建两个常量。

用该方式创建的对象s10,只会在堆空间中。

使用字面量和new关键字相加方式创建

		String s12 = "A" + new String("B");
        System.out.println(s12 == s12.intern());//true
        String s13="AB";
        System.out.println(s12 == s13); //true

1.JVM会判断字符串常量池中是否存在"A"常量,如果存在,就什么也不做,如果不存在,会在字符串常量池中创建"A"常量;

2.无论堆上是否存在相同字面量的对象,在堆空间中创建"B"对象,然后判断字符串常量池中是否存在"B"常量,如果存在,就什么也不做,如果不存在,会在字符串常量池中创建"B"常量;

3.无论堆上是否存在相同字面量的对象,在堆空间中创建"AB"对象并将其地址返回给s12。

s12在创建时最多会创建四个对象,其中堆空间肯定会有两个,字符串常量池可能会创建两个常量。

用该方式创建的对象s12,只会在堆空间中。

String.intern()

		String s14 = "A";
        System.out.println(s14 == s14.intern()); //true
        String s15 = new String("A") + new String("A");
        String s16 = new String("A") + new String("A");
        s15.intern();//此时字符串常量池中"AA"对应的是堆中s15的引用
        System.out.println(s15 == s16.intern());//true
        System.out.println(s16 == s16.intern());//false
        String s17 = new String("B") + new String("B");
        System.out.println(s17 == s17.intern()); //true

intern()方法在jdk1.8中效果如下:

JVM会判断这个字符串对象字面量是否存在于常量池中,如果字符串常量池中存在该常量,那么会直接返回字符串常量池中的常量;如果字符串常量池中存在该常量在堆中的引用那么会返回该引用(指向堆中的对象);如果字符串常量池中不存在该字面量,那么会将当前对象引用复制到常量池。并且返回的是当前对象的引用。

发布了92 篇原创文章 · 获赞 4 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/DingKG/article/details/103376079
今日推荐