轉載:https://blog.csdn.net/andychen314/article/details/50857313
答案是 兩個對象,要理解這個,就要知道string類的工作原理。下面來慢慢分析一下:
-
public class StringTest {
-
public static void main(String[] args){
-
String s1= "Hello";
-
-
String s2= "Hello";
-
-
String s3= new String( "Hello");
-
-
System.out.println( "s1和s2 引用地址是否相同:"+(s1 == s2));
-
System.out.println( "s1和s2 值是否相同:"+s1.equals(s2));
-
-
System.out.println( "s1和s3 引用地址是否相同:"+(s1 == s3));
-
System.out.println( "s1和s3 值是否相同:"+s1.equals(s3));
-
}
-
}
s1和s2 引用地址是否相同:true
s1和s2 值是否相同:true
s1和s3 引用地址是否相同:false
s1和s3 值是否相同:true
上面程序中的"=="是判斷兩個對象引用的地址是否相同,也就是判斷是否為同一個對象,s1與s2 返回為true,s1與s3返回則是false。說明s1與s2 引用的同一個對象的地址,s3則與其它兩個引用不是同一個對象地址。
原因是Java為了避免產生大量的String對象,設計了一個字符串常量池。工作原理是這樣的,創建一個字符串時,JVM首先為檢查字符串常量池中是否有值相等的字符串,如果有,則不再創建,直接返回該字符串的引用地址,若沒有,則創建,然后放到字符串常量池中,並返回新創建的字符串的引用地址。所以上面s1與s2引用地址相同。那為什么s3與s1、s2引用的不是同一個字符串地址呢? String s3=new String("Hello"); JVM首先是在字符串常量池中找"Hello" 字符串,如果沒有創建字符串常量,然后放到常量池中,若已存在,則不需要創建;當遇到 new 時,還會在內存(不是字符串常量池中)上創建一個新的String對象,存儲"Hello",並將內存上的String對象引用地址返回,所以s3與s1、s2引用的不是同一個字符串地址。
說到這里,可能有同學會問,放在常量池中會不會存在線程安全的問題?Java的工程師們早就考慮到了,String類是一個不可變對象,其它有兩層意思:一是String類是一個final類,不能產生一個String的子類;二是在String類中提供的所有方法中,如果有String返回值就會創建一個String對象,不對原對象進行修改,這就保證了原對象不可改變。
了解了String類的工作原理,回歸問題本身。
在String的工作原理中,已經提到了,new 一個String對象,是需要先在字符串常量中查找相同值或創建一個字符串常量,然后再在內存中創建一個String對象,所以 String str = new String("xyz"); 會創建兩個對象。