JAVA String对象的创建

String对象的创建是比较特殊的,普通对象创建都是在堆中创建,String对象确不一定,下面看一段代码

  1. public class StringTest1 {  
  2.     public static void main(String[] args) throws Exception{  
  3.         String a = "abc";  
  4.         String b = "abc";  
  5.         String c = "ab";  
  6.         String d = new String("ab");  
  7.         System.out.println("a=" + a);               //a=abc  
  8.         System.out.println("b=" + b);               //b=abc  
  9.         System.out.println("c=" + c);               //c=ab  
  10.         System.out.println("d=" + d);               //d=ab  
  11.         System.out.println("a==b is " + (a == b));  //a==b is true  
  12.         System.out.println("c==d is " + (c == d));  //c==d is false  
  13.           
  14.         Field field = String.class.getDeclaredField("value");  
  15.         field.setAccessible(true);  
  16.           
  17.         char[] valueA = (char[]) field.get(a);  
  18.         char[] valueB = (char[]) field.get(b);  
  19.         char[] valueC = (char[]) field.get(c);  
  20.         char[] valueD = (char[]) field.get(d);  
  21.         System.out.println("a.value(" + valueA.hashCode() + ")=" + Arrays.toString(valueA));      
  22.         //a.value([1829164700)=[a, b, c]  
  23.           
  24.         System.out.println("b.value(" + valueB.hashCode() + ")=" + Arrays.toString(valueB));      
  25.         //b.value([1829164700)=[a, b, c]  
  26.           
  27.         System.out.println("c.value(" + valueC.hashCode() + ")=" + Arrays.toString(valueC));      
  28.         //c.value([2018699554)=[a, b]  
  29.           
  30.         System.out.println("d.value(" + valueD.hashCode() + ")=" + Arrays.toString(valueD));      
  31.         //d.value([2018699554)=[a, b]  
  32.           
  33.         valueA[0] = ‘z‘;  
  34.         valueD[0] = ‘x‘;  
  35.         System.out.println("a=" + a);               //a=zbc  
  36.         System.out.println("b=" + b);               //b=zbc  
  37.         System.out.println("c=" + c);               //c=xb  
  38.         System.out.println("d=" + d);               //d=xb  
  39.     }  
  40. }  



a跟b都是“abc”,测试结果a跟b的引用是相等的,value数组也是相等的,改变a的第一位,b也跟着变了。

c跟d都是“ab”,但是两个引用是不相等的,d是用new创建的,这个时候才会在堆中创建对象,a,b,c三个引用都是直接指向常量池的对象的, 但是下面c和d的value似乎又是同一个数组,改变d的第一位,c也变了,说明d在堆中创建的对象还是指向常量池的,所以用new的话就多创建了个对 象。


还有一个经典的问题, String a = "a" + "b";创建了几个对象。

一般来说应该是3个吧,一个"a",一个"b",一个结果"ab",下面写一个简单的类

  1. public class StringTest2 {  
  2.     @SuppressWarnings("unused")  
  3.     public static void main(String[] args){  
  4.         String a = "a" + "b";  
  5.     }  
  6. }  


使用javap看一下字节码

  1. javap -c StringTest2.class  
  2. Compiled from "StringTest2.java"  
  3. public class test.StringTest2 {  
  4.   public test.StringTest2();  
  5.     Code:  
  6.        0: aload_0  
  7.        1: invokespecial #8                  // Method java/lang/Object."<init>":  
  8. ()V  
  9.        4: return  
  10.   
  11.   public static void main(java.lang.String[]);  
  12.     Code:  
  13.        0: ldc           #16                 // String ab  
  14.        2: astore_1  
  15.        3: return  
  16. }  


只有一个指令ldc           #16 ,从常量池里加常量#16,很明显这个常量就是ab,我就不去解析class文件了,应该是没错,直接反编译一下,得到的结果是

  1. package test;  
  2.   
  3. public class StringTest2  
  4. {  
  5.   public static void main(String[] args)  
  6.   {  
  7.     String a = "ab";  
  8.   }  
  9. }  


所以引用直接指向常量池"ab"了,就一个对象吗,可能是编译器优化的结果吧,如果有时间去单独把class文件一个字节一个字节解析出来结果应该更明了。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。