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

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

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

一、不可變類簡介

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

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

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

1.線程安全

不可變對象是線程安全的,在線程之間可以相互共享,不需要利用特殊機(jī)制來保證同步問題,因?yàn)閷ο蟮闹禑o法改變。可以降低并發(fā)錯誤的可能性,因?yàn)椴恍枰靡恍╂i機(jī)制等保證內(nèi)存一致性問題也減少了同步開銷。

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

3....

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

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

1. 類添加final修飾符,保證類不被繼承。

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

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

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

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

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

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

如果構(gòu)造器傳入的對象直接賦值給成員變量,還是可以通過對傳入對象的修改進(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)存地址,用戶可以在ImmutableDemo之外通過修改array對象的值來改變myArray內(nèi)部的值。

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

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

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

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

四、String對象的不可變性

string對象在內(nèi)存創(chuàng)建后就不可改變,不可變對象的創(chuàng)建一般滿足以上5個原則,我們看看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類被final修飾,不可繼承

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

3.不存在value的setter

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

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

6.獲取value時不是直接返回對象引用,而是返回對象的copy.

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

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

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

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

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

2. 線程安全考慮。

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

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

4. 支持hash映射和緩存。

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

缺點(diǎn):

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

六、String對象的是否真的不可變

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

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

打印結(jié)果為:

s = Hello World
s = Hello_World 

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

總結(jié)

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

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

相關(guān)文章

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

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

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

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

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

    spring boot 監(jiān)聽容器啟動代碼實(shí)例

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

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

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

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

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

    mybatis查詢oracle long類型的踩坑記錄

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

    詳解Java的繼承

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

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

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

    Intellij IDEA中啟動多個微服務(wù)(開啟Run Dashboard管理)

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

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

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

最新評論

靖安县| 宝兴县| 繁峙县| 高淳县| 麻城市| 昭觉县| 东丰县| 涪陵区| 衡阳市| 泾川县| 长寿区| 洛浦县| 克什克腾旗| 涟水县| 隆林| 水城县| 博罗县| 镶黄旗| 扬中市| 南雄市| 西乌| 绿春县| 秦皇岛市| 酒泉市| 康平县| 咸丰县| 太白县| 长顺县| 浦城县| 友谊县| 西贡区| 舒兰市| 临猗县| 沂源县| 崇信县| 凌海市| 通化市| 新兴县| 资中县| 贵德县| 涿鹿县|