主頁 > 後端開發 > String類菜鳥級教程(字串常量池及不可變,StringBuffer 和 StringBuilder)

String類菜鳥級教程(字串常量池及不可變,StringBuffer 和 StringBuilder)

2021-10-08 08:23:24 後端開發

文章目錄

  • 前言
  • 1.創建字串
  • 2.字串比較相等
    • 2.1字串傳參
  • 3.字串常量池
  • 4.字串創建實體分析
  • 5.理解字串不可變
  • 6.字符, 位元組與字串
    • 6.1字符與字串
    • 6.2位元組與字串
  • 7.字串常見操作
    • 7.1字串比較
    • 7.2字串查找
    • 7.3字串替換
    • 7.4字串拆分
    • 7.5字串截取
    • 7.6其他操作
  • 8. StringBuffer 和 StringBuilder
    • 8.1String 和 StringBuffer 和StringBuilder的區別
    • 8.2StringBuffer 和 StringBuilder的區別:

前言

java是面向物件的一門編程語言,通過實體化物件,物件間的互動實作相應的功能,決解相應的問題,,java中實作了很多的類供我們使用,我們要學習java一定要學好一些常用的類,去學習里面的構造方法,成員方法,介面方法等,所以今天我就簡單的向大家介紹String類,和類里面的一些構造方法及常用的方法,首先我打開java使用幫助檔案,針對的是JDK1.8版本,看檔案對Sting這個類的介紹,這里簡單的說明了Sting這個類是在java.lang這個包底下的,它繼承了object類,以及這個類實作了哪些介面,有哪些構造方法等許多的描述,我們有時間可以多多閱讀這個中文幫助檔案,在使用其他的類有什么不明白的也可以查閱該檔案,
在這里插入圖片描述

1.創建字串

🎇常見的構造 String 的方式:

  public static void main(String[] args) {
     // 方式一
        String str1 = "hellobit";
        System.out.println(str1);
        // 方式二
        String str2 = new String("hellobit");
        System.out.println(str2);
        // 方式三
        char[] chars = {'a','b','c'};
        String str3 = new String(chars);
        System.out.println(str3);
    }

??方式三String里面重寫了toString方法,再通過println進行列印,就列印了str3這個參考所指向的物件了,所以這里列印的是字串的內容,而不是參考里面的地址,對于字串的創建,我們需要重點理解創建時的記憶體布局情況,這樣可以幫助我們更好地理解字串的創建,方式一,方式二創建字串的記憶體布局比較簡單,直接就是堆疊上的參考變數指向堆上的物件,后面有構造String的記憶體布局圖,接下來我簡單地畫一下方式三創建字串的記憶體布局圖,
在這里插入圖片描述
首先我們在堆區創建一個字符陣列,由參考變數chars來指向它,之后我們再new了一個物件String(chars),物件里面的成員變數有一個char型別的陣列value,value是一個參考變數,構造這個匿名物件的時候我們要傳一個引數,引數是陣列或者字串都行,呼叫String的其中一個構造方法public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}該方法復制產生了一個新的陣列,這個陣列由value這個參考來維護,

2.字串比較相等

??📃如果現在有兩個int型變數,判斷其相等可以使用 == 完成,

int x = 10 ;
int y = 10 ;
System.out.println(x == y);
// 執行結果
true

如果說現在在String類物件上使用 == ?
代碼1

String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2);
// 執行結果
true

看起來貌似沒啥問題, 再換個代碼試試, 發現情況不太妙.
代碼2

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2);
// 執行結果
false

代碼一的記憶體布局:
在這里插入圖片描述

代碼二的記憶體布局:
在這里插入圖片描述
📝📐我們來分析上面兩種創建 String 方式的差異.我們發現, 代碼1中str1 和 str2 是指向同一個物件的. 此時如 “Hello” 這樣的字串常量是在 字串常量池 中,代碼2中str1 和 str2 是指向的不是同一個物件,但最終指向的字串內容都是 “Hello” ,通過 String str1 = new String(“Hello”); 這樣的方式創建的 String 物件相當于再堆上另外開辟了空間來存盤"Hello" 的內容, 也就是記憶體中存在兩份 “Hello”.
🔍?? String 是參考資料型別,如果使用“==”來比較兩個參考的值,比較的還是值相同不相同,但是這個值不是字串值,是參考值,str1和str2分別指向堆上兩個不同地址處,代碼2 str1和str2的值不同,所以結果為false,如果要比較字串的內容可以使用equals方法進行比較,上圖中代碼2首先第一行代碼傳入字串"Hello",發現字串常量池里面沒有該字串,就將其入池,value是String里面的一個陣列參考,是new產生的匿名物件的一個成員,new String("Hello")產生物件時要傳入一個引數Hello,傳入引數后呼叫構造方法,這樣Srting字串才能完成構造,這樣value這個參考指向了字串常量池里面的"Hello",str1指向value,同理str2也指向它創建的物件的成員value,創建物件時也要傳入引數Hello,但發現常量池里面有Hello了就直接用了,value就直接指向常量池里面唯一的那個Hello了,

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
// System.out.println(str2.equals(str1)); // 或者這樣寫也行
// 執行結果
true

equals 使用注意事項
現在需要比較 str 和 “Hello” 兩個字串是否相等, 我們該如何來寫呢?

String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));

在上面的代碼中, 哪種方式更好呢????
🎇🎆那推薦使用 “方式二”. 一旦 str 是 null, 方式一的代碼會拋出例外, 而方式二不會,

String str = null;
// 方式一
System.out.println(str.equals("Hello")); // 執行結果 拋出 java.lang.NullPointerException 異// 方式二
System.out.println("Hello".equals(str)); // 執行結果 false

2.1字串傳參

Java 中陣列, String, 以及自定義的類都是參考型別,由于 String 是參考型別, 因此對于以下代碼,我們應該注意傳參考不一定改變字串的值,

String str1 = "Hello";
String str2 = str1;

它的記憶體布局圖如上面代碼1,, 這時我們可能會想是不是修改 str1 , str2 也會隨之變化呢?

str1 = "world";
System.out.println(str2);
// 執行結果
Hello

在這里插入圖片描述

我們發現, “修改” str1 之后, str2 也沒發生變化, 還是 hello?
事實上, str1 = “world” 這樣的代碼并不算 “修改” 字串, 而是讓 str1 這個參考指向了一個新的 String 物件.
在如下面的代碼:

 public static void func(String str) {
        str = "bit";
    }

    public static void main(String[] args) {
        String str = "gaobo";
        func(str);
        System.out.println(str);
    }

下面的代碼在函式傳參的時候,傳參考不會改變原來的值
在這里插入圖片描述
這里有兩個參考,一個main函式里面的,一個func函式里面的,開始的時候這兩個參考指向同一記憶體空間0x123,之后被調函式里的參考指向一個新的地址,但不影響呼叫函式里的參考,

3.字串常量池

在上面的例子中, String類的兩種實體化操作, 直接賦值和 new 一個新的 String.
直接賦值

String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2);
// 執行結果
true

🎇為什么現在并沒有開辟新的堆記憶體空間呢??因為String類的設計使用了共享設計模式
在JVM底層實際上會自動維護一個物件池(字串常量池)

  • 如果現在采用了直接賦值的模式進行String類的物件實體化操作,那么該實體化物件(字串內容)將自動保存 到這個物件池之中.
  • 如果下次繼續使用直接賦值的模式宣告String類物件,此時物件池之中如若有指定內容,將直接進行參考,
  • 如若沒有,則開辟新的字串物件而后將其保存在物件池之中以供下次使用 也就是簡單地說該字串常量池中只會有不同的String類物件,不會出現相同的String類物件,常量池的一個功能幫助我們節省記憶體空間,同樣的東西我們存盤一份就行了

采用構造方法

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2);
// 執行結果
false

📝由上面的代碼二的記憶體布局圖可知:
這樣的做法有兩個缺點:

  1. 如果使用String構造方法就會開辟兩塊堆記憶體空間,并且其中一塊堆記憶體將成為垃圾空間(字串常量 “hello” 也是一個匿名物件, 用了一次之后就不再使用了, 就成為垃圾空間, 會被 JVM 自動回收掉).
  2. 字串共享問題. 同一個字串可能會被存盤多次, 比較浪費空間

4.字串創建實體分析

下面我將通過一些簡單的例子,進一步地帶老鐵們熟悉直接賦值,采用構造方法構造字串及字串常量池在構造字串時的作用,
代碼1:

  String str1 = "helloboy";
        String str2 = new String("helloboy");
        System.out.println(str1 == str2);//false
        //比較的還是值相同不相同,但是這個值不是字串值,是參考值
        System.out.println(str1.equals(str2));//true

記憶體布局圖:
在這里插入圖片描述
📝該代碼的記憶體布局圖,可以結合最上面上面代碼1,代碼2的記憶體布局圖來看,首先直接賦值創建了一個字串 String str1 = “helloboy”;,放在字串常量池,之后通過構造的方式,str2指向在堆區實體化的物件,這個物件的產生需要傳一個字串引數,剛好字串常量池有這個引數,,直接用就行了,value就指向了這個引數,
代碼2:

String str1 = "hello";
        String str2 = "hello" + "world";
        System.out.println(str1 == str2);//true

像"helloworld",“world”,"hello"這些量被稱為字串字面值常量,是一個常量,代碼在進行字串的拼接的時候,編譯期間會進行優化,把它優化為一個常量,由常量池的知識可知在運行期間就只開辟一塊空間存盤優化過的常量了,因此str1和str2就指向了字串常量池的同一塊空間了,
代碼3:

String str1 = "goodboy";
        String str2 = "good";
        String str3 = str2+"boy";
        System.out.println(str1 == str3);

在這里插入圖片描述

直接賦值構造兩個字串,“goodboy”,"good"放在字串常量池中,str1和str2分別指向這兩個字串,定義變數str3在堆區開辟空間,它的內容等于str2+“boy”;,str3最終指向拼接好的字串,
代碼4:

 String str1 = "goodboy";
        String str4 = "good"+new String("boy");
        System.out.println(str1 == str4);

在這里插入圖片描述
??📘"goodboy","good","boy"這些字串之前沒有的首先都是放入常量池,new String(“boy”)新產生一個物件,物件里的參考指向傳入的引數,之后在堆上開辟一塊記憶體,存拼接好的字串"goodboy",拼接好的字串雖然也是"goodboy",但是和常量池里的不一樣,
代碼5:

String str1 = "goodboy";
        String str5 = new String("good)+new String("boy");
        System.out.println(str1 == str5);//false
        System.out.println(str1.equals(str5));//ture

這代碼和上面的差不多,用腳指頭想想也明白,哈哈!!(借助上面的代碼和圖秒懂),首先常量池里放入"goodboy",“good”,“boy”,通過構造的方式在堆區構造兩個字串,之后兩個字串在堆區拼接形成和常量池內容一樣的字串,str5指向該字串,
代碼6:

 String str1 =  "goodboy";
        String str2= new String("goodboy");
        str2.intern();
        System.out.println(str1 == str2);

在這里插入圖片描述
📝這個代碼和代碼1的記憶體布局圖一樣,只是多了一步對字串的入池操作 str2.intern();對于我們在堆區構造產生的字串,str2
拿到物件里面的字串的值,和常量池里面的字串比較,如果常量池有該字串就不如池,如果沒有該字串就把該字串放入常量池中,因為原來字串常量池里有我們構造出來的字串,所以堆區的字串就不如池了,記憶體代碼布局就像開始一樣的、
代碼7:

String s3 = new String("1") + new String("1");
        s3.intern();
        String s4 = "11";
        System.out.println(s3 == s4);//true

在這里插入圖片描述
上面的代碼是字串要入池的時候,池子里有該字串,現在的這個代碼是入池的時候,池子里沒有這個字串,首先在堆上創建兩個字串物件,之后拼接形成字串“11”,s3這個參考指向指向“11”,之后將s3指向的字串做入池操作,池子里沒有就入進去,入的時候在常量池里面開辟一塊記憶體,存盤要入的字串在堆疊區的地址,而不是內容,之后又創建一個物件“11”,因為產量池里面有這個物件,所以s4這個參考就直接存盤了常量池里那個字串的地址了,文字和上面的圖一起食用效果更佳!!!
代碼8:

String s3 = new String("1") + new String("1");
        String s4 = "11";
        s3.intern();
        System.out.println(s3 == s4);

在這里插入圖片描述
這代碼和上面的代碼只是有幾行代碼顛倒了,就產生了不一樣的效果了,s3在s4放入常量池后再入池,就入不了池了,就什么操作也不發生,

5.理解字串不可變

🌈?字串是一種不可變物件. 它的內容不可改變.
從源代碼可知String 類的內部實作也是基于一個 char value[]的陣列來實作的,這個陣列被finalprivate修飾 但是 String 類并沒有提供 set 方法來修改內部的字符陣列,所以簡單的認為字串是一種不可變物件,
在這里插入圖片描述
感受下形如這樣的代碼

String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
// 執行結果
hello world!!!

形如 += 這樣的操作, 表面上好像是修改了字串, 其實不是. 記憶體變化如下:

在這里插入圖片描述
從上面的記憶體變化圖中,我們可以看到,最終形成了一個新的字串,但是這個字串不是在原來字串的后面添加字串形成的,沒有修改字串的內容,是通過字串的拼接形成一個新的物件,第一次產生一個物件hello world并且str指向這個物件,第二次產生一個hello world!!!物件,str1又指向這個新的物件,每次拼接完成后,str這個參考里面的地址都發生了改變,
?🚫因此我們在開發中要注意不要出現類似如下的代碼,會產生大量的臨時物件, 效率比較低.

String str = "hello" ;
for(int x = 0; x < 1000; x++) {
str += x ;//拼接字串
}
System.out.println(str);

那么如果實在需要修改字串, 例如, 現有字串 str = “Hello” , 想改成 str = “hello” , 該怎么辦?
💯常見辦法: 借助原字串, 創建新的字串
substring()方法截取一個字串的子串,括號里面的引數表示從主串的什么位置開始截取,主串的第一個位置默認為0位置,之后又進行字串的截取,那么情況就和上面的情況一樣了,

String str = "Hello";
str = "h" + str.substring(1);//
System.out.println(str);
// 執行結果
hello

?特殊辦法: 使用 “反射” 這樣的操作可以破壞封裝, 訪問一個類內部的 private 成員,但今天的這篇博文我們不詳講,只是提一下,后面我的博文會詳細講到,
為什么 String 要不可變?(不可變物件的好處是什么?) ??

  1. 方便實作字串常量池. 如果 String 可變, 那么物件池就需要考慮何時深拷貝字串的問題了.
  2. 不可變物件是執行緒安全的.
  3. 不可變物件更方便快取 hash code, 作為 key 時可以更高效的保存到 HashMap 中.

6.字符, 位元組與字串

6.1字符與字串

字串內部包含一個字符陣列,String 可以和 char[] 相互轉換.

字符與字串常用的一些方法如下表:

No方法名稱型別描述
1public String(char value[])構造將字符陣列中的所有內容變為字串
2public String(char value[], int offset, int count)構造將部分字符陣列中的內容變為字串,offset 為偏移量,從0開始 ,count為轉換的字符個數
3public char charAt(int index)普通取得指定索引的字符,索引從0開始
4public char[] toCharArray()普通將字串變為字符陣列回傳

方法代碼簡單演示:
方法一:將字符陣列中的所有內容變為字串

char[] value = {'a', 'b', 'c', 'd', 'e'};
String str = new String(value);
System.out.println(str);

結果為:abcde
方法二:將部分字符陣列中的內容變為字串

 char[] value = {'a','b','c','d','e'};
        String str = new String(value,1,2);
        //從偏移量為1的位置開始取2個字符來構造String物件
        System.out.println(str);

結果為:bc
方法三: 取得指定索引的字符,索引從0開始

String str2 = "hello";
        char ch = str2.charAt(1);//字串的第一個字符為0位置
        System.out.println(ch);

結果為:e
方法四:將字串變為字符陣列回傳

String str3 = "hello";
        char[] chars = str3.toCharArray();//將字串以字符陣列的方式進行存盤
        System.out.println(Arrays.toString(chars));

結果為:[h,e,l,l,o]
???注意:對于上述方法給定的數字位置和數字范圍,一定要合理,不然就會產生例外,

6.2位元組與字串

位元組常用于資料傳輸以及編碼轉換的處理,字串 String 也能和位元組陣列 byte[] 相互轉換

No方法名稱型別描述
1public String(byte bytes[])構造將位元組陣列變成字串
2public String(byte bytes[], int offset, int length)構造將部分位元組陣列中的內容變為字串
3public byte[] getBytes()普通將字串以位元組陣列的形式回傳
4public byte[] getBytes(String charsetName)throws java.io.UnsupportedEncodingException普通編碼轉換處理

方法代碼簡單演示:
方法一:將位元組陣列變成字串

byte[] bytes = {97, 98 ,99 ,100};
String str = new String(bytes);
System.out.println(str);

結果為:abcd
方法二:將部分位元組陣列中的內容變為字串

byte[] bytes = {97, 98 ,99 ,100};
String str = new String(bytes, 1, 2);
System.out.println(str);

結果為:bc
方法三:將字串以位元組陣列的形式回傳

public static void main(String[] args) {
    String str = "abcde";
    byte[] bytes = str.getBytes();
    System.out.println(Arrays.toString(bytes));
}

結果為:[97, 98, 99, 100, 101]
方法四:編碼轉換處理(很少使用,了解即可)

  public static void main(String[] args) throws UnsupportedEncodingException {
        String str = "李敏敏";
        byte[] bytes = str.getBytes("utf-8");//幾乎不用
        System.out.println(Arrays.toString(bytes));
    }

結果為:[-26, -99, -114, -26, -107, -113, -26, -107, -113]
如果我們將編碼方式“utf-8”,改為“gbk”則會有不同的結果

  public static void main(String[] args) throws UnsupportedEncodingException {
        String str = "李敏敏";
        byte[] bytes = str.getBytes("gbk");//幾乎不用
        System.out.println(Arrays.toString(bytes));
    }

結果為:[-64, -18, -61, -12, -61, -12]
其實這個方法就是把我們給的字串,以我們指定的編碼規則轉換為位元組陣列的,編碼規則不同則轉換的內容不同,在utf-8中一個漢字占3個位元組,gbk中占一個位元組,

小結:
那么何時使用 byte[], 何時使用 char[] 呢?

  • byte[] 是把 String 按照一個位元組一個位元組的方式處理, 這種適合在網路傳輸, 資料存盤這樣的場景下使用. 更適合針對二進制資料來操作.
  • char[] 是把 String 按照一個字符一個字符的方式處理, 更適合針對文本資料來操作,尤其是包含中文的時候.
  • 一個簡單粗暴的區分方式就是用記事本打開能不能看懂里面的內容. 如果看的懂, 就是文本資料(例如 .java 檔案), 如果看不懂, 就是二進制資料(例如 .class 檔案),

7.字串常見操作

7.1字串比較

上述介紹到 equals 可以比較字串是否相等,并且是區分大小寫的,而除了它,String 類還有其他比較字串的方法

No方法名稱型別描述
1public boolean equals(Object anObject)普通區分大小寫的比較
2public boolean equalsIgnoreCase(String anotherString)普通不區分大小寫的比較
3public int compareTo(String anotherString)普通比較兩個字串大小關系

方法代碼簡單演示:
方法一:區分大小寫的比較

String str1 = "hello";
String str2 = new String("Hello");
System.out.println(str1.equals(str2));

結果為:false
方法二:不區分大小寫的比較

String str1 = "hello";
String str2 = new String("Hello");
System.out.println(str1.equalsIgnoreCase(str2));

結果為:true
方法三: 比較兩個字串大小關系

String str1 = "hello";
String str2 = new String("hella");
System.out.println(str1.compareTo(str2));

結果為:14
在String類中compareTo()方法是一個非常重要的方法,比較規則大致是,都是以第一個字串為比較基準,首先比較字串長度,第一個字串的長度大于第二個字串的長度則回傳一個正數,長度相同回傳0,第一個的長度小于第二個的長度回傳一個負數,長度相同之后從前往后比較,字串里面第一個不相同的字符 的大小關系就是整個字串大小的關系,比較的回傳值也是和比較長度的回傳情況一樣的,

7.2字串查找

No方法名稱型別描述
1public boolean contains(CharSequence s)普通判斷一個字串是否存在
2public int indexOf(String str)普通從頭開始查找指定字串的位置,查到了回傳位置的開始索引,查不到回傳-1
3public int indexOf(String str, int fromIndex)普通從指定位置開始查找子字串位置
4public int lastIndexOf(String str)普通由后向前查找子字串位置
5public int lastIndexOf(String str, int fromIndex)普通從指定位置由后向前查找
6public boolean startsWith(String prefix)普通判斷是否以指定字串開頭
7public boolean startsWith(String prefix, int toffset)普通從指定位置開始判斷是否以指定字串開頭
8public boolean endWith(String suffix)普通判斷是否以指定字串結尾

方法代碼簡單演示:
方法一:判斷一個字串是否存在

String str = "helloworld";
System.out.println(str.contains("hello"));

結果為:true
方法二:從頭開始查找指定字串的位置,查到了回傳位置的開始索引,查不到回傳-1

String str = "helloworld";
System.out.println(str.indexOf("world"));

結果為:5
方法三:從指定位置開始查找子字串位置

String str = "helloworldhelloworld";
System.out.println(str.indexOf("world", 6));

結果為:15
方法四:
由后向前查找子字串位置

String str = "helloworld";
System.out.println(str.lastIndexOf("world"));

結果為:5
方法五: 從指定位置由后向前查找

 String str = "helloworld";
        //System.out.println(str.lastIndexOf("world"));
        System.out.println(str.lastIndexOf("world", 5));
       

結果為:5
方法六:判斷是否以指定字串開頭

String str = "helloworld";
System.out.println(str.startsWith("hello"));

結果為:true
方法七:從指定位置開始判斷是否以指定字串開頭

String str = "helloworld";
System.out.println(str.startsWith("hello", 2));

結果為:false
方法八:判斷是否以指定字串結尾

String str = "helloworld";
System.out.println(str.endsWith("world"));

結果為:true

7.3字串替換

String 類中也有方法將一個指定的新字串替換掉已有的字串資料

No方法名稱型別描述
1public String replaceAll(String regex, String replacement)普通替換所有的指定內容
2public String replaceFirst(String regex, String replacement)普通替換首個內容
3public String replace(char oldChar, char newChar)普通替換所有的指定字符

方法一: 替換所有的指定內容
將原來字串里面的某一字串替換為另一字串

String str = "ababcabcd";
        String str3 = str.replaceAll("ab","gg");
        System.out.println(str3);

結果為:ggggcggcd
方法二:替換首個內容
將字串的開始幾個字符替換為另外的幾個字符


        String str = "ababcabcd";
        String str4 = str.replaceFirst("ab","gg");
        System.out.println(str4);

結果為:ggabcabcd
方法三:替換所有的指定字符
將字串中某一個字符全部替換為另一個新的字符


        String str = "ababcabcd";
        //替換 所有的字符
        String str2 = str.replace('a','g');
        System.out.println(str2);

結果為:ggabcabcd

7.4字串拆分

String 類中也有方法將一個完整的字串按照指定的分隔符劃分為若干子字串

No方法名稱型別描述
1public String[] split(String regex)普通將字串全部拆分
2public String[] split(String regex, int limit)普通將字串部分拆分,該陣列長度就是 limit 極限

方法一:將字串全部拆分,只有一個引數的

  String str = "ab#abc#abcd";
        //以引數#進行分割  
        String[] strings = str.split("#");
        for ( String s : strings) {
            System.out.println(s);
        }

結果為:
ab
abc
abcd
方法二:將字串部分拆分,該陣列長度就是 limit極限


String str = "ab#abc#abcd";
        //以引數進行分割  引數不存在 不分割  ,  第二個引數 是分割的極限組數
        String[] strings = str.split("#",5);
        for ( String s : strings) {
            System.out.println(s);
        }

結果為:
ab
abc
abcd
注意:以引數進行分割 ,引數不存在 不分割 , 第二個引數 是分割的極限組數,分割的陣列小于等于這個極限陣列,
方法三:拆分 IP 地址
拆分是特別常用的操作. 一定要重點掌握. 另外有些特殊字符作為分割符可能無法正確切分, 需要加上轉義,如分割Ip地址的點號就是一個特殊的運算子,要特殊處理,

 String str = "192.168.1.1";   
        String[] strings = str.split("\\.");
        for ( String s : strings) {
            System.out.println(s);
        }

結果:
192
168
1
1
🚭?注意事項:

  1. 字符"|","*","+“都得加上轉義字符,前面加上”".
  2. 而如果是".",那么就得寫成"\."
  3. 如果一個字串中有多個分隔符,可以用"|"作為連字符.

7.5字串截取

No方法名稱型別描述
1public String substring(int beginIndex)普通從指定索引截取到結尾
2public String substring(int beginIndex, int endIndex)普通截取部分內容

方法一:從指定索引截取到結尾

String str1 = "helloworld";
String str2 = str1.substring(5);
System.out.println(str2);

結果為:“world”
方法二:截取部分內容

String str1 = "helloworld";
String str2 = str1.substring(2,5);
System.out.println(str2);

結果為:“llo”
注意事項:

  1. 索引從0開始
  2. 截取的范圍為左閉右開, 如substring(2, 5) 表示包含 02號下標的字符, 不包含 5 號下標

7.6其他操作

除了上述的一些操作字串的方法,其實還有很多其他的方法,我們可以使用那個API檔案查看方法的使用,下面以表格的形式列舉其他一些常見的方法,沒有演示它的使用,老鐵們可以自己用用,🤓😎

No方法名稱型別描述
1public String trim()普通去掉字串中的左右空格,保留中間空格
2public String toUpperCase()普通字串轉大寫
3public String toLowerCase()普通字串轉小寫
4public native String intern()普通字串入池操作
5public int length()普通取得字串長度
6public boolean isEmpty()普通判斷字串是否為空(空不是 null,而是長度為0)

這里的方法就不一一展示示例了,如果大家能夠把上述字串的方法都記得的話,那么去做一些題目那真的可以說是更加輕松了,并且字串的方法不止這些,大家可以去 Java 的 api 中去查看學習,

8. StringBuffer 和 StringBuilder

8.1String 和 StringBuffer 和StringBuilder的區別

👀🔅String 和 StringBuffer 和StringBuilder有相同也有不同,其實 StringBuffer 和StringBuilder就是String的plus版本,是對String的一些完善,StringBuffer 和 StringBuilde幾乎沒差別,我們先以StringBuffer 為例討論前兩者的不同,再討論后兩者的不同,

1.String 和 StringBuffer 都可以產生字串,但產生的方式不一樣,前者即可以通過直接賦值的方式產生,也可以通過實體化物件的方式產生,

  StringBuffer sb = new StringBuffer("hello");
        //StringBuffer sb1 = "hello";//不可以
        String sb2="hello";
        String string =new String("hello");
        

2.在String中使用"+"來進行字串連接,但是這個操作在StringBuffer 類中需要更改為append()方法:

StringBuffer sb = new StringBuffer("hello");
        sb.append("bit");
        sb.append(1).append("!!!");
        System.out.println(sb);
        //===========================
         String s = "hello";
        s = s + "bit";

3.除了append()方法外,StringBuffer也有一些String類沒有的方法, 如字串反轉reverse()等,
4.String和StringBuffer最大的區別在于:String的內容無法修改,而StringBuffer的內容可以修改,頻繁修改字串的情況考慮使用StingBuffer,如之前的字串的拼接:
這個代碼之前說了它會產生很多的物件,我們它執行的匯編代碼時是通過StingBuffer對其進行優化的,但還是產生了好多物件,這也說明了String的局限性,如果直接使用StingBuffer就只產生了一個物件,就完成了字串的修改,

 String str = "hello";
        for(int i = 0;i < 10;i++) {
            str = str + i;
        }
        System.out.println(str);

如果我們直接使用StringBuilder代碼改成下面的代碼不就高效和節省記憶體了嘛

 String str = "hello";
        StringBuilder sb = new StringBuilder();
        sb.append(str);
        for(int i = 0;i < 10;i++) {
            ///str = str + i;
            sb.append(i);
        }
        str = sb.toString();
        System.out.println(str);

我們也可以在結合記憶體布局圖和原始碼截圖大致理解下:
在這里插入圖片描述
再進一步說就是String產生的物件不可以變,每次都要產生新物件,在新物件里進行拼接 StringBuilder產生的物件是可以變的,進行拼接時 ,我們在StringBuilder物件的字串里添字串,他每次回傳的都是當前物件,它只new了一個物件,沒動過常量池里面的字串,沒毛病吧!

8.2StringBuffer 和 StringBuilder的區別:

StringBuffer有關鍵字synchronized 修飾,采用同步處理,在進行當前的字串拼接時不會受到其它拼接的的影響,等當前拼接完成后才進行其他拼接,屬于執行緒安全操作;而StringBuilder未采用同步處理,會受到其他拼接的干擾,屬于執行緒不安全操作在這里插入圖片描述
🔅**注意:**String和StringBuffer類不能直接轉換,如果要想互相轉換,可以采用如下原則:

  • String變為StringBuffer:利用StringBuffer的構造方法或append()方法
  • StringBuffer變為String:呼叫toString()方法,

如下代碼:

以上兩種方式 就是 String轉換為StringBuilder、StringBuffer型別字串,

 String str = "abcd";
        StringBuilder sb = new StringBuilder(str);

        StringBuilder sb2 = new StringBuilder();
        sb2.append(str);
       

StringBuilder、StringBuffer型別字符轉換為String,(以StringBuilder為例)

 StringBuilder sb2 = new StringBuilder("abc");
        String s = sb2.toString();
        System.out.println(s);

好了,本期有關String類的文章就介紹到這,下篇博文又見,感謝點贊的友友們,

在這里插入圖片描述

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/306230.html

標籤:java

上一篇:StringBuffer類

下一篇:阿里開源的這個庫,讓 Excel 匯出不再復雜(既要能寫,還要寫的好看)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more