一:String
直接賦值和使用new的區別
String str = new String();
此時JVM
Demo_01_String
//直接賦值
String str1 = "hello";
String str2 = "hello";
String str3 = "world";
System.out.println("string==:"+(str1 == str2));//true:二者都指向常量池中同一對象,其地址值相同
System.out.println("string==:"+(str2 == str3));//false
System.out.println("string.equals:"+str1.equals(str2));//true
System.out.println("str1地址:"+str1.hashCode()); //99162322
System.out.println("str2地址:"+str2.hashCode()); //99162322
System.out.println("str3地址:"+str3.hashCode()); //113318802
// new String
String str4 = new String("hello");
String str5 = new String("hello");
String str6 = new String("world");
System.out.println("string==:"+(str1 == str4));//false:存放的地址不同
System.out.println("string==:"+(str4 == str5));//false:比較兩個包裝類的引用是否指向同一個對象,即在堆中的地址是否相同
System.out.println("string.equals:"+str1.equals(str4));//true 比較引用類型的值是否相等
System.out.println("string.equals:"+str4.equals(str5));//true
System.out.println("str4地址:"+str4.hashCode()); //99162322
System.out.println("str5地址:"+str5.hashCode()); //99162322
System.out.println("str6地址:"+str6.hashCode()); //113318802
//字符串相加
String strConst = str2 + str3;//是先加,然後在常量池找
String strNew = str5 + str6;//先開空間,再拼接
System.out.println(strConst.hashCode());
System.out.println(strNew.hashCode());
System.out.println("字符串相加後比較:"+(strConst == strNew)); //
System.out.println("字符串相加後比較:"+strConst.equals(strNew));
Demo_02_StringBuffer
StringBuffer sbf1 = new StringBuffer("hello");
StringBuffer sbf2 = new StringBuffer("hello");
StringBuffer sbf3 = new StringBuffer("world");
System.out.println("stringBuffer==:"+(sbf1 == sbf2)); //false
System.out.println("stringBuffer.equals:"+sbf1.equals(sbf2)); //false
System.out.println("stringBuffer.equals:"+sbf2.append(sbf3)); //拼接
Demo_03_StringBuilder
StringBuilder sbu1 = new StringBuilder("hello");
StringBuilder sbu2 = new StringBuilder("hello");
StringBuilder sbu3 = new StringBuilder("world");
System.out.println("stringBuilder==:"+(sbu1 == sbu2)); //false
System.out.println("stringBuilder.equals:"+sbu1.equals(sbu2)) //false
System.out.println("stringBuilder.equals:"+sbu2.append(sbu3));
- 由於String變量實際上是對一個String對象的引用(指向常量池),所以兩個通過new生成的String變量永遠是不相等的(因爲new生成的是兩個對象,其(在堆中的)內存地址不同)。
- String是final類,其值是不可變的,看以下板栗,只是改變了賦值地址;
// 1. 重新賦值
String str1 = "hello";
System.out.println("str1原本地址:"+str1.hashCode()); //99162322
str1 = "java";
System.out.println("str1改變後的地址:"+str1.hashCode()); //3254818
重新賦值後str1指向新地址,但舊地址中保存的"world"依舊存在,但已經不再是str1所指向的,str1已經指向了其它地址。
所有對String類型進行改變的時候都會重新生成一個新的String對象,如果字符串的內容經常改變,而且不考慮多線程的話,建議使用StringBuilder
// 2. 字符串拼接後地址有無改變?
String strConst = str2 + str3;//是先加,然後在常量池找
String strNew = str5 + str6;//先開空間,再拼接
System.out.println("字符串拼接後的地址:"+strConst.hashCode()); //變成-1524582912
System.out.println("字符串拼接後的地址:"+strNew.hashCode()); //變成-1524582912
System.out.println("sbf3原本地址:"+sbf3.hashCode()); //27134973
System.out.println("sbf3拼接後:"+sbf2.append(sbf3));
System.out.println("sbf3拼接後的地址:"+sbf3.hashCode()); //還是sbf3的地址27134973
查看源碼可知String重寫了equals()方法,但StringBuffer和StringBuilder沒有
看JDK怎麼說
StringBuffer
- 是線程安全的可變字符序列,可將字符串緩衝區安全地用於多個線程,可以在必要時對這些方法進行同步;
- 主要操作是 append 和 insert 方法;
- 沒有重寫equals方法
StringBuilder
- 此類提供一個與 StringBuffer 兼容的 API,但不保證同步;
- 該類被設計用作 StringBuffer 的一個簡易替換,用在字符串緩衝區被單個線程使用的時候,這樣比buffer快
- 主要操作和buffer一樣
- 沒有重寫equals方法
總結
- String = 操作少量的數據
- StringBuilder = 單線程操作字符串緩衝區 下操作大量數據;線程非安全的
- StringBuffer = 多線程操作字符串緩衝區 下操作大量數據;線程安全的