常用類:String相關類與方法
尚硅谷JavaSE筆記-20

String類

String類特性

  • 表示字符串,內容以""包裹表示,稱為字面量的定義方式
  • 是一個final類,不可被繼承
  • 實現了Serializable接口,可以序列化
  • 實現了Comparable接口,表示可以比較大小
  • 內部定義了一個final char[] value數組來實際儲存數據,代表不可變的字符序列
    • 當我們用字面量(區別於new)定義了一個String str1="abc",相當於在方法區的字符串常量池中新增了一個"abc"序列,其為不可變的
    • 字符串常量池中不會儲存內容相同的字符串,比如我再新增一個str2="abc",則他們指向同一地址。
      • 延伸str6="a"+"bc",在聲明時字面量相加,等於常量跟常量拼接,都是在常量池,所以指向同樣位置
    • 而當我把str1="hello",或是用+拼接了其他內容,或是用replace取代了其中某一位的字,都是在常量池重新開闢空間,所謂不可變是這個意思
  • 如果是用String str3=new String("abc");方法生成,則是創在堆中,str3本身是指向堆的地址,去比==都是false。這個動作實際開闢了2個記憶體空間,它在堆中的value才指向常量池
    • 如果是new一個構造器生成時賦予的name傳入形參則跟new String是不同的,傳入形參也是類似於字面量的方法(因為顯然多在堆中開闢位置是毫無必要的)
    • 若是用+拼接有任何涉及到變量的,例如str4=str1+"def",都是相當於在堆空間new的操作,==去比較時全都false
    • 但如果變量被final修飾(正常不會有人這麼做),相當於這個變量存在常量池,又會是常量跟常量拼接,所以指向同樣位置
    • 若是用intern()方法,例如str5=str1.intern();,返回值是在常量池中,==比較是true

面試題-判斷結果

public class StringTest {
    String str = new String("good");
    char[] ch = {'t', 'e', 's', 't'};

    public void change(String str, char[] ch) {
        str = "bad";
        ch[0] = 'b';
    }

    public static void main(String[] args) {
        StringTest ex = new StringTest();
        ex.change(ex.str, ex.ch);
        System.out.println(ex.str); // good
        System.out.println(ex.ch); // best
    }
}
  • 切記傳形參時,引用類型傳的是地址值

  • 這個案例中形參只是正好也叫str而已,仔細看編譯器提示它應該會是灰色的,因為根本沒用到。

  • change的str是方法的形參,當屬性的str作為實參傳入時,把屬性str的地址給了形參

  • 形參str指向方法區造了一個"bad",但也沒用到然後隨著方法結束就消亡了。而屬性str仍然指向"good"

  • ch的狀況同理,它的地址被傳進去給了形參,形參跟實參都是指向同一個位置,地址指向的首位元素被改成了b,所以改變

  • 而若使用this.str = "bad";,形參叫啥名字、或有無這個string的形參根本都無所謂,是等同於在其他地方str = "bad";,在方法區常量池中重新開闢並重新賦值

String常用方法

  • int length():返回字數(一個中英文字母都是1)
  • char charAt(index):返回指定下標,小心越位
  • boolean isEmpty():返回是否空字串
  • boolean equals(Object obj):比較內容是否相同
  • boolean equalsIgnoreCase(String str):忽略大小寫比較內容是否相同
  • String concat(String str2):將str2拼接到後面,等同於"+"
  • int CompareTo(String str2):根據字符串編碼,拿調用者減去str2,可以用在排序
  • String toLowerCase():返回一份全轉為小寫的副本
  • String toUpperCase():返回一份全轉為大寫的副本
  • String trim():刪除前後的空格(中間的不算)
  • String substring(int 開始,結尾):根據下標取切片,左閉右開(含頭不含尾),結尾可省略
    • 即是說想從頭複製到尾形參是(0,length),注意超過會溢出
  • boolean endsWith(String str):返回是否以str結尾,區分大小寫,長度不限
  • boolean startsWith(String str):返回是否以str開頭,區分大小寫,長度不限
    • boolean startsWith(String str,int 下標):從指定下標開始(含)算
  • boolean contains(String str):返回是否包含一個以上str,區分大小寫,長度不限
  • int indexOf(String str):返回第一次匹配到str的下標,區分大小寫,長度不限。-1表示無
    • int indexOf(String str,int 下標):從指定下標開始(含)算
  • int lastIndexOf(String str):返回最後一次匹配到str的下標,區分大小寫,長度不限。-1表示無
    • int lastIndexOf(String str,int 下標):從指定下標開始(含)反向搜索(往左搜)
    • indexOflastIndexOf`返回相同,要嘛只存在一個解,要嘛都-1
  • String replace(string 舊,新):拿舊換新,區分大小寫,長度不限,預設全部取代
  • String replaceAll(string 正則,新):正則式替換,全部取代
  • String replaceFirst(string 正則,新):正則式替換,只取代第一個匹配
  • boolean match(string 正則):匹配是否符合正則
  • String[] split(string 正則):依照正則切分成字符串的數組
    • String[] split(string 正則,int limit):最多切成幾個元素,超過全放在最後

String類、基本數據轉換(複習)

  • String轉成基本數據、包裝類:Integer.parseInt(str)
  • 基本數據、包裝類轉String:String.valueOf(num)
    • 或是直接str2=num+""; // 是在堆裡
  • String轉成char[]:toCharArray()
    • 反轉,直接調用構造器= new String(arr)
  • String轉成byte[]:getBytes(),會返回位元組(字節),預設編碼utf-8(中文字大多是3位),utf-8本身是一個可變長度的編碼方式
    • getBytes(字元編碼):也可以指定編碼
    • 反轉,一樣調用構造器= new String(arr),形參也可以加,“指定編碼”

StringBuffer

面試重點題 字符序列 特性
String 不可變 改變等於新創,效率最低
StringBuffer 可變 線程安全、效率低
StringBuilder 可變 線程不安全、效率高

以下沒特別講都是StringBufferStringBuilder都共有的特性

  • 底層都是char[],但不同於Stringfinal修飾,StringBuffer的內容是可變的
  • new StringBufferStringBuilder時,capacity預設容量是16,注意容量不等於當前長度length
  • 當使用append拼接其他內容時,會先判斷是否超過容量,超過就創立一個新的數組容量是原有*2再+2,把原來的複製過去再拼接
  • 超過太多會考慮直接計算欲拼接完的字符長度來當新容量
  • 實際開發中,由於拼接複製效率低,最好在構造時就預想好需使用的容量,StringBuffer(int capacity)StringBuilder(int capacity)

StringBuffer常用方法

範圍沒特別說都是左閉右開(含頭不含尾),預設返回都是對this操作

都是StringBufferStringBuilder共有的方法

  • append(xxx):拼接,內容xxx都視為String拚上去
  • delete(int start,int end):刪除指定範圍的內容
  • replace(首,尾,str):取代指定範圍的內容為str
  • setCharAt(index,ch):修改指定位內容為ch
  • insert(index,str):從指定位置插入str,插完的index位即是str開頭
  • reverse():序列反轉
  • indexOf(String str):返回第一次匹配到str的下標,區分大小寫,長度不限。-1表示無

String算法題練習

public class CharCount {
    public static void main(String[] args) {
        // 获取一个字符串在另一个字符串中出现的次数。
        //比如:获取" ab"在"abkkcadkabkebfkabkskab" 中出现的次数
        String s0 = "abkkcadkabkebfkabkskab";
//        String s0 = "abkkcadkabkebfkabababababababababababababerg654erg654erg564abababkskab";
        String st = "ab";
        int count = 0;
        if (s0.contains(st)) {
            String s1 = s0.replace(st, "@");
            char[] c1 = s1.toCharArray();
            System.out.println(Arrays.toString(c1));
            for (int i = 0; i < c1.length; i++) {
                if (c1[i] == 64) {
                    count++;
                }
            }
        } else {
            count = 0;
        }
        System.out.println("次數=" + count);
    }
    /*
    老師思路:
    while包住,用indexOf(子str,index)
    匹配有,就count++,index+=子str長度
     */
}
public class Reverse {
    public static void main(String[] args) {
        // 将一个字符串进行反转。将字符串中指定部分进行反转。比如"abcdefg"反转为"abfedcg"
        int left = 2; // 擷取左邊保留位數
        int right = 1; // 擷取右邊倒數保留位數

        String str = "abcdefghijk";
        String s2 = str.substring(left, str.length() - right);
        System.out.println("欲反轉順序區=" + s2);

        char[] rs2 = s2.toCharArray();
        for (int i = 0; i < rs2.length / 2; i++) {
            char c = rs2[i];
            rs2[i] = rs2[rs2.length - 1 - i];
            rs2[rs2.length - 1 - i] = c;

        }
        System.out.println("反轉後=" + Arrays.toString(rs2));
        String rrs2 = new String(rs2);
        String str3 = str.substring(0, left) + rrs2 + str.substring(str.length() - right);
        System.out.println("最終=" + str3);
    }
}
/*
老師的思路一:
不切出sub數組,而是在for循環直接換位
for(int x=左,y=右;x<y;x++,y--){
char temp=arr[x];
arr[x]=arr[y]
...

思路二:
切出來,倒著遍歷數組,拼成一個反著的string,再接回去

思路三:
切出來,用stringBuilder裝,反轉
 */
public class Contain {
    public static void main(String[] args) {
        // 4.获取两个字符串中最大相同子串。比如:
        //str1 = "abcwerthelloyuiodef";str2 = "cvhellobnm"
        //前提,只存在一解
        //提示:将短的那个串进行长度依次递减的子串与较长的串比较。
        String str1 = "abcwerthelloyuiodef";
        String str2 = "cvhellobnm";
        String ans = "";
        for (int i = 0; i < str2.length(); i++) {
            String str3 = str2.substring(i);
            if (str1.contains(str3)) {
                ans = str3;
                break;
            } else {
                String str4 = str2.substring(i, str2.length() - 1 - i);
                if (str1.contains(str4)) {
                    ans = str4;
                    break;
                }
            }
        }
        System.out.println("ans=" + ans);

    }

    /*
    老師思路:
用兩個循環包住,外部控制位數從長度--,內部一個個去切,直到contains符合
     */
}

小結

  • String類的不可變性:底層是一個final char[],長度跟內容自然不可變,改變都是新造一個重給地址

上次修改於 2021-12-05