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

深入理解java.lang.String類的不可變性

 更新時(shí)間:2021年06月27日 16:16:45   作者:sco5282  
不可變類只是其實(shí)例不能被修改的類。每個(gè)實(shí)例中包含的所有信息都必須在創(chuàng)建該實(shí)例的時(shí)候就提供,并且在對(duì)象的整個(gè)生命周期內(nèi)固定不變,感興趣的可以了解一下

1. 字符串 String 的不可變性

什么是不可變類?

這樣理解:
        一個(gè)對(duì)象在創(chuàng)建完成后,不能去改變它的狀態(tài),不能改變它的成員變量(如果成員變量包含基本數(shù)據(jù)類型,那么這個(gè)基本數(shù)據(jù)類型的值不能改變;如果包含引用類型,那么這個(gè)引用類型的變量不能指向別的對(duì)象)

不可變類只是其實(shí)例不能被修改的類。每個(gè)實(shí)例中包含的所有信息都必須在創(chuàng)建該實(shí)例的時(shí)候就提供,并且在對(duì)象的整個(gè)生命周期內(nèi)固定不變。為了使類不可變,要遵循下面五條規(guī)則:

  • 不要提供任何會(huì)修改對(duì)象狀態(tài)的方法
  • 保證類不會(huì)被擴(kuò)展。 一般的做法是讓這個(gè)類稱為 final 的,防止子類化,破壞該類的不可變行為
  • 使所有的域都是 final 的
  • 使所有的域都成為私有的。 防止客戶端獲得訪問被域引用的可變對(duì)象的權(quán)限,并防止客戶端直接修改這些對(duì)象
  • 確保對(duì)于任何可變性組件的互斥訪問。 如果類具有指向可變對(duì)象的域,則必須確保該類的客戶端無法獲得指向這些對(duì)象的引用

翻閱 API 文檔:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    // value 數(shù)組被 final 修飾
    private final char value[];
    ...
}

String 類代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作為此類的實(shí)例來實(shí)現(xiàn)。 這些字面值都是直接存儲(chǔ)在“方法區(qū)”的 字符串常量池

字符串是常量;它們的值在創(chuàng)建之后 不能改變,所以可以共享它們。例如:

String str = "abc";

這時(shí)就有人疑惑了:為什么 String 不可變?但我的代碼中經(jīng)常改變 String 啊,如下:

String str = "HELLO";
str = "WORLD";
System.out.println(str);    // WORLD

這樣操作,不就是將 “HELLO” 對(duì)象改變成了 “WORLD” 對(duì)象了嗎?

雖然字符串的內(nèi)容看上去從“HELLO” 變成了“WORLD”,但實(shí)際上,這已經(jīng)是生成了一個(gè)新的字符串了:

String str = "HELLO";
System.out.println(str.hashCode());  // 68624562
str = "WORLD";
System.out.println(str.hashCode());  // 82781042

變量 str 前后的 hashCode 值不一樣,說明了 str 在改變前后,指向了不同的對(duì)象。所以,變量 str 只是指向了不同對(duì)象,字符串 “HELLO”對(duì)象本身沒有被改變。

變量 str 的指向如下圖所示(jdk1.8:字符串常量位于堆中):

在這里插入圖片描述

我們也可以使用 javap 命令來查看 class 的常量池:

javap -c -v StringTest.class

執(zhí)行后,常量池信息如下:

在這里插入圖片描述

從常量池中可以看出,確實(shí)有兩個(gè)字符串對(duì)象:HELLO、WORLD

【總結(jié)】:一旦一個(gè) String 對(duì)象堆中被創(chuàng)建出來,它就無法被修改。而且,String 類的所有 API 方法都沒有改變字符串本身的值,都是返回了一個(gè)新的字符串對(duì)象。

2. String 設(shè)計(jì)成不可變類的好處

在了解了“String 是不可變”的之后,大家是不是很疑惑:為什么要把 String 設(shè)計(jì)成不可變的呢?這樣做又有什么好處呢?

主要從以下幾個(gè)角度考慮:

  • 安全可靠性:字符串在 Java 應(yīng)用程序中應(yīng)用廣泛(存儲(chǔ)敏感信息,如:用戶名、密碼、連接 url、網(wǎng)絡(luò)連接等);JVM類加載器在加載類的時(shí)也廣泛地使用它。因此,保護(hù) String 類對(duì)于提升整個(gè)應(yīng)用程序的安全性至關(guān)重要。
  • 緩存:字符串是使用最廣泛的數(shù)據(jù)結(jié)構(gòu),大量的字符串的創(chuàng)建是非常耗費(fèi)資源的。JVM 中專門開辟了一部分空間來存儲(chǔ) Java 字符串,那就是字符串常量池。通過字符串常量池,兩個(gè)內(nèi)容相同的字符串變量,可以從池中指向同一個(gè)字符串對(duì)象,從而節(jié)省了關(guān)鍵的內(nèi)存資源
  • 線程安全:不可變會(huì)自動(dòng)使字符串成為線程安全的,因?yàn)楫?dāng)從多個(gè)線程訪問它們時(shí),它們不會(huì)被更改
  • hashcode 緩存:字符串也被廣泛地用于哈希實(shí)現(xiàn),如 HashMap、HashTable、HashSet 等。在對(duì)這些散列實(shí)現(xiàn)進(jìn)行操作時(shí),經(jīng)常調(diào)用鍵的hashCode() 方法。不可變性保證了字符串的值不會(huì)改變,因此,hashCode() 方法在 String 類中被重寫,以方便緩存。這樣,在第一次hashCode() 調(diào)用期間計(jì)算和緩存散列,并從那時(shí)起返回相同的值。

3. 面試題

// 生成兩個(gè)對(duì)象:一個(gè)在常量池中;一個(gè)中堆中,且都是 hello 對(duì)象
String s = new String("hello");

那么,下面會(huì)生成幾個(gè)對(duì)象呢?

// 只會(huì)在字符串常量池中生成一個(gè)對(duì)象:helloworld。
String s3 = "hello" + "world";

這種字面量用“+”拼接,編譯器在編譯期間會(huì)直接進(jìn)行優(yōu)化。

// 這個(gè)會(huì)生成4個(gè)對(duì)象。2個(gè)在常量池中:hello、world
// 2個(gè)在堆中:StringBuilder、helloworld對(duì)象
String s = "hello";
String s2 = s + "world";

編譯后,使用反編譯軟件 ------ jad 進(jìn)行查看:

String s1 = "hell0";
String s2 = (new StringBuilder()).append(s1).append("world").toString();

發(fā)現(xiàn):使用“+”將變量和字面量進(jìn)行拼接的結(jié)果是:將 String 轉(zhuǎn)成了StringBuilder 后,使用其 append() 方法進(jìn)行處理的

查看 StringBuilder.toString() 方法源碼:

@Override
public String toString() {
	// char[] value; value 是 StringBuilder 類的成員變量
    return new String(value, 0, count);
}

最后調(diào)用 toString() 方法時(shí),會(huì)創(chuàng)建一個(gè) String 對(duì)象。這個(gè)字符串對(duì)象只會(huì)在堆中創(chuàng)建,并不會(huì)在字符串常量池中創(chuàng)建。所以,會(huì)創(chuàng)建4個(gè)對(duì)象(hello 和 world 會(huì)直接在字符串常量池中創(chuàng)建)。

到此這篇關(guān)于深入理解java.lang.String類的不可變性的文章就介紹到這了,更多相關(guān)java.lang.String不可變性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM之方法返回地址詳解

    JVM之方法返回地址詳解

    這篇文章主要介紹了JVM之方法返回地址詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Spring AOP注解案例及基本原理詳解

    Spring AOP注解案例及基本原理詳解

    這篇文章主要介紹了Spring AOP注解案例及基本原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java線程間通信不同步問題原理與模擬實(shí)例

    Java線程間通信不同步問題原理與模擬實(shí)例

    這篇文章主要介紹了Java線程間通信不同步問題,結(jié)合實(shí)例形式分析了java線程間通信不同步問題的原理并模擬實(shí)現(xiàn)了線程間通信不同步情況下的異常輸出,需要的朋友可以參考下
    2019-10-10
  • 詳解SpringBoot配置文件啟動(dòng)時(shí)動(dòng)態(tài)配置參數(shù)方法

    詳解SpringBoot配置文件啟動(dòng)時(shí)動(dòng)態(tài)配置參數(shù)方法

    這篇文章主要介紹了詳解SpringBoot配置文件啟動(dòng)時(shí)動(dòng)態(tài)配置參數(shù)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • JAVA十大排序算法之冒泡排序詳解

    JAVA十大排序算法之冒泡排序詳解

    這篇文章主要介紹了java中的冒泡排序,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • Java中Map實(shí)現(xiàn)線程安全的3種方式

    Java中Map實(shí)現(xiàn)線程安全的3種方式

    本文主要介紹了Java中Map實(shí)現(xiàn)線程安全的3種方式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • struts2的流程和一系列相關(guān)知識(shí)代碼解析

    struts2的流程和一系列相關(guān)知識(shí)代碼解析

    這篇文章主要介紹了struts2的流程和一系列相關(guān)知識(shí)代碼解析,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項(xiàng)目的超詳細(xì)教程

    IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項(xiàng)目的超詳細(xì)教程

    這篇文章主要介紹了IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項(xiàng)目的教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java使用OpenCV3.2實(shí)現(xiàn)視頻讀取與播放

    Java使用OpenCV3.2實(shí)現(xiàn)視頻讀取與播放

    這篇文章主要為大家詳細(xì)介紹了Java使用OpenCV3.2實(shí)現(xiàn)視頻讀取與播放,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • sa-token整合springboot中的代碼示例展示

    sa-token整合springboot中的代碼示例展示

    sa-token?是一個(gè)輕量級(jí)的 Java 權(quán)限認(rèn)證框架,它可以很方便地集成到 Spring Boot 項(xiàng)目中,以提供簡(jiǎn)潔的認(rèn)證和授權(quán)功能,這篇文章主要介紹了sa-token整合springboot中的代碼示例展示,需要的朋友可以參考下
    2024-04-04

最新評(píng)論

鄯善县| 两当县| 黑龙江省| 石家庄市| 永清县| 武乡县| 株洲县| 会宁县| 辽阳市| 北川| 九江市| 石泉县| 张家口市| 惠安县| 通化市| 黎城县| 乌鲁木齐县| 公主岭市| 青龙| 阿拉善右旗| 昆明市| 武隆县| 永吉县| 宜阳县| 三河市| 广元市| 讷河市| 宁波市| 进贤县| 改则县| 成安县| 连云港市| 六盘水市| 乌海市| 鸡泽县| 扎兰屯市| 民县| 沙坪坝区| 古浪县| 方正县| 潜江市|