JavaEE - 09常用類
阿新 • • 發佈:2020-12-07
字串相關類
(1.1)String
(1.1.1)String特性
> String類: 代表字串。Java程式中的所有字串字面值(如"abc")都作為此類的例項實現。 > String是一個final類,不可被繼承。代表不可變的字元序列。 不可變性:當對字串重新賦值時,需要重新指定記憶體區域賦值,不能使用原有的value進行賦值。 當對現有的字串進行連線操作時,也需要重新指定記憶體區域賦值,不能使用原有的。 當呼叫String的replace()方法修改指定字元或字串時,也需要重新指定記憶體區域賦值。 > 字串是常量,用雙引號引起來表示。它們的值在建立之後不能更改。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage.*/ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L;
(1.1.2)String物件建立
String str = "hello"; // 本質上 this.value = "".value;String s1 = new String(); // this.value = original.value; String s2 = new String(String original); // this.value = Arrays.copyOf(value, value.length); String s3 = new String(char[] a); // this.value = Arrays.copyOfRange(value, offset, offset+count); String s4 = new String(char[] a, int startIndex, int count);
面試題: String str1 = "abc"與 String str2 = new String("abc")的區別
字串常量儲存在字串常量池,目的是共享;字串非常量物件儲存在堆中。
@Test public void test(){ String s1 = "abc"; String s2 = "abc"; String s3 = new String("abc"); String s4 = new String("abc"); // s1 和 s2 的資料"abc",字串常量池;s3 和 s4,在堆中開闢空間後對應的地址值。 System.out.println(s1 == s2); // true System.out.println(s1 == s3); // false System.out.println(s1 == s4); // false System.out.println(s3 == s4); // false }
@Test public void test2(){ Person p1 = new Person("Tom",12); Person p2 = new Person("Tom",12); System.out.println(p1.name == p2.name); // true
System.out.println(p1.name.equals(p2.name)); // true }
面試題:String s = new String("abc");方式建立物件,記憶體中建立了幾個物件?
兩個:一個是堆空間中new結構,另一個是char[]對應的常量池中資料:"abc"。
(1.1.3)字串拼接計算
> 字串拼接時常量與常量的拼接結果在常量池。且常量池中不會存在相同內容的常量。 > 字串拼接時只要其中有一個是變數,結果就在堆中。 > 如果拼接的結果呼叫intern()方法,返回值就在常量池中。
@Test public void test3(){ String s1 = "abc"; String s2 = "DEF"; String s3 = "abcDEF"; String s4 = "abc" + "DEF"; String s5 = s1 + "DEF"; String s6 = "abc" + s2; String s7 = s1 + s2; String s8 = (s1 + s2).intern(); System.out.println(s3 == s4); // true System.out.println(s3 == s5); // false System.out.println(s3 == s6); // false System.out.println(s5 == s6); // false System.out.println(s3 == s7); // false System.out.println(s5 == s7); // false
System.out.println(s3 == s8); // true
}
public class StringTest { String str = new String("good"); char[] ch = {'t','e','s','t'}; public void change(String str, char ch[]){ str = "test ok"; ch[0]= 'b'; } public static void main(String[] args) { StringTest st = new StringTest(); st.change(st.str, st.ch); System.out.println(st.str); // good System.out.println(st.ch); // best } }
@Test public void test4(){ String s = "0"; for(int i =1; i<=5;i++){ s += i; } System.out.println(s); // 常量池:"0" ,堆空間: "01","012","0123","01234","012345" String str = new String("0"); for(int i =1; i<=5;i++){ str += i; } System.out.println(str); // 常量池:"0", 堆空間: "0" ,"01","012","0123","01234","012345"
}
(1.1.4)String常用方法
- int length(): 返回字串的長度:return value.length
- char charAt(Int index):返回某索引處的字元 return value[index]
- boolean isEmpty(): 判斷字串是否為空。return value.length == 0
- String toLowerCase(): 使用預設語言環境的規則,將此 String 中的所有字元都轉換為小寫。
- String toLowerCase(Locale locale): 使用給定 Locale 的規則將,此 String 中的所有字元都轉換為小寫。
- String toUpperCase(): 使用預設語言環境的規則,將此 String 中的所有字元都轉換為大寫。
- String toUpperCase(Locale locale):使用給定 Locale 的規則,將此 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(不包含)的一個子字串。
- boolean endsWith(String suffix): 測試此字串是否以指定的字尾結束。
- boolean startsWith(String prefix): 測試此字串是否以指定的字首開始。
- boolean startsWith(String prefix, int toffset):測試此字串從指定索引開始的子字串是否以指定字首開始。
- booleancontains(CharSequence chars):判斷是否包含指定的字元系列。包含返回true。
- int indexOf(String str): 返回指定子字串在此字串中第一次出現處的索引。未找到返回-1。
- int indexOf(String str, int fromIndex): 返回指定子字串在此字串中第一次出現處的索引,從指定的索引開始。
- int lastIndexOf(String str): 返回指定子字串在此字串中最右邊出現處的索引。未找到返回-1。
- int lastIndexOf(String str, int fromIndex): 返回指定子字串在此字串中最後一次出現處的索引,從指定的索引開始反向搜尋。
- String replace(char oldChar, char newChar): 返回一個新的字串,它是通過用 newChar 替換此字串中出現的所有 oldChar 得到的。
- String replace(CharSequence target, CharSequence replacement):使用指定的字面值替換字串中所有匹配的子字串。
- String replaceAll(String regex, String replacement):使用給定的 replacement 替換此字串所有匹配給定的正則表示式的子字串。
- String replaceFirst(String regex, String replacement):使用給定的 replacement 替換此字串匹配給定的正則表示式的第一個子字串。
- boolean matches(String regex):告知此字串是否匹配給定的正則表示式。
- String[] split(String regex):根據給定正則表示式的匹配拆分此字串。
- String[] split(String regex, int limit):根據匹配給定的正則表示式來拆分此字串。最多不超過limit個,超過的話,剩餘全部放在最後一個元素中。
@Test public void test6(){ String str1 = "北京廠面積大"; String str3 = str1.replace("北京","上海"); System.out.println(str1); // 北京廠面積大 System.out.println(str3); // 上海廠面積大 String str = "12hello34world56java78mysql34"; String string = str.replaceAll("\\d+",",").replaceAll("^,|,$",""); System.out.println(string); // hello,world,java,mysql }
@Test public void test7(){ String str = "123456"; boolean matches = str.matches("\\d+"); System.out.println(matches); // true String tel = "0571-54789999"; boolean matches1 = tel.matches("0571-\\d{7,8}"); System.out.println(matches1); //true } @Test public void test8(){ String str = "abc|def|ghi"; String[] strs = str.split("\\|"); for(int i =0;i < strs.length; i++){ System.out.println(strs[i]); } String str2 = "abc.def.ghi"; String[] strs2 = str2.split("\\."); for(int i =0;i < strs2.length; i++){ System.out.println(strs2[i]); } }
(1.1.5)String與基本資料型別轉換
字串 -> 基本資料型別、包裝類 Integer包裝類的public static int parseInt(String s):可以將由"數字"組成的字串轉換成整型。 類似地,使用java.lang包中的Byte、Short、Long、Float、Double類使用相應的方法,將字串轉換為對應基本資料型別。 基本資料型別、包裝類 -> 字串 呼叫String類的public String valueOf(int n)可將int型轉換為字串。 相應的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b)可進行由資料型別到字串的轉換 static String valueOf(primitive data type x): 返回給定data type型別x引數的字串表示形式。 char[] toCharArray(): 將此字串轉換為一個新的字元陣列。@Test public void test(){ String str1 = "123"; int num = Integer.parseInt(str1); String str2 = String.valueOf(num); String str3 = "abc123"; char[] charArray = str3.toCharArray(); // String -> char[] for (int i = 0; i<charArray.length; i++){ System.out.println(charArray[i]); } char[] arr = new char[]{'h','e','l','l','o'}; String str4 = new String(arr); // char[] -> String System.out.println(str4); }
@Test public void test3(){ String str1 = "abc123"; byte[] bytes = str1.getBytes(); System.out.println(Arrays.toString(bytes)); // [97, 98, 99, 49, 50, 51] }
@Test public void test3() throws UnsupportedEncodingException { String str1 = "abc123中國"; byte[] bytes = str1.getBytes(); // 使用預設的字符集進行轉換, 字串-> 二進位制 【utf8 一個漢字三個位元組; gbk 一個漢字兩個位元組】
System.out.println(Arrays.toString(bytes)); //[97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67]
byte[] gbks = str1.getBytes("gbk");
System.out.println(Arrays.toString(gbks)); //[97, 98, 99, 49, 50, 51, -42, -48, -71, -6]
String str2 = new String(bytes); // 使用預設的字符集進行解碼, 二進位制 -> 字串
System.out.println(str2);
String str3 = new String(gbks,"gbk"); // 不指定字符集,編碼和解碼字符集不一致,導致亂碼
System.out.println(str3);
}
@Test public void test4(){ String s1 = "javaEESpring"; String s2 = "javaEE"; String s3 = s2 + "Spring"; System.out.println(s1 == s3); //false final String s4 = "javaEE"; String s5 = s4 + "Spring"; System.out.println(s1 == s5); //true }
(1.2)StringBuffer、StringBuilder
(1.2.1)String、StringBuffer、StringBuilder三者的異同 String:不可變的字元序列;底層使用char[]儲存 StringBuffer: 可變的字元序列;執行緒安全,效率低;底層使用char[]儲存 StringBuilder:可變的字元序列;jdk5.0新增,執行緒不安全,效率高。底層使用char[]儲存@Test public void test(){ StringBuffer sb1 = new StringBuffer("abc"); sb1.setCharAt(0,'m'); System.out.println(sb1); // mbc }
(1.2.2)StringBuffer原始碼分析
@Test public void test1(){ 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的字元陣列 sb1.append('a');// value[0] = 'a'; sb1.append('b');// value[1] = 'b'; System.out.println(sb1.length());// 2 sb1.capacity(); 16 StringBuffer sb2 = new StringBuffer("abc");// char[] value = new char["abc".length() + 16] System.out.println(sb2.length());// 3 sb2.capacity(); 19 }
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence { public StringBuffer() { super(16); } public StringBuffer(String str) { super(str.length() + 16); append(str); } @Override public synchronized int length() { return count; } @Override public synchronized int capacity() { return value.length; } }
擴容問題:底層陣列擴容:預設情況下,擴容為原來容量的2倍+2,同時將原有陣列的元素複製到新的陣列中。
abstract class AbstractStringBuilder implements Appendable, CharSequence { public void ensureCapacity(int minimumCapacity) { if (minimumCapacity > 0) ensureCapacityInternal(minimumCapacity); } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; } private int hugeCapacity(int minCapacity) { if (Integer.MAX_VALUE - minCapacity < 0) { // overflow throw new OutOfMemoryError(); } return (minCapacity > MAX_ARRAY_SIZE) ? minCapacity : MAX_ARRAY_SIZE; } }(1.2.3)StringBuffer類常用方法
- StringBuffer append(String s):將指定的字串追加到此字元序列。
- StringBuffer reverse():將此字元序列用其反轉形式取代。
- StringBuffer delete(int start, int end):移除此序列的子字串中的字元。
- StringBuffer insert(int offset, xxx):在指定位置插入xxx。
- StringBuffer replace(int start, int end, String str):使用給定 String 中的字元替換此序列的[start,end)子字串中的字元。
> 當append和insert時,如果原來value陣列長度不夠,可擴容。
> 如上這些方法支援方法鏈操作。
> 方法鏈原理:
@Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
- public int indexOf(String str)
- public String substring(int start, int end):返回一個從start開始到end結束的左閉右開區間的子字串。
- public int lenth()
- public char charAt(int n)
- public void setCharAt(int n, char ch)
@Test public void test2(){ StringBuffer sb1 = new StringBuffer("abc"); sb1.append(1); sb1.append('2'); System.out.println(sb1); // abc12 // sb1.delete(2,4); // ab2 // sb1.replace(2,4,"hello"); // abhello2 // sb1.insert(2,false); // abfalsec12 // sb1.reverse(); // 21cba String s2 = sb1.substring(1,3); //bc System.out.println(sb1.length()); //5 }
@Test public void test3(){ long startTime = 0L; long endTime = 0L; String text = ""; StringBuffer buffer = new StringBuffer(""); StringBuilder builder = new StringBuilder(""); startTime = System.currentTimeMillis(); for (int i=0; i<20000; i++){ buffer.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuffer執行時間:" + (endTime - startTime)); startTime = System.currentTimeMillis(); for (int i=0; i<20000; i++){ builder.append(String.valueOf(i)); } endTime = System.currentTimeMillis(); System.out.println("StringBuilder執行時間:" + (endTime - startTime)); startTime = System.currentTimeMillis(); for (int i=0; i<20000; i++){ text = text + i; } endTime = System.currentTimeMillis(); System.out.println("String執行時間:" + (endTime - startTime)); }
StringBuffer執行時間:5 StringBuilder執行時間:4 String執行時間:1474