JDK8下的String详解


JDK 8 下的String

字符常量池

jdk8 位于堆中

创建对象的两种方式

通过字面量创建

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

采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在”abc”这个对象,如果不存在,则在字符串池中创建”abc”这个对象,然后将池中”abc”这个对象的引用地址返回给”abc”对象的引用s1,这样s1会指向池中”abc”这个字符串对象;如果存在,则不创建任何对象,直接将池中”abc”这个对象的地址返回,赋给引用s2。因为s1、s2都是指向同一个字符串池中的”abc”对象,所以结果为true。

new关键字创建

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

采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有”xyz”这个字符串对象,如果有,则不在池中再去创建”xyz”这个对象了,直接在堆中创建一个”xyz”字符串对象,然后将堆中的这个”xyz”对象的地址返回赋给引用s3,这样,s3就指向了堆中创建的这个”xyz”字符串对象;如果没有,则首先在字符串池中创建一个”xyz”字符串对象,然后再在堆中创建一个”xyz”字符串对象,然后将堆中这个”xyz”字符串对象的地址返回赋给s3引用,这样,s3指向了堆中创建的这个”xyz”字符串对象。s4则指向了堆中创建的另一个”xyz”字符串对象。s3 、s4是两个指向不同对象的引用,结果当然是false。


new String(“s”)涉及两个对象:字符串常量池中各一个。

  • 若规定new 一次算创建一个对象 则通过javap -c 查看字节码,只创建了一个对象

    Compiled from "StringTest.java"
    public class StringTest {
      public StringTest();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: new           #2                  // class java/lang/String
           3: dup
           4: ldc           #3                  // String a
           6: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
           9: astore_1
          10: return
    }

intern()

When the intern method is invoked, if the pool already contains a

string equal to this String object as determined by

the {@link #equals(Object)} method, then the string from the pool is

returned. Otherwise, this String object is added to the

pool and a reference to this String object is returned.

  • String.intern()是一个Native方法,它的作用是:如果运行时常量池中已经包含一个等于此String对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中创建与此String内容相同的字符串,并返回常量池中创建的字符串的引用。

几个问题

注意:每个问题的代码均独立运行互不干扰

1

String a = new String("1")+new String("2");
a.intern();
String b = "12";
System.out.println(a==b);

true;

解释:

  1. a对象通过+创建,所以栈中a 引用堆中的String(”12”)对象。
  2. a.intern()方法被调用,字符常量池中 “12” 引用堆中的String(”12”)对象。
  3. b是通过常量直接创建的,而字符常量池中有“12” 直接返回常量池中对象的引用(堆中的String(”12”)对象)。
  4. a==b 就是比较引用是否相等,都是 引用堆中的String(”12”)对象所以相等。

2

String a = new String("1")+new String("2");
String b = "12";

a.intern();

System.out.println(a==b);

false;

a.intern();的调用位置发生了变化,显然b中指向的是字符常量池中的对象,而a指向的是堆中的对象,所以false

3.

String b = new StringBuilder("abx").toString();
System.out.println(b.intern()==b);

false

解释见下

4.

String b = new StringBuilder("ab").append("x").toString();
System.out.println(b.intern()==b);

true

*解释:3:*new StringBuilder(“abx”); 执行该语句就会在字符串常量池中创建一个对象abx*,堆中也创建了一个对象b*。既然常量池中已经有了abx,那么在叫用intern()方法的时候就会返回常量池中的abx,而b是堆中的一个对象的引用。显然不相等。

**4:**String b = new StringBuilder(“ab”).append(“x”).toString();

常量池中至少(还有很多默认加入的对象)有ab和x,没有abx!调用intern就会返回b,当然相等。

5.

String b = new StringBuilder("ja").append("va").toString();
System.out.println(b.intern()==b);

false

因为java会被默认加入到常量池中 rt.jar

参考

https://www3.ntu.edu.sg/home/ehchua/programming/java/J3d_String.html


文章作者: Bxan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Bxan !
  目录