Java字符串里的 ==


      String str1 = "abc";
      String str2 = "abc";
      String str3 = "a" + "bc";       

      System.out.println(str1 == str2);
      System.out.println(str1 == "a" + "bc");
      System.out.println(str1 == new String("abc"));      
System.out.println(new String("ab")+"c" == new String("ab")+"c");

输出
true
true
false
false

一般用来比较字符串是否相同的equals()是比较字符串的内容,即在堆中的字符序列。而 == 则是比较两个字符串的内存地址是否相同(堆中的引用)。

第一个true很容易理解。str1和str2都是在内存的字符串常量池中。

字符串常量池:

  • 为了减少在jvm中创建的字符串的数量,字符串类维护了一个字符串常量池,字符串常量池(String pool)是Java堆内存中一个特殊的存储区域;
  • 当创建String对象时,jvm会先检查字符串常量池,如果这个字符串的常量值已经存在在池中了,就直接返回池中对象的引用,如果不在池中,就会实例化一个字符串并放入池中;
  • 常量池:用于保存java在编译期就已经确定的,已经编译的class文件中的一份数据。包括了类、方法、接口中的常量,也包括字符串常量,如String s = "a"这种声明方式;
第二个true:看上去“a"+"bc"是经过运算的,理应生成一个新的对象。但为什么它们却是相等的呢?这是因为“a"+"bc"这种只包含常量的字符串连接符创建字符串的也是常量。它们在编译器编译的时候就直接计算完成丢进了常量池里面。所以他们对应了同一个引用。
 
三个False:
第一个false很显然,使用了new就代表这个对象会存储在堆上。引用自然不会和在常量池中的对象一样。
 
第二个false则是因为在运行期"ab"+"c"操作实际上是编译器创建了StringBuilder对象进行了append操作后通过toString()返回了一个字符串对象存在heap上。
 
更多例子:
String s0 = "111";              //pool
String s1 = new String("111");  //heap
final String s2 = "111";        //pool 
String s3 = "sss111";           //pool
String s4 = "sss" + "111";      //pool
String s5 = "sss" + s0;         //heap 
String s6 = "sss" + s1;         //heap
String s7 = "sss" + s2;         //pool
String s8 = "sss" + s0;         //heap
 
System.out.println(s3 == s4);   //true
System.out.println(s3 == s5);   //false
System.out.println(s3 == s6);   //false
System.out.println(s3 == s7);   //true
System.out.println(s5 == s6);   //false
System.out.println(s5 == s8);   //false
对于final String s2 = "111",是一个用final修饰的变量,在编译期就已知了,在包含变量的字符串连接符"a"+s2时直接用常量"111"来代替s2,等效于"a"+"111",在编译期就已经生产了字符串对象"a111"对象在常量池中。


参考:
https://www.jianshu.com/p/039d6df30fea

 
 
原文地址:https://www.cnblogs.com/Nullc/p/12692837.html