這系列博文主要是將自己之前學習的一些java基礎內容進行歸納與總結。
常用方法
int length() // 獲取長度
char charAt(int index) // 獲取對應角標的字符
int indexOf(String str) // 獲取對應角標
String substring(int beginIndex, int endIndex) // 截取區間返回 包含開頭不包含結尾
String[] split(String regex, int limit) // 根據正則表達式分隔字符,limit應用次數
String trim() // 忽略前後空白
String replace(char oldChar, char newChar) // 替換
char[] toCharArray() // 分解成字符數組
String intern() // 判斷常量池是否存在該字符串,如果存在則返回,否則在常量池記錄首次出現的引用(jdk1.7後)
Sting對equals方法的重寫
// Object的equals方法 直接通過==比較內存地址
public boolean equals(Object obj) {
return (this == obj);
}
// String對equals方法進行了重寫 先比較內存地址如果不相等再比較字符串值是否相同
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
.... // 逐個char進行比較
}
}
String的比較
String s1 = new String("aaa");
String s2 = "aaa";
System.out.println(s1 == s2); // false
s1 = new String("bbb").intern();
s2 = "bbb";
System.out.println(s1 == s2); // true
s1 = "ccc";
s2 = "ccc";
System.out.println(s1 == s2); // true
s1 = new String("ddd").intern();
s2 = new String("ddd").intern();
System.out.println(s1 == s2); // true
s1 = "ab" + "cd";
s2 = "abcd";
System.out.println(s1 == s2); // true
String temp = "hh";
s1 = "a" + temp;
// 如果調用s1.intern 則最終返回true
s2 = "ahh";
System.out.println(s1 == s2); // false
temp = "hh".intern();
s1 = "a" + temp;
s2 = "ahh";
System.out.println(s1 == s2); // false
temp = "hh".intern();
s1 = ("a" + temp).intern();
s2 = "ahh";
System.out.println(s1 == s2); // true
s1 = new String("1"); // 同時會生成堆中的String對象 以及常量池中的"1",但是此時s1是指向堆內存的String對象
s1.intern(); // 返回的是常量池中的已經存在"1"的引用
s2 = "1"; // 還是指向常量池中已存在的"1"
System.out.println(s1 == s2); // false
// 先調用intern
String s3 = new String("1") + new String("1"); // 此時生成了四個對象 常量池中的"1" + 2個堆中的"1" + s3指向的堆中的對象(注此時常量池不會生成"11")
s3.intern(); // jdk1.7之後,常量池不僅僅可以存儲對象,還可以存儲對象的引用,會直接將s3的地址存儲在常量池
String s4 = "11"; // jdk1.7之後,常量池中的地址其實就是s3的地址
System.out.println(s3 == s4); // jdk1.7之前false, jdk1.7之後true
// 後調用intern
s3 = new String("2") + new String("2");
s4 = "22"; // 常量池中不存在22,所以會新開闢一個存儲22對象的常量池地址
s3.intern(); // 常量池22的地址和s3的地址不同,若 s3 = s3.intern() 則爲true
System.out.println(s3 == s4); // false
String在內存中的對象創建
- 字符串相加如果沒有任何變量參與,則編譯器對String做了優化,會直接拼接轉化爲一個字符串
- 若有變量參與則是通過new StringBuild().append()相加
- new String(“E”) + new String(“F”) 一共創建了五個變量
String s1 = "A" + "B" + "C"; // 直接在常量池中創建 "ABC"
// 字節碼:
Code:
0: ldc #2 // String ABC
2: astore_1
3: return
String s2 = s1 + "D"; // 在堆中new StringBuilder,通過append相加
// 字節碼:
Code:
0: ldc #2 // String ABC
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String D
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_2
23: return
String s3 = new String("E") + new String("F"); // 創建了五個對象, 常量池中的"E"、"F",堆中的"E"、"F",s3指向堆中的對象
// 字節碼:
Code:
0: new #2 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: new #4 // class java/lang/String
10: dup
11: ldc #5 // String E
13: invokespecial #6 // Method java/lang/String."<init>":(Ljava/lang/String;)V
16: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: new #4 // class java/lang/String
22: dup
23: ldc #8 // String F
25: invokespecial #6 // Method java/lang/String."<init>":(Ljava/lang/String;)V
28: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
31: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: astore_1
35: return
IDEA中在控制檯打印執行的字節碼
在Setting中配置External Tools
參數說明
Name: Show Byte Code (隨意)
Program: C:\Program Files\Java\jdk1.8.0_144\bin\javap.exe (jdk bin目錄下的javap.exe)
Arguments: -c $FileClass$ (照填)
Working directory: $OutputPath$ (照填)
然後右鍵執行即可