編程語言中的問題很多時候我們看似懂,實際不懂,因為很多時候看不到更多的情況,從而缺少對這些看不到的情況的認知和解釋。
今天mark一下String和new String()的區別。其實很簡單。
String s1 = new String("string") // 這是一個對象,對象存放在堆里面
String s2 = "string" //這是一個字符串常量,存放在常量池中,也就是方法區里面
String s3 = "string" // ....
以上就是這兩個最大的區別。每一個對象有自己的內存地址;而字符串常量雖然可能變量名不同,但是只要常量的值相同,他們的內存地址都是常量池中的那一個內存地址,是等同的。
所以s2 == s3 是true,s1 == s2 是false,而s1.equals(s2)是true。
“==” -> 代表同一個東西(如對象,常量等等)
“.equals()” -> 代表變量所表示的值相同。也就是比較變量的hash值
注意一點的是:常量池這個東西,是針對一個java進程來說的,所以不管一個常量在哪里:在文件 A.java 也好,文件B.java也好,不管這個變量是一個什么類型:private也好,static也好,只要這些文件運行在了一個java進程中並且包含相同值得字符串常量(更大范圍的說是常量),他們就等是相等(==)的,都指向同一個內存地址。(當然,出現新的字符串常量就會在常量池中開辟新的地址了)
引用深入理解Java虛擬機的原話:“運行時常量池(Runtime Constant Pool)是方法區的一部分。class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法去的運行時常量池中存放。”
代碼測試:不同類,不同文件中的不同變量名的相同值得字符串常量
public class App { private static String aString = "abc"; public static void main(String[] args) { String aString = "abc"; String bString = new String("abc"); String cString = "abc"; System.out.println(aString == new T().bString); System.out.println(aString == T.aString); System.out.println(aString == App.aString); System.out.println(aString == cString); System.out.println(aString == bString); System.out.println(aString.equals(bString)); } } class T { static String aString = "abc"; String bString = "abc"; }
程序輸出:
true true true true false
true
考慮一點的是:對於常量來說"=="和"equals"有沒有效率上的差別的?答案是沒有,測試代碼:
public class App { private static String aString = "abc"; public static void main(String[] args) { String aString = "abc"; String bString = new String("abc"); String cString = "abc"; long ctimes = 1000 * 1000 * 1000 * 1000 * 1000; long time1 = System.currentTimeMillis(); for (long i = 0; i < ctimes; i++) { if (aString == cString) { } } long time2 = System.currentTimeMillis(); for (long i = 0; i < ctimes; i++) { if (aString.equals(cString)) { } } long time3 = System.currentTimeMillis(); System.out.println("== time spent = " + (time2 - time1)); System.out.println("equals time spent == " + (time3 - time2)); } }
輸出結果沒有差別,原因其實很簡單,我們去看equals的源碼:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
這下清楚了!!其實this == anObject跟==沒有任何區別的。