先看一个例子如果你会了那这篇文章你没必要看了,如果不会那请看下去,你一定会有收获:
String s = new String("hello");
String str1 = s+ "world";
String str3 = "helloworld";
system.out.println(srt1==str3);
String s = new String("hello");
String str1 = s+ "world";
String str2 = str1.intern();
String str3 = "helloworld";
system.out.println(srt1==str3);
String类具有很多构造函数,常用的有:
1.直接赋值一个字符串
2.new String(String original)
3.new String(char[] a)
4.new String(char[] a,in,int)
1.直接赋值时,先在常量池寻找是否有对应的字符串,若有,直接将引用变量指向常量池中字符串的地址;若无,则在常量池里面创建该字符串,再将其地址赋给引用变量。
2.new String(String original)创建时,先在堆中创建一个字符数组空间,然后再去常量池中寻找是否有对应的字符串,若有,则将常量池中该字符串赋给堆中的字符数组,然后将引用变量指向该数组;若无,则先在常量池里面创建该字符串,然后将常量池中该字符串赋给堆中的字符数组,然后将引用变量指向该数组。
1.以下情况下会在常量池里面直接生成helloworld的字符串,并将该字符串的地址赋值给引用变量str。
1)String str = "hello" + "world";
2)String str= "helloworld";
2.以下情况的字符串相加会先创建StringBuilder对象,然后调用StringBuilder的append()方法做字符串的拼接,并返回该StringBuilder对象给引用变量str,此时不会在常量池里面创建“helloworld”。ps:只要相加时,有一个加量为对象,则会创建StringBuilder进行append。
1) String str1 = "hello";
String str2 = "world";
String str = str1 +str2;
2) String str1 = "hello";
String str = str1 +"world";
3) String str = new String("hello") + new String("world");
4) String str = new String("hello") + "world";
因为不是所有的字符串创建方式都会在常量池中生成对应的字符串,而intern函数用于根据所给的字符串在常量池中创建对应的字符串。jdk7以后,调用intern方法时,如果该字符串已经存在于常量池中,则将常量池中的引用直接返回;如果不存在,则在常量池中生成一个对原字符串的引用。
String str1 = "helloworld";
String str2 = str1.intern();
str1==str2??? true 原因:两者都指向常量池中的“helloworld”
String str1 = new String("helloworld");
String str2 = str1.intern();
str1==str2??? false 原因:new一个String对象时,也会在常量池中创建对应的字符串。前者指向堆中的字符串对象,后者指向常量池中的字符串
以上两种情况都是字符串已经存在于常量池中的情况。
下面重点来了,刚才所说的:jdk7以后,调用intern方法时,如果该字符串已经存在于常量池中,则将常量池中的引用直接返回;如果不存在,则在常量池中生成一个对原字符串的引用。
看下面这两个例子:
String s = new String("hello");
String str1 = s+ "world";//通过创建Stringbuilder来实现拼接,这种情况下并不会在常量池中生成“helloworld”字符串。
String str3 = "helloworld";
str3==str1是否相等???答案是 false
原因:str1指向的的是堆中的StringBuilder对象,而str3指向的是常量池中的“helloworld”,所以两者不是同一对象。
在上面例子的基础上,向str3之前加入String str2 = str1.intern():
String s = new String("hello");
String str1 = s+ "world";
String str2 = str1.intern();
String str3 = "helloworld";
这种情况下,str3==str1是否相等???答案是 true。惊讶不?懵逼不?不急来分析分析。
同样的str1是通过创建Stringbuilder来实现拼接的,str1的指向并没有变,所以变的是str3的指向。而str3的指向会变,完全是因为调用了str1的intern方法。再来一遍:调用intern方法时,如果该字符串已经存在于常量池中,则将常量池中的引用直接返回;如果不存在,则在常量池中生成一个对原字符串的引用。由于str1创建后,常量池中并没有“helloworld”,所以会在常量池中生成一个对原字符串的引用,而这个引用实质上就是指向堆中的str1(StringBuilder对象)。而此时,创建str3的话,根据字符串的创建机制,str3就指向了str1,所以最终两者相等。