国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java不可變類機制

2019-11-06 08:08:32
字體:
來源:轉載
供稿:網友

不可變類(Immutable Class):所謂的不可變類是指這個類的實例一旦創建完成后,就不能改變其成員變量值。如JDK內部自帶的很多不可變類:Interger、Long和String等。

可變類(Mutable Class):相對于不可變類,可變類創建實例后可以改變其成員變量值,開發中創建的大部分類都屬于可變類。

不可變類的特性對java來說帶來怎樣的好處?

1)線程安全:不可變對象是線程安全的,在線程之間可以相互共享,不需要利用特殊機制來保證同步問題,因為對象的值無法改變。可以降低并發錯誤的可能性,因為不需要用一些鎖機制等保證內存一致性問題也減少了同步開銷。

2)易于構造、使用和測試。

不可變類的設計原則

如何在Java中寫出Immutable的類?要寫出這樣的類,需要遵循以下幾個原則:

1)immutable對象的狀態在創建之后就不能發生改變,任何對它的改變都應該產生一個新的對象。

2)Immutable類的所有的成員都應該是PRivate final的。通過這種方式保證成員變量不可改變。但只做到這一步還不夠,因為如果成員變量是對象,它保存的只是引用,有可能在外部改變其引用指向的值,所以第5點彌補這個不足

3)對象必須被正確的創建,比如:對象引用在對象創建過程中不能泄露。

4)只提供讀取成員變量的get方法,不提供改變成員變量的set方法,避免通過其他接口改變成員變量的值,破壞不可變特性。

5)類應該是final的,保證類不被繼承,如果類可以被繼承會破壞類的不可變性機制,只要繼承類覆蓋父類的方法并且繼承類可以改變成員變量值,那么一旦子類以父類的形式出現時,不能保證當前類是否可變。

6)如果類中包含mutable類對象,那么返回給客戶端的時候,返回該對象的一個深拷貝,而不是該對象本身(該條可以歸為第一條中的一個特例)

如果將構造器傳入的對象直接賦值給成員變量,還是可以通過對傳入對象的修改進而導致改變內部變量的值。例如:

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

這種方式不能保證不可變性,myArray和array指向同一塊內存地址,用戶可以在ImmutableDemo之外通過修改array對象的值來改變myArray內部的值。為了保證內部的值不被修改,可以采用深度copy來創建一個新內存保存傳入的值。正確做法:

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

String類的不可變實現

String對象在內存創建后就不可改變,不可變對象的創建一般滿足以上原則,我們看看String代碼是如何實現的。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; /** The value is used for character storage. */ /** 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; private int hash; // Default to 0 .... public String(char value[]) { this.value = Arrays.copyOf(value, value.length); // deep copy操作 } public char[] toCharArray() { char result[] = new char[value.length]; System.arraycopy(value, 0, result, 0, value.length); return result; } ... }

如代碼所示,可以觀察到String類的設計符合上面總結的不變類型的設計原則。雖然String對象將value設置為final,并且還通過各種機制保證其成員變量不可改變。但是還是可以通過反射機制改變其值。例如:

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

上面的方式,其實并沒有改變value的內存地址,而是改變了數組的內部結構,內部結構并不是final的,采用下面的方式,直接修改value的內存地址:

String s = "Hello World"; //創建字符串"Hello World", 并賦給引用s System.out.println("s = " + s); //獲取String類中的value字段 Field valueFieldOfString = String.class.getDeclaredField("value"); valueFieldOfString.setAccessible(true); //改變value屬性的訪問權限 valueFieldOfString.set(s, "hello_world".toCharArray());

打印結果為:

s = Hello Worlds = Hello_World

發現String的值已經發生了改變。也就是說,通過反射是可以修改所謂的“不可變”對象的。

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

轉載:http://blog.csdn.net/fuzhongmin05/article/details/54880139

延伸:

關于field反射:http://www.360doc.com/content/11/1231/14/1954236_176297236.shtml final關鍵詞在多線程環境中的使用:http://blog.csdn.net/xiaoxiaoxuanao/article/details/52573859 深入理解Java內存模型(六)——final: http://www.infoq.com/cn/articles/java-memory-model-6


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 罗定市| 沂水县| 平利县| 宣化县| 永川市| 宣汉县| 芜湖县| 海盐县| 奎屯市| 林州市| 罗甸县| 唐海县| 昌图县| 庐江县| 浮山县| 三河市| 天柱县| 盐山县| 长沙市| 葫芦岛市| 闻喜县| 肥乡县| 淳安县| 仲巴县| 鱼台县| 山西省| 织金县| 阿拉尔市| 祁东县| 柘城县| 河源市| 浮梁县| 大石桥市| 溧水县| 汤原县| 乌海市| 滁州市| 栾川县| 兴义市| 且末县| 西吉县|