1. 程式人生 > 實用技巧 >JavaEE - 09常用類

JavaEE - 09常用類

字串相關類

(1.1)String

(1.1.1)String特性

> String類: 代表字串。Java程式中的所有字串字面值(如"abc")都作為此類的例項實現。 > String是一個final類,不可被繼承。代表不可變的字元序列 不可變性:當對字串重新賦值時,需要重新指定記憶體區域賦值,不能使用原有的value進行賦值。 當對現有的字串進行連線操作時,也需要重新指定記憶體區域賦值,不能使用原有的。 當呼叫String的replace()方法修改指定字元或字串時,也需要重新指定記憶體區域賦值。 > 字串是常量,用雙引號引起來表示。它們的值在建立之後不能更改。
> String物件的字元內容是儲存在一個字元陣列value[]中的。 > 通過字面量的方式(區別於new)給一個字串賦值,此時的字串值宣告在字串常量池中。 > 字串常量池中是不會儲存相同內容的字串的。 > String實現了Serializable,表示支援序列化;實現了Comparable,表示可以比較大小。

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