百度的面試官問
String A="ABC";
String B=new String("ABC");
這兩個值,A,B 是否相等,如果都往HashSet里面放,能放下嗎?
答:(a)A==B 的判斷為false;
(b)A.equals(B)為true ;因為值相等,所以都往HashSet里面放不下,只能放一個
問題:==與equals()的區別:
- ==:比較引用類型比較的是地址值是否相同
- equals:比較引用類型默認也是比較地址值是否相同,注意:String類重寫了equals()方法,比較的是內容是否相同。
String A = "ABC";內存會去查找永久代(常量池) ,如果沒有的話,在永久代中中開辟一塊兒內存空間,把地址付給棧指針,如果已經有了"ABC"的內存,直接把地址賦給棧指針;
因此
String str1="aa";
Srting str2="aa";
String Str3="aa";
....
這樣下去,str1==Str2==str3;會一直相等下去,(a) ==的判斷, (b) equals()的判斷;都相等,因為他們的地址都相等,因此只在常量池中有一份內存空間,地址全部相同;
而String str = new String("a");是根據"a"這個String對象再次構造一個String對象;在堆中從新new一塊兒內存,把指針賦給棧,
將新構造出來的String對象的引用賦給str。 因此 只要是new String(),則,棧中的地址都是指向最新的new出來的堆中的地址,
(a)“”==“” 是判斷地址的,當然不相同;
(b)至於equals,String類型重寫了 equals()方法,判斷值是否相等,明顯相等,因此 equals 是相等的;
這是String 重寫的equals:
* @see #compareTo(String) * @see #equalsIgnoreCase(String) */ 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; }
public class StringDemo2 { public static void main(String[] args) { String s1 = new String("hello"); String s2 = "hello"; System.out.println(s1 == s2);// false System.out.println(s1.equals(s2));// true } } **運行結果:** > false > true
代碼詳解
- 首先,通過main()方法進棧。
- 然后再棧中定義一個對象s1,去堆中開辟一個內存空間,將內存空間的引用賦值給s1,“hello”是常量,然后去字符串常量池 查看是否有hello字符串對象,沒有的話分配一個空間存放hello,並且將其空間地址存入堆中new出來的空間中。
- 在棧中定義一個對象s2,然后去字符串常量池中查看是否有”hello”字符串對象,有,直接把”hello”的地址賦值給s2.
- 即s1中存的是堆中分配的空間,堆中分配的空間中存的是字符串常量池中分配空間存放”hello”的空間的地址值。而s2中之間存的是字符串常量池中分配空間存放”hello”的空間的地址值。
- 由於s1與s2中存放的地址不同,所以輸出false。因為,類String重寫了equals()方法,它比較的是引用類型的 的值是否相等,所以輸出true。即結果為false、true。
Demo1
public class StringDemo1 { public static void main(String[] args) { String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1 == s2);// false System.out.println(s1.equals(s2));// true String s3 = new String("hello"); String s4 = "hello"; System.out.println(s3 == s4);// false System.out.println(s3.equals(s4));// true String s5 = "hello"; String s6 = "hello"; System.out.println(s5 == s6);// true System.out.println(s5.equals(s6));// true } }
Demo1詳解
s1~s6用equals()的比較不解釋,都是比較的值,均為true。以下講解==
- s1、s2:二者均為new出來的,各自在堆中分配有空間,並各自將內存地址賦值給s1、s2。空間地址不同,==比較為false。但是各自在堆中空間中保存的值均為在字符串常量池中的同一個對象的地址。根據Demo處的圖即解釋不難理解。
- s3、s4同上Demo出解釋。
- s5、s6都是在常量池中取值,二者都指向常量池中同一對象,其地址值相同,所以結果為true。
Demo2
public class StringDemo4 { public static void main(String[] args) { String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; System.out.println(s3 == s1 + s2);// false System.out.println(s3.equals((s1 + s2)));// true System.out.println(s3 == "hello" + "world");//false System.out.println(s3.equals("hello" + "world"));// true } }
Demo2詳解
equals()比較方法不解釋,比較值,均相等,均為true。
- s1與s2相加是先在字符串常量池中開一個空間,然后拼接,這個空間的地址就是s1與s2拼接后的地址。與s3的地址不同,所以輸出為false。
- s3與”hello”+”world”作比較,”hello”+”world”先拼接成”helloworld”,然后再去字符串常量池中找是否有”helloworld”,有,所以和s3共用一個字符串對象,則為true。
總結
- String s = new String(“hello”)會創建2(1)個對象,String s = “hello”創建1(0)個對象。
注:當字符串常量池中有對象hello時括號內成立! - 字符串如果是變量相加,先開空間,在拼接。
- 字符串如果是常量相加,是先加,然后在常量池找,如果有就直接返回,否則,就創建。