这段时间有不少关于String的帖子,也有很多很好的解释。我在这里就算是搜集一下,并简单地分析一下原因。一是我不熟悉JVM的底层规范,二是我觉得别人分析的很好,但是不能拘泥于这样分析,分析的目的是为了让我们明白其中的道理。
下面我列出参考的帖子,也方便大家去查看:
《深入研究java对String字符串对象的创建以及管理》;
还是靠程序来说话:
- publicclassVerifyString{
- publicstaticvoidmain(Stringargs[]){
- Stringstr1="IamaString";
- Stringstr2="IamaString";
- Stringstr3=newString("IamaString");
- Stringstr5="Iama";
- Stringstr6="String";
- Stringstr7=str5+str6;
- Stringstr8="Iama"+"String";
- Stringstr9=str3.intern();
- Stringstr10=str7.intern();
- if(str1==str2)
- System.out.println("str1andstr2arethesameString.");
- else
- System.out.println("str1andstr2arethedifferentStrings.");
- if(str1==str3)
- System.out.println("str1andstr3arethesameString.");
- else
- System.out.println("str1andstr3arethedifferentStrings.");
- if(str1==str7)
- System.out.println("str1andstr7arethesameString.");
- else
- System.out.println("str1andstr7arethedifferentStrings.");
- if(str1==str8)
- System.out.println("str1andstr8arethesameString.");
- else
- System.out.println("str1andstr8arethedifferentStrings.");
- if(str1==str9)
- System.out.println("str1andstr9arethesameString.");
- else
- System.out.println("str1andstr9arethedifferentStrings.");
- if(str1==str10)
- System.out.println("str1andstr10arethesameString.");
- else
- System.out.println("str1andstr10arethedifferentStrings.");
- }
- }
运行的结果是:
- str1andstr2arethesameString.
- str1andstr3arethedifferentStrings.
- str1andstr7arethedifferentStrings.
- str1andstr8arethesameString.
- str1andstr9arethesameString.
- str1andstr10arethesameString.
解释以上的输出结果,首先要理解一个叫String Pool的概念,虽然JVM没有明确提出这个概念,但是细想一下,别的语言String基本都是作为基本类型来处理的,而在Java中直接就是一个对象,然而奇怪的是对象能像基本类型那样直接赋常量。这就能看出Java设计者的那种取舍吧,毕竟作为对象来处理的话,效率没有基本类型那样高。我们不需要更多的理解,直接记住String str1 = "I am a String";是把"I am a String"扔到了字符串池中,然后把引用抛给str1,以后再有相同值的String变量也是这种赋值语句的,那么还是存在字符串池中,有就直接返回引用,没有就创建一个新的。所以说着语句就创建了一个String对象。再看下一个String str3 = new String("I am a String");这个创建了几个对象?两个!不要怀疑!一个是在new String("I am a String")创建在heap中的,另一个是str3也在heap中,它们所指向的字符数组是相同的,位于内存区的常量池中。关于这一点,请看大企鹅的这篇blog:《还是 String》。接下来看str7和str8,明明两个的值是一样的,为什么结果不一样呢?这就牵扯到Java编译器对于不同str8的优化了。因为str7右边的是两个变量,而不是直接的两个值,编译器就无法在编译期间知道str8的值,相反,str8对于编译器来说直接就是str8 = "I am a String"了,这样的两种不同的情况,就有不同的结果了。再看str3和str7都和返回否定的,而为什么str9和str10返回的是一致的呢?因为intern()方法是把执行该方法的引用拖到了字符串池中,当然了如果字符串池中有的话,就直接返回引用了。
总结一下就是:
1. 区分好String str1 = "I am a String"和String str3 = new String("I am a String")创建对象的数目和地方。
2. 了解String str1 = "I am a " + "String"是编译期间确定值的。
3. 了解intern()方法。