java學習筆記(8)——String類詳解
1.概述
String:字元串,使用一對""引起來表示。
- String聲明為final的,不可被繼承
- String實作了Serializable接口:表示字元串是支援序列化的。實作了Comparable接口:表示String可以比較大小
- String内部定義了final char[] value用于存儲字元串資料
- 通過字面量的方式(差別于new給一個字元串指派,此時的字元串值聲明在字元串常量池中)。
- 字元串常量池中是不會存儲相同内容(使用String類的equals()比較,傳回true)的字元串的。
2.String的不可變性
2.1 說明
- 當對字元串重新指派時,需要重寫指定記憶體區域指派,不能使用原有的value進行指派。
- 當對現的字元串進行連接配接操作時,也需要重新指定記憶體區域指派,不能使用原有的value進行指派。
- 當調用String的replace()方法修改指定字元或字元串時,也需要重新指定記憶體區域指派,不能使用原有的value進行指派。
public void test1(){
String s1 = "abc";//字面量的定義方式
String s2 = "abc";
s1 = "hello";
System.out.println(s1 == s2);//比較s1和s2的位址值
System.out.println(s1);//hello
System.out.println(s2);//abc
System.out.println("*****************");
String s3 = "abc";
s3 += "def";
System.out.println(s3);//abcdef
System.out.println(s2);
System.out.println("*****************");
String s4 = "abc";
String s5 = s4.replace('a', 'm');
System.out.println(s4);//abc
System.out.println(s5);//mbc
}
3.String執行個體化的不同方式
3.1 方式說明
- 方式一:通過字面量定義的方式
- 方式二:通過new + 構造器的方式
public void test2(){
//通過字面量定義的方式:此時的s1和s2的資料javaEE聲明在方法區中的字元串常量池中。
String s1 = "javaEE";
String s2 = "javaEE";
//通過new + 構造器的方式:此時的s3和s4儲存的位址值,是資料在堆空間中開辟空間以後對應的位址值。
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
System.out.println("***********************");
Person p1 = new Person("Tom",12);
Person p2 = new Person("Tom",12);
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true
p1.name = "Jerry";
System.out.println(p2.name);//Tom
}
-
String s = new String(“abc”);方式建立對象,在記憶體中建立了幾個對象?
兩個:一個是堆空間中new結構,另一個是char[]對應的常量池中的資料:“abc”
4. 字元串拼接方式指派的對比
4.1 說明
- 常量與常量的拼接結果在常量池。且常量池中不會存在相同内容的常量。
- 隻要其中一個是變量,結果就在堆中。
- 如果拼接的結果調用intern()方法,傳回值就在常量池中
@Test
public void test4(){
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3);//false
final String s4 = "javaEE";//s4:常量
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true
}
@Test
public void test3(){
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
String s8 = s6.intern();//傳回值得到的s8使用的常量值中已經存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
}
5.常用方法:
- int length():傳回字元串的長度: return value.length
- char charAt(int index): 傳回某索引處的字元return value[index]
- boolean isEmpty():判斷是否是空字元串:return value.length == 0
- String toLowerCase():使用預設語言環境,将 String 中的所字元轉換為小寫
- String toUpperCase():使用預設語言環境,将 String 中的所字元轉換為大寫
- String trim():傳回字元串的副本,忽略前導空白和尾部空白
- boolean equals(Object obj):比較字元串的内容是否相同
- boolean equalsIgnoreCase(String anotherString):與equals方法類似,忽略大小寫
- String concat(String str):将指定字元串連接配接到此字元串的結尾。 等價于用“+”
- int compareTo(String anotherString):比較兩個字元串的大小
- String substring(int beginIndex):傳回一個新的字元串,它是此字元串的從beginIndex開始截取到最後的一個子字元串。
- String substring(int beginIndex, int endIndex) :傳回一個新字元串,它是此字元串從beginIndex開始截取到endIndex(不包含)的一個子字元串。
public void test2() {
String s1 = "HelloWorld";
String s2 = "helloworld";
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2));
String s3 = "abc";
String s4 = s3.concat("def");
System.out.println(s4);
String s5 = "abc";
String s6 = new String("abe");
System.out.println(s5.compareTo(s6));//涉及到字元串排序
String s7 = "北京尚矽谷教育";
String s8 = s7.substring(2);
System.out.println(s7);
System.out.println(s8);
String s9 = s7.substring(2, 5);
System.out.println(s9);
}
@Test
public void test1() {
String s1 = "HelloWorld";
System.out.println(s1.length());
System.out.println(s1.charAt(0));
System.out.println(s1.charAt(9));
// System.out.println(s1.charAt(10));
// s1 = "";
System.out.println(s1.isEmpty());
String s2 = s1.toLowerCase();
System.out.println(s1);//s1不可變的,仍然為原來的字元串
System.out.println(s2);//改成小寫以後的字元串
String s3 = " he llo world ";
String s4 = s3.trim();
System.out.println("-----" + s3 + "-----");
System.out.println("-----" + s4 + "-----");
}
}
- boolean endsWith(String suffix):測試此字元串是否以指定的字尾結束
- boolean startsWith(String prefix):測試此字元串是否以指定的字首開始
- boolean startsWith(String prefix, int toffset):測試此字元串從指定索引開始的子字元串是否以指定字首開始
- boolean contains(CharSequence s):當且僅當此字元串包含指定的 char 值序列時,傳回 true
- int indexOf(String str):傳回指定子字元串在此字元串中第一次出現處的索引
- int indexOf(String str, int fromIndex):傳回指定子字元串在此字元串中第一次出現處的索引,從指定的索引開始
- int lastIndexOf(String str):傳回指定子字元串在此字元串中最右邊出現處的索引
- int lastIndexOf(String str, int fromIndex):傳回指定子字元串在此字元串中最後一次出現處的索引,從指定的索引開始反向搜尋
@Test
public void test3(){
String str1 = "hellowworld";
boolean b1 = str1.endsWith("rld");
System.out.println(b1);
boolean b2 = str1.startsWith("He");
System.out.println(b2);
boolean b3 = str1.startsWith("ll",2);
System.out.println(b3);
String str2 = "wor";
System.out.println(str1.contains(str2));
System.out.println(str1.indexOf("lol"));
System.out.println(str1.indexOf("lo",5));
String str3 = "hellorworld";
System.out.println(str3.lastIndexOf("or"));
System.out.println(str3.lastIndexOf("or",6));
//什麼情況下,indexOf(str)和lastIndexOf(str)傳回值相同?
//情況一:存在唯一的一個str。情況二:不存在str
}
替換:
22. String replace(char oldChar, char newChar):傳回一個新的字元串,它是通過用 newChar 替換此字元串中出現的所 oldChar 得到的。
23. String replace(CharSequence target, CharSequence replacement):使用指定的字面值替換序列 替換此字元串所比對字面值目标序列的子字元串。
24. String replaceAll(String regex, String replacement):使用給定的 replacement 替換此字元串所比對給定的正規表達式的子字元串。
25. String replaceFirst(String regex, String replacement):使用給定的 replacement 替換此字元串比對給定的正規表達式的第一個子字元串。
比對:
26. boolean matches(String regex):告知此字元串是否比對給定的正規表達式。
切片:
27. String[] split(String regex):根據給定正規表達式的比對拆分此字元串。
28. String[] split(String regex, int limit):根據比對給定的正規表達式來拆分此字元串,最多不超過limit個,如果超過了,剩下的全部都放到最後一個元素中。
public void test4(){
String str1 = "北京尚矽谷教育北京";
String str2 = str1.replace('北', '東');
System.out.println(str1);
System.out.println(str2);
String str3 = str1.replace("北京", "上海");
System.out.println(str3);
System.out.println("*************************");
String str = "12hello34world5java7891mysql456";
//把字元串中的數字替換成,,如果結果中開頭和結尾有,的話去掉
String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(string);
System.out.println("*************************");
str = "12345";
//判斷str字元串中是否全部有數字組成,即有1-n個數字組成
boolean matches = str.matches("\\d+");
System.out.println(matches);
String tel = "0571-4534289";
//判斷這是否是一個杭州的固定電話
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result);
System.out.println("*************************");
str = "hello|world|java";
String[] strs = str.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
System.out.println();
str2 = "hello.world.java";
String[] strs2 = str2.split("\\.");
for (int i = 0; i < strs2.length; i++) {
System.out.println(strs2[i]);
}
}
6. String與其它結構的轉換
6.1 與基本資料類型、包裝類之間的轉換
>String --> 基本資料類型、包裝類:調用包裝類的靜态方法:parseXxx(str)
基本資料類型、包裝類 --> String:調用String重載的valueOf(xxx)
public void test1(){
String str1 = "123";
// int num = (int)str1;//錯誤的
int num = Integer.parseInt(str1);
String str2 = String.valueOf(num);//"123"
String str3 = num + "";
System.out.println(str1 == str3);
}
6.2 與字元數組之間的轉換
String --> char[]:調用String的toCharArray()
char[] --> String:調用String的構造器
public void test2(){
String str1 = "abc123"; //題目: a21cb3
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
char[] arr = new char[]{'h','e','l','l','o'};
String str2 = new String(arr);
System.out.println(str2);
}
6.3 與位元組數組之間的轉換
編碼:String --> byte[]:調用String的getBytes()
解碼:byte[] --> String:調用String的構造器
編碼:字元串 -->位元組 (看得懂 —>看不懂的二進制資料)
解碼:編碼的逆過程,位元組 --> 字元串 (看不懂的二進制資料 —> 看得懂
說明:解碼時,要求解碼使用的字元集必須與編碼時使用的字元集一緻,否則會出現亂碼。
public void test3() throws UnsupportedEncodingException {
String str1 = "abc123中國";
byte[] bytes = str1.getBytes();//使用預設的字元集,進行編碼。
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk");//使用gbk字元集進行編碼。
System.out.println(Arrays.toString(gbks));
System.out.println("******************");
String str2 = new String(bytes);//使用預設的字元集,進行解碼。
System.out.println(str2);
String str3 = new String(gbks);
System.out.println(str3);//出現亂碼。原因:編碼集和解碼集不一緻!
String str4 = new String(gbks, "gbk");
System.out.println(str4);//沒出現亂碼。原因:編碼集和解碼集一緻!
}
6.4 與StringBuffer、StringBuilder之間的轉換
String -->StringBuffer、StringBuilder:調用StringBuffer、StringBuilder構造器
StringBuffer、StringBuilder -->String:①調用String構造器;②StringBuffer、StringBuilder的toString()
7 String、StringBuffer、StringBuilder三者的對比
- String:不可變的字元序列;底層使用char[]存儲
- StringBuffer:可變的字元序列;線程安全的,效率低;底層使用char[]存儲
- StringBuilder:可變的字元序列;jdk5.0新增的,線程不安全的,效率高;底層使用char[]存儲
7.1.StringBuffer與StringBuilder的記憶體解析
以StringBuffer為例:
String str = new String();//char[] value = new char[0];
String str1 = new String("abc");//char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底層建立了一個長度是16的數組。
System.out.println(sb1.length());//
sb1.append('a');//value[0] = 'a';
sb1.append('b');//value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
- 底層建立了一個長度是16的數組。
- 問題1. System.out.println(sb2.length());//3
-
問題2. 擴容問題:如果要添加的資料底層數組盛不下了,那就需要擴容底層的數組。
預設情況下,擴容為原來容量的2倍 + 2,同時将原數組中的元素複制到新的數組中。
指導意義:開發中建議大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
7.2.對比String、StringBuffer、StringBuilder三者的執行效率
從高到低排列:StringBuilder > StringBuffer > String
7.4.StringBuffer、StringBuilder中的常用方法
- 增:append(xxx)
- 删:delete(int start,int end)
- 改:setCharAt(int n ,char ch) / replace(int start, int end, String str)
- 查:charAt(int n )
- 插:insert(int offset, xxx)
- 長度:length();
- 周遊:for() + charAt() / toString()
備注:本文來自觀看尚矽谷視訊做的筆記。強烈推薦!