String類

String類的創(chuàng)建

//方式一
String str = "hello word";
//方式二
String str = new String("hello word");
//方式三
char[] arr = {'a', 'b', 'c'};
String str = new String(arr);

我們看看以上代碼的內(nèi)存分布圖:


引用類型有點類似c語言中的指針囊卜,我們在內(nèi)存中開辟了一小塊內(nèi)存空間保存一個地址,但是與c語言不同的是指針能進行數(shù)字運算,但引用不行肩钠,java中String就是引用類型.
由于String是引用類型碾褂,因此我們分析以下代碼的內(nèi)存分布:

String str1 = "hello word';
String str2 = str1;
QQ截圖20210128173143.png

修改str1的值兽间,看看str2是否會隨之改變

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = "hello word";
        String str2 = str1;
   
        str1 = "zmm";
        System.out.println(str2);
    }
}

image.png

從內(nèi)存分布分析此結果

image.png

可以看出我們修改str1并不會影響str2的結果,也就意味著我們修改了str1其實只是修改了str1的指向正塌,讓str1引用指向了一個新的String對象

字符串比較相等

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1 == str2);
    }
}
image.png

那么根據(jù)以上結果嘀略,是否就能確定判斷字符串相等可以用 '' == '', 我們再看一個例子:

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1 == str2);
    }
}
QQ截圖20210128180011.png

我們分析兩種創(chuàng)建String方式的差異
第一種:

QQ截圖20210128173143.png

str1 和str2 是指向同一個對象,是由于像 " hello '' 這樣的字符串乓诽,我們是將它保存在字符串常量池中的帜羊,如果我們需要使用 '' hello '' 這個字符串常量,就直接引用字符串常量池的這個位置就可.
第二種:
QQ截圖20210128173143.png

用 String str1 = new String(" hello ") 這個方式創(chuàng)建對象鸠天,我們在內(nèi)存中開了兩塊空間讼育,來保存 " hello "這個字符串,因此在用" == " 比較兩個字符串是否相等的時候稠集,其實是在比較兩個字符串的地址是否一樣奶段,而不是比較字符串的內(nèi)容

equals方法來比較字符串內(nèi)容是否相等

import java.util.Arrays;

public class test {
public static void main(String[] args) throws NameException, PasswordException {
        String str1 = new String("hello");
        String str2 = new String("hello");

        System.out.println(str1.equals(str2));
    }
}
QQ截圖20210128180011.png

使用 equals 的注意事項

//方式一
System.out.println(" hello ".equals(str2));
//方式二
System.out.println(str1.equals(str2));

以上兩種方式我們更推薦方式一,若一旦 " str1 = null "那么就會拋出異常
方式二

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = null;
        String str2 = new String("hello");

        System.out.println(str1.equals(str2));
    }
}
QQ截圖20210128180011.png

方式一

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = null;
        String str2 = new String("hello");

        System.out.println("hello".equals(str1));
    }
}
QQ截圖20210128180011.png

字符串常量池

直接賦值

import java.util.Arrays;

public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        String str1 = "hello";
        String str2 = "hello";

        System.out.println(str1 == str2);
    }
}

在JVM底層實際上會自動維護一個對象池(字符串常量池)

  • 如果現(xiàn)在采用了直接賦值的模式進行String類的對象實例化操作剥纷,那么該實例化對象(字符串內(nèi)容)將自動保存到這個對象池之中.
  • 如果下次繼續(xù)使用直接賦值的模式聲明String類對象痹籍,此時對象池之中如若有指定內(nèi)容,將直接行引用
  • 如若沒有晦鞋,則開辟新的字符串對象而后將其保存在對象池之中以供下次使用

采用構造方法

String str = new String(" hello ");

這樣的做法有兩個缺點:

  • 如果使用String構造方法就會開辟兩塊堆內(nèi)存空間蹲缠,并且其中一塊堆內(nèi)存將成為垃圾空間(字符串常量 "hello" 也是一個匿名對象, 用了一次之后就不再使用了, 就成為垃圾空間, 會被 JVM 自動回收掉).
  • 字符串共享問題,同一個字符串可能被儲存多次悠垛,比較浪費空間

intern 方法可以顯示把對象入池

import java.util.Arrays;
//判斷str是否入池
public class test {
    public static void main(String[] args) throws NameException, PasswordException {
        
        String str1 = new String("hello");
        System.out.println(str1 == "hello");
    }
}
QQ截圖20210128180011.png
import java.util.Arrays;

public class test {
    public static void main(String[] args) {
        //顯示入池
        String str1 = new String("hello").intern();
        System.out.println(str1 == "hello");
    }
}
QQ截圖20210128180011.png

結論

  • 直接賦值:只會開辟一塊堆內(nèi)存空間线定,并且該字符串對象可以自動保存在對象池中以供下次使用
  • 構造方法:會開辟兩塊堆內(nèi)存空間确买,不會自動保存在對象池中斤讥,可以使用intern()方法手工入池
  • 我們一般采用直接賦值的方式創(chuàng)建String類對象

字符串的不可變

字符串是一種不可變對象,它的內(nèi)容不可變
String類的內(nèi)部實現(xiàn)也是基于char[ ]來實現(xiàn)湾趾,但是String類并沒有提供set方法來修改內(nèi)部字符數(shù)組

public class example {
    public static void main(String[] args) {
       String str = "hello ";
       str = str + "word";
       str += "!!!";
        System.out.println(str);
    }
}
QQ截圖20210128180011.png

內(nèi)存分布圖

QQ截圖20210129170441.png

字符串str拼接以后周偎,str的引用指向改變了抹剩,但String的對象并沒有改變

String不可變的好處:

  • 方便實現(xiàn)字符串對象池
  • 不可變對象線程安全
  • 不可變對象更方便緩存 hash code, 作為 key 時可以更高效的保存到 HashMap 中

字符、字節(jié)與字符串

方法名稱 類型 描述
public String(char value[]) 構造 使用字符數(shù)組的內(nèi)容構造一個字符串
public String(char value[]蓉坎,int offset, int court) 構造 使用字符數(shù)組中以offset下標開始的連續(xù)count個字符構造一個字符串
public char charAt(int index) 普通 獲得字符串中指定索引的字符
public char[] toCharArray() 普通 將字符串變?yōu)樽址麛?shù)組返回
  • 示例代碼1:字符數(shù)組轉(zhuǎn)字符串
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        char[] arr = {'a','b','c'};
        String str = new String(arr);
        System.out.println(str);
    }
}
image.png
  • 示例代碼2:將指定字符轉(zhuǎn)成字符串
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        char[] arr = {'a','b','c','d','f'};
        String str = new String(arr,2,3);
        System.out.println(str);
    }
}
QQ截圖20210128180011.png
  • 示例代碼3:獲得字符串中的某個字符
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str = "hello";
        char ch = str.charAt(4);
        System.out.println(ch);
    }
}
QQ截圖20210128180011.png
  • 示例代碼4:字符串轉(zhuǎn)成字符數(shù)組
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str = "hello";
        char[] str1 = str.toCharArray();
        System.out.println(Arrays.toString(str1));
    }
}
QQ截圖20210128180011.png

字符串常見操作

字符串常見比較

方法名稱 類型 描述
public boolean equals(Object anObject) 普通 區(qū)分大小寫的比較
public boolean equalsIgnoreCase(String anotherString) 普通 不區(qū)分大小寫的比較
public int compareTo(String anotherString) 普通 兩個字符串比較關系
  • 示例代碼1
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.equals(str2));
    }
}
image.png
  • 示例代碼2:
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.equalsIgnoreCase(str2));

    }
}
image.png
  • 示例代碼3:
import java.util.Arrays;
import java.util.Scanner;

public class example {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.compareTo(str2));

    }
}
image.png
public class example {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "hello";
        System.out.println(str1.compareTo(str2));

    }
}
image.png
public class example {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "Hello";
        System.out.println(str1.compareTo(str2));

    }
}
image.png

使用compareTo()這個方法澳眷,若兩個字符串相等,則返回0蛉艾;反之返回將字符串中的字符一一比較返回其差值;

不區(qū)分大小寫的字符串比較

public class example {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "Hello";
        
        System.out.println(str1.equalsIgnoreCase(str2));

    }
}
image.png

字符串查找

所謂字符串查找就是從一個完整的字符串之中可以判斷指定內(nèi)容是否存在

方法名稱 類型 描述
public boolean contains(CharSequence s) 普通 判斷一個子字符串是否存在
public int indexOf(String str) 普通 從左開始向右查找指定字符串是否存在钳踊,查到了返回位置的開始索引,如果查不到返回-1
public int indexOf(String str, int fromIndex) 普通 從指定位置開始查找子串的位置
public int lastIndexOf(String str) 普通 由右向左查找子字符串位置
public int lastIndexOf(String str, int fromIndex) 普通 從指定位置由右向左查找子串
public boolean startsWith(String prefix) 普通 判斷是否以指定字符串開頭
public boolean startsWith(String prefix, int toffset) 普通 從指定位置開始判斷是否以指定字符串開頭
public boolean endsWith(String suffix) 普通 判斷是否以指定字符串結尾
  • 示例代碼1:
public class example {
    public static void main(String[] args) {
        String str1 = "Hello word";
        System.out.println(str1.contains("word"));

    }
}
image.png
  • 示例代碼2:
public class example {
    public static void main(String[] args) {
        String str1 = "Hello word";
        String str2 = "word";
        System.out.println(str1.indexOf(str2));

    }
}
image.png
  • 示例代碼3:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adcmfro";
        String str1 = "m";
        System.out.println(str.indexOf(str1, 3));
    }
}
QQ截圖20210128180011.png
  • 示例代碼4:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        String str1 = "r";
        System.out.println(str.lastIndexOf(str1));
    }
}
image.png
  • 示例代碼5:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        String str1 = "r";
        System.out.println(str.lastIndexOf(str1, 4));
    }
}
image.png
  • 示例代碼6:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        System.out.println(str.startsWith("amm"));
    }
}
image.png
  • 示例代碼7:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        System.out.println(str.startsWith("ad",0));
    }
}
image.png
  • 示例代碼8:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "adrmfro";
        System.out.println(str.endsWith("r"));
    }
}
image.png

字符串替換

使用一個指定的新的字符串替換掉已有的字符串數(shù)據(jù)勿侯,可用方法如下

方法名稱 類型 描述
public String replaceAll(String regex, String replacement) 普通 替換所有的指定內(nèi)容
public String replaceFirst(String regex, String replacement) 普通 替換首個內(nèi)容
  • 示例代碼:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "helloword";
        System.out.println(str.replaceAll("l", "m"));
        System.out.println(str.replaceFirst("l", "x"));
        System.out.println(str.replace("w", "o"));
    }
}
image.png

注意事項: 由于字符串是不可變對象, 替換不修改當前字符串, 而是產(chǎn)生一個新的字符串.

字符串拆分

可以將一個完整的字符串按照指定的分隔符劃分為若干個子字符串

方法名稱 類型 描述
public String[] split(String regex) 普通 將字符串全部拆分
public String[] split(String regex, int limit) 普通 將字符串部分拆分拓瞪,該數(shù)組的長度極限就是limit
  • 示例代碼1:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "hello word";
        String[] s = str.split(" ");
        for(String x: s) {
            System.out.println(x);
        }
    }
}
image.png
  • 示例代碼2:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "hello word hello zmm";
        String[] s = str.split(" ", 2);
        for(String x: s) {
            System.out.println(x);
        }
    }
}
image.png
  • 示例代碼3:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "192.168.1.1";
        String[] s = str.split("\\.");
        for(String x: s) {
            System.out.println(x);
        }
    }
}
image.png

注意事項:

  • 字符"|","*","+"都得加上轉(zhuǎn)義字符,前面加上" \ "即可.
  • 而如果是""助琐,那么就得寫成"\".
  • 如果一個字符串中有多個分隔符祭埂,則可以用" | "作為連接符

字符串截取

從一個完整字符串之中截取部分內(nèi)容,可用方法如下

方法名稱 類型 描述
public String substring(int beginIndex) 普通 從指定索引截取到結尾
public String substring(int beginIndex, int endIndex) 普通 截取部分內(nèi)容
  • 示例代碼1:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "helloword";
        System.out.println(str.substring(4));
    }
}
image.png
  • 示例代碼2:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = "helloword";
        System.out.println(str.substring(4, 6));
    }
}
image.png

注意事項:

  • 索引從0開始
  • 注意前閉后開區(qū)間的寫法, substring(0, 5) 表示包含 0 號下標的字符, 不包含 5 號下標

其他操作方法

方法名稱 類型 描述
public String trim() 普通 去掉字符串中的左右空格兵钮,保留中間空格
public String toUpperCase() 普通 字符串轉(zhuǎn)大寫
public String toLowerCase() 普通 字符串轉(zhuǎn)小寫
public native String intern() 普通 字符串入池操作
public String concat(String str) 普通 字符串連接蛆橡,等同于"+",不入池
public int length() 普通 取得字符串長度
public boolean isEmpty() 普通 判斷字符串是否為空(不是null掘譬,而是長度為0)
  • 示例代碼1:
package xsk;

public class Test {
    public static void main(String[] args) {
      String str = " hello bit hello  ";
        System.out.println(str.trim());
    }
}
image.png
  • 示例代碼2:
package xsk;

public class Test {
    public static void main(String[] args) {
      String str = " Hello bit hello  ";
        System.out.println(str.toUpperCase());
    }
}
image.png
  • 示例代碼3:
package xsk;

public class Test {
    public static void main(String[] args) {
      String str = " Hello bit hello  ";
        System.out.println(str.toLowerCase());
    }
}
image.png
  • 示例代碼4:
package xsk;

public class Test {
    public static void main(String[] args) {
        String str = " Hello bit hello ";
        String str1 = "aaa";
        System.out.println(str.concat(str1));
    }
}
image.png
  • 示例代碼5:

public class Test {
    public static void main(String[] args) {
        String str = " Hello bit hello ";

        System.out.println(str.isEmpty());
        System.out.println(str.length());
    }
}
image.png

String Buffer 和 String Builder

StringBuffer和StringBuilder是為了解決String是不可變對象帶來的麻煩
我們來看一下之前那個頻繁拼接字符串的代碼

public class Test {
    public static void main(String[] args) {
        String str = "hooo";
        for(int i = 0; i < 10; i++) {
            str += i;
        }
        System.out.println(str);

    }
}
image.png

我們知道String是不可變對象泰演,所以這個代碼的效率很低,就是在頻繁的創(chuàng)建新的對象葱轩。我們使用StringBuffer和StringBuilder來分別優(yōu)化一下這個代碼

public class Test {
    public static void main(String[] args) {
        StringBuffer str = new StringBuffer("hoooo");
        for(int i = 0; i < 10; i++) {
            str.append(i);
        }
        System.out.println(str);

    }
}
image.png

String睦焕、StringBuffer和StringBuilder的區(qū)別

  • String是不可變的,StringBuffer和StringBuilder都是可變的靴拱;
  • StringBuffer和StringBuilder大部分功能都是類似的垃喊;
  • StringBuffer采用同步處理,屬于線程安全袜炕;StringBuilder沒有采用同步操作本谜,線程不安全
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妇蛀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子笤成,更是在濱河造成了極大的恐慌评架,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炕泳,死亡現(xiàn)場離奇詭異纵诞,居然都是意外死亡,警方通過查閱死者的電腦和手機培遵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門浙芙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來登刺,“玉大人,你說我怎么就攤上這事嗡呼≈郊螅” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵南窗,是天一觀的道長揍很。 經(jīng)常有香客問我,道長万伤,這世上最難降的妖魔是什么窒悔? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任煎源,我火速辦了婚禮知市,結果婚禮上跋炕,老公的妹妹穿的比我還像新娘趟薄。我一直安慰自己侥钳,他們只是感情好趴酣,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布饱苟。 她就那樣靜靜地躺著诅妹,像睡著了一般芜抒。 火紅的嫁衣襯著肌膚如雪珍策。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天宅倒,我揣著相機與錄音攘宙,去河邊找鬼。 笑死拐迁,一個胖子當著我的面吹牛蹭劈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播线召,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼铺韧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缓淹?” 一聲冷哼從身側響起哈打,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎讯壶,沒想到半個月后料仗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡伏蚊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年立轧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡氛改,死狀恐怖帐萎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胜卤,我是刑警寧澤疆导,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站瑰艘,受9級特大地震影響是鬼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜紫新,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一均蜜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧芒率,春花似錦囤耳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至匪蟀,卻和暖如春椎麦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背材彪。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工观挎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人段化。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓嘁捷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親显熏。 傳聞我的和親對象是個殘疾皇子雄嚣,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容