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

JAVA不可變類(lèi)(immutable)機(jī)制與String的不可變性(推薦)

 更新時(shí)間:2016年08月01日 11:12:15   作者:JohnZheng  
這篇文章主要介紹了JAVA不可變類(lèi)(immutable)機(jī)制與String的不可變性(推薦)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下

一、不可變類(lèi)簡(jiǎn)介

不可變類(lèi):所謂的不可變類(lèi)是指這個(gè)類(lèi)的實(shí)例一旦創(chuàng)建完成后,就不能改變其成員變量值。如JDK內(nèi)部自帶的很多不可變類(lèi):Interger、Long和String等。
可變類(lèi):相對(duì)于不可變類(lèi),可變類(lèi)創(chuàng)建實(shí)例后可以改變其成員變量值,開(kāi)發(fā)中創(chuàng)建的大部分類(lèi)都屬于可變類(lèi)。

二、不可變類(lèi)的優(yōu)點(diǎn)

說(shuō)完可變類(lèi)和不可變類(lèi)的區(qū)別,我們需要進(jìn)一步了解為什么要有不可變類(lèi)?這樣的特性對(duì)JAVA來(lái)說(shuō)帶來(lái)怎樣的好處?

1.線(xiàn)程安全

不可變對(duì)象是線(xiàn)程安全的,在線(xiàn)程之間可以相互共享,不需要利用特殊機(jī)制來(lái)保證同步問(wèn)題,因?yàn)閷?duì)象的值無(wú)法改變??梢越档筒l(fā)錯(cuò)誤的可能性,因?yàn)椴恍枰靡恍╂i機(jī)制等保證內(nèi)存一致性問(wèn)題也減少了同步開(kāi)銷(xiāo)。

2.易于構(gòu)造、使用和測(cè)試

3....

三、不可變類(lèi)的設(shè)計(jì)方法

對(duì)于設(shè)計(jì)不可變類(lèi),個(gè)人總結(jié)出以下原則:

1. 類(lèi)添加final修飾符,保證類(lèi)不被繼承。

如果類(lèi)可以被繼承會(huì)破壞類(lèi)的不可變性機(jī)制,只要繼承類(lèi)覆蓋父類(lèi)的方法并且繼承類(lèi)可以改變成員變量值,那么一旦子類(lèi)以父類(lèi)的形式出現(xiàn)時(shí),不能保證當(dāng)前類(lèi)是否可變。

2. 保證所有成員變量必須私有,并且加上final修飾

通過(guò)這種方式保證成員變量不可改變。但只做到這一步還不夠,因?yàn)槿绻菍?duì)象成員變量有可能再外部改變其值。所以第4點(diǎn)彌補(bǔ)這個(gè)不足。

3. 不提供改變成員變量的方法,包括setter

避免通過(guò)其他接口改變成員變量的值,破壞不可變特性。

4.通過(guò)構(gòu)造器初始化所有成員,進(jìn)行深拷貝(deep copy)

如果構(gòu)造器傳入的對(duì)象直接賦值給成員變量,還是可以通過(guò)對(duì)傳入對(duì)象的修改進(jìn)而導(dǎo)致改變內(nèi)部變量的值。例如:

public final class ImmutableDemo { 
private final int[] myArray; 
public ImmutableDemo(int[] array) { 
this.myArray = array; // wrong 
} 
}

這種方式不能保證不可變性,myArray和array指向同一塊內(nèi)存地址,用戶(hù)可以在ImmutableDemo之外通過(guò)修改array對(duì)象的值來(lái)改變myArray內(nèi)部的值。

為了保證內(nèi)部的值不被修改,可以采用深度copy來(lái)創(chuàng)建一個(gè)新內(nèi)存保存?zhèn)魅氲闹?。正確做法:

public final class MyImmutableDemo { 
private final int[] myArray; 
public MyImmutableDemo(int[] array) { 
this.myArray = array.clone(); 
} 
}

5. 在getter方法中,不要直接返回對(duì)象本身,而是克隆對(duì)象,并返回對(duì)象的拷貝

這種做法也是防止對(duì)象外泄,防止通過(guò)getter獲得內(nèi)部可變成員對(duì)象后對(duì)成員變量直接操作,導(dǎo)致成員變量發(fā)生改變。

四、String對(duì)象的不可變性

string對(duì)象在內(nèi)存創(chuàng)建后就不可改變,不可變對(duì)象的創(chuàng)建一般滿(mǎn)足以上5個(gè)原則,我們看看String代碼是如何實(shí)現(xiàn)的。

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
/** Cache the hash code for the string */
private int hash; // Default to 0
....
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length); // deep copy操作
}
...
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
...
} 

如上代碼所示,可以觀察到以下設(shè)計(jì)細(xì)節(jié):

1.String類(lèi)被final修飾,不可繼承

2.string內(nèi)部所有成員都設(shè)置為私有變量

3.不存在value的setter

4.并將value和offset設(shè)置為final。

5.當(dāng)傳入可變數(shù)組value[]時(shí),進(jìn)行copy而不是直接將value[]復(fù)制給內(nèi)部變量.

6.獲取value時(shí)不是直接返回對(duì)象引用,而是返回對(duì)象的copy.

這都符合上面總結(jié)的不變類(lèi)型的特性,也保證了String類(lèi)型是不可變的類(lèi)。

五、String對(duì)象的不可變性的優(yōu)缺點(diǎn)

從上一節(jié)分析,String數(shù)據(jù)不可變類(lèi),那設(shè)置這樣的特性有什么好處呢?我總結(jié)為以下幾點(diǎn):

1.字符串常量池的需要.

字符串常量池可以將一些字符常量放在常量池中重復(fù)使用,避免每次都重新創(chuàng)建相同的對(duì)象、節(jié)省存儲(chǔ)空間。但如果字符串是可變的,此時(shí)相同內(nèi)容的String還指向常量池的同一個(gè)內(nèi)存空間,當(dāng)某個(gè)變量改變了該內(nèi)存的值時(shí),其他遍歷的值也會(huì)發(fā)生改變。所以不符合常量池設(shè)計(jì)的初衷。

2. 線(xiàn)程安全考慮。

同一個(gè)字符串實(shí)例可以被多個(gè)線(xiàn)程共享。這樣便不用因?yàn)榫€(xiàn)程安全問(wèn)題而使用同步。字符串自己便是線(xiàn)程安全的。

3. 類(lèi)加載器要用到字符串,不可變性提供了安全性,以便正確的類(lèi)被加載。譬如你想加載java.sql.Connection類(lèi),而這個(gè)值被改成了myhacked.Connection,那么會(huì)對(duì)你的數(shù)據(jù)庫(kù)造成不可知的破壞。

4. 支持hash映射和緩存。

因?yàn)樽址遣豢勺兊模栽谒鼊?chuàng)建的時(shí)候hashcode就被緩存了,不需要重新計(jì)算。這就使得字符串很適合作為Map中的鍵,字符串的處理速度要快過(guò)其它的鍵對(duì)象。這就是HashMap中的鍵往往都使用字符串。

缺點(diǎn):

1.如果有對(duì)String對(duì)象值改變的需求,那么會(huì)創(chuàng)建大量的String對(duì)象。

六、String對(duì)象的是否真的不可變

雖然String對(duì)象將value設(shè)置為final,并且還通過(guò)各種機(jī)制保證其成員變量不可改變。但是還是可以通過(guò)反射機(jī)制的手段改變其值。例如:

//創(chuàng)建字符串"Hello World", 并賦給引用s
String s = "Hello World"; 
System.out.println("s = " + s); //Hello World
//獲取String類(lèi)中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");
//改變value屬性的訪(fǎng)問(wèn)權(quán)限
valueFieldOfString.setAccessible(true);
//獲取s對(duì)象上的value屬性的值
char[] value = (char[]) valueFieldOfString.get(s);
//改變value所引用的數(shù)組中的第5個(gè)字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World 

打印結(jié)果為:

s = Hello World
s = Hello_World 

發(fā)現(xiàn)String的值已經(jīng)發(fā)生了改變。也就是說(shuō),通過(guò)反射是可以修改所謂的“不可變”對(duì)象的

總結(jié)

不可變類(lèi)是實(shí)例創(chuàng)建后就不可以改變成員遍歷的值。這種特性使得不可變類(lèi)提供了線(xiàn)程安全的特性但同時(shí)也帶來(lái)了對(duì)象創(chuàng)建的開(kāi)銷(xiāo),每更改一個(gè)屬性都是重新創(chuàng)建一個(gè)新的對(duì)象。JDK內(nèi)部也提供了很多不可變類(lèi)如Integer、Double、String等。String的不可變特性主要為了滿(mǎn)足常量池、線(xiàn)程安全、類(lèi)加載的需求。合理使用不可變類(lèi)可以帶來(lái)極大的好處。

以上所述是小編給大家介紹的JAVA不可變類(lèi)(immutable)機(jī)制與String的不可變性(推薦),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java的帶GUI界面猜數(shù)字游戲的實(shí)現(xiàn)示例

    Java的帶GUI界面猜數(shù)字游戲的實(shí)現(xiàn)示例

    這篇文章主要介紹了Java的帶GUI界面猜數(shù)字游戲的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • springboot打印接口調(diào)用日志的實(shí)例

    springboot打印接口調(diào)用日志的實(shí)例

    這篇文章主要介紹了springboot打印接口調(diào)用日志的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • spring boot 監(jiān)聽(tīng)容器啟動(dòng)代碼實(shí)例

    spring boot 監(jiān)聽(tīng)容器啟動(dòng)代碼實(shí)例

    這篇文章主要介紹了spring boot 監(jiān)聽(tīng)容器啟動(dòng)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • java后端如何調(diào)用第三方接口(往header和body中的參數(shù)傳參)

    java后端如何調(diào)用第三方接口(往header和body中的參數(shù)傳參)

    這篇文章主要介紹了java后端如何調(diào)用第三方接口(往header和body中的參數(shù)傳參),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Spring Batch讀取txt文件并寫(xiě)入數(shù)據(jù)庫(kù)的方法教程

    Spring Batch讀取txt文件并寫(xiě)入數(shù)據(jù)庫(kù)的方法教程

    這篇文章主要給大家介紹了Spring Batch讀取txt文件并寫(xiě)入數(shù)據(jù)庫(kù)的方法,SpringBatch 是一個(gè)輕量級(jí)、全面的批處理框架。這里我們用它來(lái)實(shí)現(xiàn)文件的讀取并將讀取的結(jié)果作處理,處理之后再寫(xiě)入數(shù)據(jù)庫(kù)中的功能。需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-04-04
  • mybatis查詢(xún)oracle long類(lèi)型的踩坑記錄

    mybatis查詢(xún)oracle long類(lèi)型的踩坑記錄

    這篇文章主要介紹了mybatis查詢(xún)oracle long類(lèi)型的踩坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 詳解Java的繼承

    詳解Java的繼承

    大家好,本篇文章主要講的是詳解Java的繼承,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下,方便下次瀏覽
    2022-01-01
  • 解決調(diào)用ftpClient.retrieveFileStream(String?remoteFilePath)第二次讀取為空問(wèn)題

    解決調(diào)用ftpClient.retrieveFileStream(String?remoteFilePath)第二次讀

    這篇文章主要給大家介紹了關(guān)于如何解決調(diào)用ftpClient.retrieveFileStream(String?remoteFilePath)第二次讀取為空問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • Intellij IDEA中啟動(dòng)多個(gè)微服務(wù)(開(kāi)啟Run Dashboard管理)

    Intellij IDEA中啟動(dòng)多個(gè)微服務(wù)(開(kāi)啟Run Dashboard管理)

    這篇文章主要介紹了Intellij IDEA中啟動(dòng)多個(gè)微服務(wù)(開(kāi)啟Run Dashboard管理),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java基于Servlet和JSP實(shí)現(xiàn)登錄功能

    Java基于Servlet和JSP實(shí)現(xiàn)登錄功能

    在 Web 開(kāi)發(fā)中,用戶(hù)登錄功能是非常常見(jiàn)的模塊之一,本文將通過(guò)使用 Java Servlet 和 JSP 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的用戶(hù)登錄功能,展示如何創(chuàng)建登錄頁(yè)面、處理用戶(hù)登錄請(qǐng)求,并使用數(shù)據(jù)庫(kù)驗(yàn)證用戶(hù)信息,需要的朋友可以參考下
    2024-11-11

最新評(píng)論

正镶白旗| 绥棱县| 翼城县| 阜南县| 石景山区| 基隆市| 马山县| 惠州市| 通道| 鹰潭市| 册亨县| 普宁市| 台北县| 泰和县| 和林格尔县| 贵德县| SHOW| 奉新县| 志丹县| 紫金县| 天门市| 敖汉旗| 环江| 吉木乃县| 婺源县| 道孚县| 隆德县| 莎车县| 昭苏县| 杭州市| 柏乡县| 三亚市| 新乡市| 肥西县| 南通市| 盘山县| 辉县市| 安顺市| 阿鲁科尔沁旗| 泰兴市| 静海县|