Java中String字符串常量池

  最近到广州某互联网公司面试,当时面试官问假设有两个字符串String a="abc",String b = "abc";问输出a==b是true仍是false。我当时坚决果断答了true,而后根据字符串常量池的知识点结合jvm的内存模型讲解,然而他却跟我说是false,说这是最基本的问题。我当时一脸懵逼,跟他讨论了很长时间,后来发现他是错的,他说a,b两个变量是存在栈中,这两个引用是不同的,只不过它们指向的内容是同样的。由于他毕竟工做了好几年,我当时也质疑个人知识点,因此当时也接受了他的答案。回来上机实践查资料求证以后,说明我是对的,具体内容整理以下。首先先上三份代码:面试

第一段:jvm

public static void main(String[] args) {  String s1 = "hello";
       String s2 = "hello";
       String s3 = "he" + "llo";
       String s4 = "hel" + new String("lo");
       String s5 = new String("hello");
       String s6 = s5.intern();
       String s7 = "h";
       String s8 = "ello";
       String s9 = s7 + s8;
      System.out.println(s1==s2);//true
        System.out.println(s1==s3);//true
        System.out.println(s1==s4);//false
        System.out.println(s1==s9);//false
        System.out.println(s4==s5);//false
        System.out.println(s1==s6);//true
    }

  在jdk1.6,1.7,1.8下运行的结果为:优化

  System.out.println(s1==s2);//true
  System.out.println(s1==s3);//true
  System.out.println(s1==s4);//false
  System.out.println(s1==s9);//false
  System.out.println(s4==s5);//false
  System.out.println(s1==s6);//truespa

第二段:设计

public static void main(String[] args) { String s1 = new String("hello"); String intern1 = s1.intern(); String s2 = "hello"; System.out.println(s1 == s2); String s3 = new String("hello") + new String("hello"); String intern3 = s3.intern(); String s4 = "hellohello"; System.out.println(s3 == s4); }

  在jdk1.6下运行的结果为:code

  false,false对象

  在jdk1.7,1.8下运行的结果为:blog

  false,true内存

第三段:字符串

public static void main(String[] args) { String s1 = new String("hello"); String s2 = "hello"; String intern1 = s1.intern(); System.out.println(s1 == s2); String s3 = new String("hello") + new String("hello"); String s4 = "hellohello"; String intern3 = s3.intern(); System.out.println(s3 == s4); }

  在jdk1.6下运行的结果为:

  false,false

  在jdk1.7,1.8下运行的结果为:

  false,false

 

第一段代码:

  String类的final修饰的,以字面量的形式建立String变量时,jvm会在编译期间就把该字面量(“hello”)放到字符串常量池中,由Java程序启动的时候就已经加载到内存中了。这个字符串常量池的特色就是有且只有一份相同的字面量,若是有其它相同的字面量,jvm则返回这个字面量的引用,若是没有相同的字面量,则在字符串常量池建立这个字面量并返回它的引用。因为s2指向的字面量“hello”在常量池中已经存在了(s1先于s2),因而jvm就返回这个字面量绑定的引用,因此s1==s2。s3中字面量的拼接其实就是“hello”,jvm在编译期间就已经对它进行优化,因此s1和s3也是相等的。s4中的new String("lo")生成了两个对象,"lo","new String("lo")","lo"存在字符串常量池,"new String("lo")"存在堆中,String s4 = "hel" + new String("lo")实质上是两个对象的相加,编译器不会进行优化,相加的结果存在堆中,而s1存在字符串常量池中,固然不相等。s1==s9的原理同样。s4==s5两个相加的结果都在堆中,不用说,确定不相等。s1==s6中,s5.intern()方法能使一个位于堆中的字符串在运行期间动态地加入到字符串常量池中(字符串常量池的内容是程序启动的时候就已经加载好了),若是字符串常量池中有该对象对应的字面量,则返回该字面量在字符串常量池中的引用,不然,建立复制一份该字面量到字符串常量池并返回它的引用。所以s1==s6输出true。

第二段代码:

  jdk1.6下字符串常量池是在永久区中,是与堆彻底独立的两个空间,s1指向堆中的内容,s2指向字符串常量池中的内容,二者固然不同,s1.intern1()将字面量加入字符串常量池中,因为字符串常量池中已经存在该字面量,因此返回该字面量的惟一引用,intern1==s2就输出true。

  jdk1.7,1.8下字符串常量池已经转移到堆中了,是堆中的一部份内容,jvm设计人员对intern()进行了一些修改,当执行s3.intern()时,jvm再也不把s3对应的字面量复制一份到字符串常量池中,而是在字符串常量池中存储一份s3的引用,这个引用指向堆中的字面量,当运行到String s4 = "hellohello"时,发现字符串常量池已经存在一个指向堆中该字面量的引用,则返回这个引用,而这个引用就是s3。因此s3==s4输出true。

第三段代码:

  jdk1.6下输出false,false,原理和上面同样。

  jdk1.7,1.8下输出false,false,s3指向堆内容,接着s4="hellohello"发现字符串常量池中没有该字面量,建立并返回该引用。s3,s4一个在堆,一个在字符串常量池,是两个独立的引用,因此s3==s4输出false。

 

  2018-03-17 05:44:23

相关文章
相关标签/搜索