1、創建String的兩種方式
String s1 = "abc";
String s2 = new String("abc");
2、String不能被繼承,因爲String類被final修飾
String的對象一旦被創建,則不能修改,是不可變的,所謂的修改其實是創建了新的對象,所指向的內存空間不變,因爲String是不可變類,所以可以安全的用於多線程中。
3、比較兩個字符串的方法
String內部實現了Comparable接口,有兩個比較方法:compareTo(String anotherString) 和compareToIgnoreCase(String str)
①、compareTo()方法
與傳入的anotherString字符串進行比較,如果小於傳入的字符串返回負數,如果大於則返回正數。當兩個字符串值相等時,返回0,此時eqauls方法會返回true。
②、compareToIgnoreCase()方法
該方法與compareTo方法類似,區別只是內部利用了toUpperCase等方法進行了大小寫轉換後進行比較。
4、String、StringBuilder、StringBuffer的區別
①、String是不可變類,每當我們對String進行操作的時候,總是會創建新的字符串。操作String很耗資源,所以Java提供了兩個工具類來操作String:StringBuffer和StringBuilder。
②、StringBuffer,也被final修飾,不可被繼承,但是它是可變類,絕大多數方法都進行了同步處理。
③、StringBuilder,StringBuilder是JDK1.5發佈的,它和StringBuffer本質上沒什麼區別,就是去掉了保證線程安全的那部分,減少了開銷。
5、字符串常量池
例一:
public static void main(String[] args){
String s1 = "a";
String s2 = "a";
System.out.println(s1 == s2); //true,比較地址值,都在常量池,相等
System.out.println(s1.equals(s2)); //true,equals中,先判斷兩個對象的地址值,地址值相同,默認就是同一個對象,不會繼續equals中的具體值是否相等的判斷了,直接會返回true。
}
例二:
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); //false
System.out.println(s1.equals(s2)); //true
例三:
String s1 = "a" + "b" + "c";
String s2 = "abc";
System.out.println(s1 == s2); //true 地址值相同,都是常量,在常量池裏面
System.out.println(s1.equals(s2)); //true 地址值相同,默認同一個對象,值當然也是相等的。
例四:
String s1 = "ab";
String s2 = "abc";
String s3 = s1 + "c";
System.out.println(s3 == s2); //false 不相等,s1是變量,編譯的時候確定不了值,在內存中會創建值,s3在堆內存中,。s2在常量池,所以不相等。
System.out.println(s3.equals(s2)); //true 比較兩個對象的值相等。
例五:
String s1 = "a";
String s2 = "a";
String s3 = "a" + s2;
String s4 = "a" + "a";
String s5 = s1 + s2;
//表達式只有常量時,編譯期完成計算
//表達式有變量時,運行期才計算,所以地址不一樣
System.out.println(s3 == s4); //false
System.out.println(s3 == s5); //false
System.out.println(s4 == "aa"); //true
例六:
String s3 = new String("xyz");
String s4 = new String("xyz");
System.out.println(s3==s4);
對例六解釋如下:
結果是 false
採用new關鍵字新建一個字符串對象時,JVM首先在字符串池中查找有沒有"xyz"這個字符串對象,如果有,則不在池中再去創建"xyz"這個對象了,直接在堆中創建一個"xyz"字符串對象,然後將堆中的這個"xyz"對象的地址返回賦給引用s3,這樣,s3就指向了堆中創建的這個"xyz"字符串對象;如果沒有,則首先在字符串池中創建一個"xyz"字符串對象,然後再在堆中創建一個"xyz"字符串對象,然後將堆中這個"xyz"字符串對象的地址返回賦給s3引用,這樣,s3指向了堆中創建的這個"xyz"字符串對象。s4則指向了堆中創建的另一個"xyz"字符串對象。s3 、s4是兩個指向不同對象的引用,結果當然是false。
例七:
String s1 = "abc";
StringBuffer s2 = new StringBuffer(s1);
System.out.println(s1.equals(s2));
//輸入false,因爲s2不是String類型,String的equals方法進行了類型判斷
6、String的intern()方法
當intern()方法被調用,如果字符串池中含有一個字符串和當前調用方法的字符串eqauls相等,那麼就會返回池中的字符串。如果池中沒有的話,則首先將當前字符串加入到池中,然後返回引用。
String s1 = "abc";
String s2 = new String("abc");
String s3 = s2.intern();
System.out.println(s1 ==s2); // false
System.out.println(s1 == s3); //true
7、字符串創建對象的問題
下面的代碼將創建幾個字符串對象。
String s1 = new String("Hello");
String s2 = new String("Hello");
答案是3個對象.
第一,行1 字符串池中的“hello”對象。
第二,行1,在堆內存中帶有值“hello”的新字符串。
第三,行2,在堆內存中帶有“hello”的新字符串。這裏“hello”字符串池中的字符串被重用。
String s = new String("abc");
上述語句可能會創建一個或兩個對象,當字符串常量池中已經存在了“abc",則只會創建一個new String對象;如果字符串池中不存在"abc",則會先在字符串池中創建"abc",再在堆中創建new String對象。