最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java-String類最全匯總(上篇)

 更新時(shí)間:2023年01月15日 16:11:53   作者:曉星航  
這篇文章主要介紹了Java-String類最全匯總(上篇),本文章內(nèi)容詳細(xì),本模塊分為了兩部分,本次為上篇,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

創(chuàng)建字符串

常見的構(gòu)造 String 的方式

// 方式一
String str = "Hello Bit";

// 方式二
String str2 = new String("Hello Bit");

// 方式三
char[] array = {'a', 'b', 'c'};
String str3 = new String(array);

注意事項(xiàng):

  • “hello” 這樣的字符串字面值常量, 類型也是 String.
  • String 也是引用類型. String str = “Hello”; 這樣的代碼內(nèi)存布局如下

回憶 “引用”

我們?cè)?jīng)在講數(shù)組的時(shí)候就提到了引用的概念.

引用類似于 C 語言中的指針, 只是在棧上開辟了一小塊內(nèi)存空間保存一個(gè)地址. 但是引用和指針又不太相同, 指針能進(jìn)行各種數(shù)字運(yùn)算(指針+1)之類的, 但是引用不能, 這是一種 “沒那么靈活” 的指針.

另外, 也可以把引用想象成一個(gè)標(biāo)簽, “貼” 到一個(gè)對(duì)象上. 一個(gè)對(duì)象可以貼一個(gè)標(biāo)簽, 也可以貼多個(gè). 如果一個(gè)對(duì)象上面一個(gè)標(biāo)簽都沒有, 那么這個(gè)對(duì)象就會(huì)被 JVM 當(dāng)做垃圾對(duì)象回收掉.

Java 中數(shù)組, String, 以及自定義的類都是引用類型.

由于 String 是引用類型, 因此對(duì)于以下代碼

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

內(nèi)存布局如圖

那么有同學(xué)可能會(huì)說, 是不是修改 str1 , str2 也會(huì)隨之變化呢?

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

我們發(fā)現(xiàn), “修改” str1 之后, str2 也沒發(fā)生變化, 還是 hello?

事實(shí)上,

str1 = "world"

這樣的代碼并不算 “修改” 字符串, 而是讓 str1 這個(gè)引用指向一個(gè)新String 對(duì)象.(這里我們修改的是指向,而非字符串本身)

提問:我們是否可以通過str1修改"Hello" --> “World”

答:做不到?。?!

下面為大家討論一下傳字符串和字符數(shù)組返回時(shí)我們本身的字符串和字符數(shù)組是否會(huì)修改的問題:

public class TestDemo {
    public static void func(String s,char[] array) {
        s = "xiangxinhang";
        array[0] = 'p';
    }
    public static void main(String[] args) {
        String str = "abcdef";
        char[] chars = {'b','i','t'};
        func(str,chars);
        System.out.println(str);
        System.out.println(Arrays.toString(chars));
    }

下面是內(nèi)存圖 圖解:

下面圖中為大家講解了為何字符串str和字符數(shù)組chars改變的值不一樣。

字符串比較相等

如果現(xiàn)在有兩個(gè)int型變量,判斷其相等可以使用 == 完成。

public static void main(String[] args) {
int x = 10 ;
int y = 10 ;
System.out.println(x == y);
}

運(yùn)行結(jié)果如下圖所示:

如果說現(xiàn)在在String類對(duì)象上使用 == ?

代碼1

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

運(yùn)行結(jié)果如下圖所示:

這里我們str1的"hello"在使用完后放入常量池,str2在賦值時(shí)我們直接取常量池中的"hello",所以這里我們的str1和str2相等。

代碼2

public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = "He" + "llo";
    System.out.println(str1 == str2);
}

運(yùn)行結(jié)果如下圖所示:

這里我們str2的"hello"雖然是拼接起來的,但是我們編譯器還是會(huì)認(rèn)為它就是"hello",然后直接從常量池中取出我們str1之前存放的"hello",從而str1和str2相等。

代碼3

public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = "He" + "llo";
    String str3 = "He";
    String str4 = str3 + "llo";
    System.out.println(str1 == str4);
}

運(yùn)行結(jié)果如下圖所示:

此時(shí)str3是一個(gè)變量–>編譯的時(shí)候不知道是啥,所以我們的str4再創(chuàng)建"He"時(shí)用的字符串不是從常量池拿的,因此我們str1和str4不相等。

看起來貌似沒啥問題, 再換個(gè)代碼試試, 發(fā)現(xiàn)情況不太妙.

代碼4

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

我們來分析兩種創(chuàng)建 String 方式的差異.

代碼1內(nèi)存布局

我們發(fā)現(xiàn), str1 和 str2 是指向同一個(gè)對(duì)象的. 此時(shí)如 “Hello” 這樣的字符串常量是在 字符串常量池 中.

關(guān)于字符串常量池

如 “Hello” 這樣的字符串字面值常量, 也是需要一定的內(nèi)存空間來存儲(chǔ)的. 這樣的常量具有一個(gè)特點(diǎn), 就是不需要修改(常量嘛). 所以如果代碼中有多個(gè)地方引用都需要使用 “Hello” 的話, 就直接引用到常量池的這個(gè)位置就行了, 而沒必要把 “Hello” 在內(nèi)存中存儲(chǔ)兩次.

代碼4內(nèi)存布局

通過

String str1 = new String("Hello");

這樣的方式創(chuàng)建的 String 對(duì)象相當(dāng)于再堆上另外開辟了空間來存儲(chǔ)"Hello" 的內(nèi)容, 也就是內(nèi)存中存在兩份 “Hello”.

String 使用 == 比較并不是在比較字符串內(nèi)容, 而是比較兩個(gè)引用是否是指向同一個(gè)對(duì)象.

關(guān)于對(duì)象的比較

面向?qū)ο缶幊陶Z言中, 涉及到對(duì)象的比較, 有三種不同的方式, 比較身份, 比較值, 比較類型.

在大部分編程語言中 == 是用來比較比較值的. 但是 Java 中的 == 是用來比較身份的.

如何理解比較值和比較身份呢?

可以想象一個(gè)場(chǎng)景, 現(xiàn)在取快遞, 都有包裹儲(chǔ)物柜. 上面有很多的格子. 每個(gè)格子里面都放著東西.

例如, “第二行, 左數(shù)第一列” 這個(gè)柜子和 “第二行, 右數(shù)第二列” 這個(gè)柜子是同一個(gè)柜子, 就是 身份相同. 如果身份相同, 那么里面放的東西一定也相同 (值一定也相同).

例如, “第一行, 左數(shù)第一列” 這個(gè)柜子和 “第一行, 左數(shù)第二列” 這兩個(gè)柜子不是同一個(gè)柜子, 但是柜子打開后發(fā)現(xiàn)里面放著的是完全一模一樣的兩雙鞋子. 這個(gè)時(shí)候就是 值相同.

Java 中要想比較字符串的內(nèi)容, 必須采用String類提供的equals方法.

    public static void main(String[] args) {
        String str1 = new String("Hello");
        String str2 = new String("Hello");
        System.out.println(str1.equals(str2));
// System.out.println(str2.equals(str1)); // 或者這樣寫也行
    }

equals 使用注意事項(xiàng)

現(xiàn)在需要比較 str 和 “Hello” 兩個(gè)字符串是否相等, 我們?cè)撊绾蝸韺懩?

String str = new String("Hello");

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

在上面的代碼中, 哪種方式更好呢?

我們更推薦使用 “方式二”. 一旦 str 是 null, 方式一的代碼會(huì)拋出異常, 而方式二不會(huì).(即equals前面的字符串必須不為null,否則會(huì)空指針異常)

String str = null;

// 方式一
System.out.println(str.equals("Hello"));  // 執(zhí)行結(jié)果 拋出 java.lang.NullPointerException 異常
// 方式二
System.out.println("Hello".equals(str));  // 執(zhí)行結(jié)果 false

方式一:

方式二:

注意事項(xiàng): “Hello” 這樣的字面值常量, 本質(zhì)上也是一個(gè) String 對(duì)象, 完全可以使用 equals 等 String 對(duì)象的方法.

字符串常量池

在上面的例子中, String類的兩種實(shí)例化操作, 直接賦值和 new 一個(gè)新的 String.

a) 直接賦值

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

為什么現(xiàn)在并沒有開辟新的堆內(nèi)存空間呢?

String類的設(shè)計(jì)使用了共享設(shè)計(jì)模式

在JVM底層實(shí)際上會(huì)自動(dòng)維護(hù)一個(gè)對(duì)象池(字符串常量池)

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

理解 “池” (pool)

“池” 是編程中的一種常見的, 重要的提升效率的方式, 我們會(huì)在未來的學(xué)習(xí)中遇到各種 “內(nèi)存池”, “線程池”, “數(shù)據(jù)庫(kù)連接池” …

然而池這樣的概念不是計(jì)算機(jī)獨(dú)有, 也是來自于生活中. 舉個(gè)栗子:

現(xiàn)實(shí)生活中有一種女神, 稱為 “綠茶”, 在和高富帥談著對(duì)象的同時(shí), 還可能和別的屌絲搞曖昧. 這時(shí)候這個(gè)屌絲被稱為 “備胎”. 那么為啥要有備胎? 因?yàn)橐坏┖透吒粠浄质至? 就可以立刻找備胎接盤, 這樣 效率比較高.

如果這個(gè)女神, 同時(shí)在和很多個(gè)屌絲搞曖昧, 那么這些備胎就稱為 備胎池.

b) 采用構(gòu)造方法

類對(duì)象使用構(gòu)造方法實(shí)例化是標(biāo)準(zhǔn)做法。分析如下程序:

String str = new String("hello");

這樣的做法有兩個(gè)缺點(diǎn):

1.如果使用String構(gòu)造方法就會(huì)開辟兩塊堆內(nèi)存空間,并且其中一塊堆內(nèi)存將成為垃圾空間(字符串常量 “hello” 也是一個(gè)匿名對(duì)象, 用了一次之后就不再使用了, 就成為垃圾空間, 會(huì)被 JVM 自動(dòng)回收掉).

2.字符串共享問題. 同一個(gè)字符串可能會(huì)被存儲(chǔ)多次, 比較浪費(fèi)空間.

我們可以使用 String 的 intern 方法來手動(dòng)把 String 對(duì)象加入到字符串常量池中

// 該字符串常量并沒有保存在對(duì)象池之中
String str1 = new String("hello") ;
String str2 = "hello" ; 
System.out.println(str1 == str2);

// 執(zhí)行結(jié)果
//false

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

// 執(zhí)行結(jié)果
//true

面試題:請(qǐng)解釋String類中兩種對(duì)象實(shí)例化的區(qū)別

1.直接賦值:只會(huì)開辟一塊堆內(nèi)存空間,并且該字符串對(duì)象可以自動(dòng)保存在對(duì)象池中以供下次使用。

2.構(gòu)造方法:會(huì)開辟兩塊堆內(nèi)存空間,不會(huì)自動(dòng)保存在對(duì)象池中,可以使用intern()方法手工入池。

綜上, 我們一般采取直接賦值的方式創(chuàng)建 String 對(duì)象.

理解字符串不可變

字符串是一種不可變對(duì)象. 它的內(nèi)容不可改變.

String 類的內(nèi)部實(shí)現(xiàn)也是基于 char[] 來實(shí)現(xiàn)的, 但是 String 類并沒有提供 set 方法之類的來修改內(nèi)部的字符數(shù)組.

public static void main(String[] args) {
    String str = "hello";
    str = str + "world";
    str += "!!!";
    System.out.println(str);
}

形如 += 這樣的操作, 表面上好像是修改了字符串, 其實(shí)不是. 內(nèi)存變化如下:

+= 之后 str 打印的結(jié)果卻是變了, 但是不是 String 對(duì)象本身發(fā)生改變, 而是 str 引用到了其他的對(duì)象.

回顧引用

引用相當(dāng)于一個(gè)指針, 里面存的內(nèi)容是一個(gè)地址. 我們要區(qū)分清楚當(dāng)前修改到底是修改了地址對(duì)應(yīng)內(nèi)存的內(nèi)容發(fā)生改變了, 還是引用中存的地址改變了.

那么如果實(shí)在需要修改字符串, 例如, 現(xiàn)有字符串 str = “Hello” , 想改成 str = “hello” , 該怎么辦?

a) 常見辦法: 借助原字符串, 創(chuàng)建新的字符串

public class TestDemo {
    public static void main(String[] args) {
        String str = "Hello";
        str = "h" + str.substring(1);
        System.out.println(str);
    }

b) 特殊辦法: 使用 “反射” 這樣的操作可以破壞封裝, 訪問一個(gè)類內(nèi)部的 private 成員.

IDEA 中 ctrl + 左鍵 跳轉(zhuǎn)到 String 類的定義, 可以看到內(nèi)部包含了一個(gè) char[] , 保存了字符串的內(nèi)容.

public class TestDemo {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        String str = "Hello";
// 獲取 String 類中的 value 字段. 這個(gè) value 和 String 源碼中的 value 是匹配的.
        Field valueField = String.class.getDeclaredField("value");
// 將這個(gè)字段的訪問屬性設(shè)為 true
        valueField.setAccessible(true);
// 把 str 中的 value 屬性獲取到.
        char[] value = (char[]) valueField.get(str);
// 修改 value 的值
        value[0] = 'h';
        System.out.println(str);
    }

關(guān)于反射

反射是面向?qū)ο缶幊痰囊环N重要特性, 有些編程語言也稱為 “自省”.

指的是程序運(yùn)行過程中, 獲取/修改某個(gè)對(duì)象的詳細(xì)信息(類型信息, 屬性信息等), 相當(dāng)于讓一個(gè)對(duì)象更好的 “認(rèn)清自己” .

為什么 String 要不可變?(不可變對(duì)象的好處是什么?)

1.方便實(shí)現(xiàn)字符串對(duì)象池. 如果 String 可變, 那么對(duì)象池就需要考慮何時(shí)深拷貝字符串的問題了.

2.不可變對(duì)象是線程安全的.

3.不可變對(duì)象更方便緩存 hash code, 作為 key 時(shí)可以更高效的保存到 HashMap 中.

注意事項(xiàng): 如下代碼不應(yīng)該在你的開發(fā)中出, 會(huì)產(chǎn)生大量的臨時(shí)對(duì)象, 效率比較低.

    public static void main(String[] args) {
        String str = "hello" ;
        for(int x = 0; x < 1000; x++) {
            str += x ;
        }
        System.out.println(str);
    }

注意:字符串的拼接 會(huì)被優(yōu)化為 StringBuilder對(duì)象

到此這篇關(guān)于Java-String類最全匯總(上篇)的文章就介紹到這了,下篇的內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Idea2019創(chuàng)建Springboot Web項(xiàng)目的方法步驟

    Idea2019創(chuàng)建Springboot Web項(xiàng)目的方法步驟

    這篇文章主要介紹了Idea2019創(chuàng)建Springboot Web項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 使用Java實(shí)現(xiàn)在Excel中創(chuàng)建下拉列表

    使用Java實(shí)現(xiàn)在Excel中創(chuàng)建下拉列表

    下拉列表(下拉框)可以確保用戶僅從預(yù)先給定的選項(xiàng)中進(jìn)行選擇,這樣不僅能減少數(shù)據(jù)輸入錯(cuò)誤,還能節(jié)省時(shí)間提高效率,下面我們就來看看如何在java中利用免費(fèi)庫(kù)實(shí)現(xiàn)創(chuàng)建下拉列表吧
    2024-03-03
  • 配置idea將Java與數(shù)據(jù)庫(kù)連接起來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的圖書管理系統(tǒng)

    配置idea將Java與數(shù)據(jù)庫(kù)連接起來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的圖書管理系統(tǒng)

    這篇文章主要給大家介紹了關(guān)于配置idea將Java與數(shù)據(jù)庫(kù)連接起來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的圖書管理系統(tǒng)的相關(guān)資料,本文從基于Java的圖書管理系統(tǒng)的背景、系統(tǒng)設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì)和系統(tǒng)實(shí)現(xiàn)等方面進(jìn)行了詳細(xì)的研究,需要的朋友可以參考下
    2023-12-12
  • MyBatis-Plus?實(shí)體類注解的實(shí)現(xiàn)示例

    MyBatis-Plus?實(shí)體類注解的實(shí)現(xiàn)示例

    MyBatis-Plus作為MyBatis的增強(qiáng)版,提供了一系列實(shí)用的注解,如@TableName、@TableId、@TableField等,旨在簡(jiǎn)化數(shù)據(jù)庫(kù)和Java實(shí)體類之間的映射及CRUD操作,通過這些注解,開發(fā)者可以輕松實(shí)現(xiàn)表映射、字段映射、邏輯刪除、自動(dòng)填充和樂觀鎖等功能
    2024-09-09
  • ShardingSphere jdbc實(shí)現(xiàn)分庫(kù)分表核心概念詳解

    ShardingSphere jdbc實(shí)現(xiàn)分庫(kù)分表核心概念詳解

    這篇文章主要為大家介紹了ShardingSphere jdbc實(shí)現(xiàn)分庫(kù)分表核心概念詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 快速解決List集合add元素,添加多個(gè)對(duì)象出現(xiàn)重復(fù)的問題

    快速解決List集合add元素,添加多個(gè)對(duì)象出現(xiàn)重復(fù)的問題

    這篇文章主要介紹了快速解決List集合add元素,添加多個(gè)對(duì)象出現(xiàn)重復(fù)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java編程實(shí)現(xiàn)數(shù)組轉(zhuǎn)成list及l(fā)ist轉(zhuǎn)數(shù)組的方法

    Java編程實(shí)現(xiàn)數(shù)組轉(zhuǎn)成list及l(fā)ist轉(zhuǎn)數(shù)組的方法

    這篇文章主要介紹了Java編程實(shí)現(xiàn)數(shù)組轉(zhuǎn)成list及l(fā)ist轉(zhuǎn)數(shù)組的方法,結(jié)合實(shí)例形式較為詳細(xì)的總結(jié)分析了java實(shí)現(xiàn)數(shù)組與list之間相互轉(zhuǎn)換的操作技巧,需要的朋友可以參考下
    2017-09-09
  • 詳解Java中==和equals()的區(qū)別

    詳解Java中==和equals()的區(qū)別

    這篇文章主要介紹了Java中==和equals()的區(qū)別,,==可以使用在基本數(shù)據(jù)類型變量和引用數(shù)據(jù)類型變量中,equals()是方法,只能用于引用數(shù)據(jù)類型,需要的朋友可以參考下
    2021-11-11
  • java導(dǎo)出csv格式文件的方法

    java導(dǎo)出csv格式文件的方法

    這篇文章主要為大家詳細(xì)介紹了java導(dǎo)出csv格式文件的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • kotlin java 混合代碼 maven 打包實(shí)現(xiàn)

    kotlin java 混合代碼 maven 打包實(shí)現(xiàn)

    這篇文章主要介紹了kotlin java 混合代碼 maven 打包實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03

最新評(píng)論

南溪县| 宁城县| 云龙县| 绥宁县| 湟中县| 星子县| 福安市| 淳安县| 句容市| 新昌县| 闽清县| 集安市| 河西区| 花莲市| 康马县| 嘉禾县| 柘荣县| 饶阳县| 府谷县| 文山县| 临邑县| 新宾| 南宫市| 准格尔旗| 阿拉善盟| 彰化县| 嘉义县| 应城市| 承德县| 鹤壁市| 南和县| 潢川县| 嫩江县| 德庆县| 余姚市| 平果县| 土默特右旗| 博爱县| 丹寨县| 馆陶县| 呼伦贝尔市|