这段时间有不少关于String的帖子,也有很多很好的解释。我在这里就算是搜集一下,并简单地分析一下原因。一是我不熟悉JVM的底层规范,二是我觉得别人分析的很好,但是不能拘泥于这样分析,分析的目的是为了让我们明白其中的道理。
下面我列出参考的帖子,也方便大家去查看:
《深入研究java对String字符串对象的创建以及管理》;
还是靠程序来说话:
- public class VerifyString {
- public static void main(String args[]){
- String str1 = "I am a String";
- String str2 = "I am a String";
- String str3 = new String("I am a String");
- String str5 = "I am a ";
- String str6 = "String";
- String str7 = str5 + str6;
- String str8 = "I am a " + "String";
- String str9 = str3.intern();
- String str10 = str7.intern();
- if(str1 == str2)
- System.out.println("str1 and str2 are the same String.");
- else
- System.out.println("str1 and str2 are the different Strings.");
- if(str1 == str3)
- System.out.println("str1 and str3 are the same String.");
- else
- System.out.println("str1 and str3 are the different Strings.");
- if(str1 == str7)
- System.out.println("str1 and str7 are the same String.");
- else
- System.out.println("str1 and str7 are the different Strings.");
- if(str1 == str8)
- System.out.println("str1 and str8 are the same String.");
- else
- System.out.println("str1 and str8 are the different Strings.");
- if(str1 == str9)
- System.out.println("str1 and str9 are the same String.");
- else
- System.out.println("str1 and str9 are the different Strings.");
- if(str1 == str10)
- System.out.println("str1 and str10 are the same String.");
- else
- System.out.println("str1 and str10 are the different Strings.");
- }
- }
运行的结果是:
- str1 and str2 are the same String.
- str1 and str3 are the different Strings.
- str1 and str7 are the different Strings.
- str1 and str8 are the same String.
- str1 and str9 are the same String.
- str1 and str10 are the same String.
解释以上的输出结果,首先要理解一个叫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()方法。