Java中不可變對象(Immutable Objects)的使用
1、什么是Immutable Objects?
不可變對象指的是在創(chuàng)建之后,它們的值無法被修改的對象。這意味著如果想改變一個(gè)不可變對象的值,就需要?jiǎng)?chuàng)建一個(gè)新的對象。
在許多編程語言中,字符串和數(shù)字都是不可變的對象。例如,在 Python 中,字符串就是不可變的,因此不能像下面這樣改變字符串的值:
string = "hello" string[0] = "H" # This will raise an error
相反,你需要?jiǎng)?chuàng)建一個(gè)新的字符串對象:
new_string = "H" + string[1:]
這個(gè)新字符串就是一個(gè)全新的字符串對象,和原來的字符串對象沒有關(guān)系。
不可變對象的一個(gè)好處是它們更容易被并發(fā)程序安全地使用。因?yàn)椴豢勺儗ο笫菬o法修改的,所以不需要擔(dān)心在多線程環(huán)境下出現(xiàn)競態(tài)條件的問題。
此外,不可變對象也更容易進(jìn)行緩存和復(fù)用。因?yàn)椴豢勺儗ο蟮闹挡粫淖儯阅憧梢园踩貙⑺鼈兇鎯υ诰彺嬷?,并在需要時(shí)直接使用它們,而不需要重新計(jì)算。
所以,合理的使用不可變對象可以提高程序的安全性、并發(fā)性能和效率。
2、Java 中有哪些不可變的對象?
Java中有許多不可變的對象,以下是其中的一些:
- 字符串(String):字符串在Java中是不可變的對象。一旦創(chuàng)建了一個(gè)字符串對象,它的值就不能被修改。
- 整數(shù)(Integer)、長整數(shù)(Long)、浮點(diǎn)數(shù)(Float)和雙精度浮點(diǎn)數(shù)(Double):這些數(shù)字類型在Java中也是不可變的對象。一旦創(chuàng)建了一個(gè)數(shù)字對象,它的值就不能被修改。
- 枚舉(Enum):枚舉類型也是不可變的對象。枚舉類型中的每個(gè)元素都是一個(gè)不可變的對象。
- LocalDate、LocalTime、LocalDateTime:Java 8中的日期和時(shí)間API中的這些類也是不可變的對象。一旦創(chuàng)建了一個(gè)日期或時(shí)間對象,它的值就不能被修改。
- BigInteger、BigDecimal:這些類提供了任意精度的整數(shù)和浮點(diǎn)數(shù)運(yùn)算,也是不可變的對象。
需要注意的是,雖然以上對象的值不能被修改,但是它們的引用可以被修改。這意味著,可以創(chuàng)建新的對象來代替舊的對象,但是舊的對象本身的值不會被修改。
3、不可變對象在JVM中的存儲
Java中不可變對象通常存在JVM的方法區(qū)(Method Area)或者叫做永久代(PermGen)中。方法區(qū)是JVM中的一塊內(nèi)存區(qū)域,用于存儲類的信息、靜態(tài)變量、常量池、方法代碼等。永久代是方法區(qū)的一個(gè)實(shí)現(xiàn),用于存儲靜態(tài)文件、類文件信息、字節(jié)碼、常量池等內(nèi)容,它在Java 8之后被元空間(Metaspace)所取代。// 存儲在方法區(qū)中的常量池里
不可變對象通常在JVM啟動(dòng)時(shí)被加載并存儲在方法區(qū)或永久代中,因?yàn)樗鼈兊闹凳遣豢勺兊?,所以可以被安全地共享和重?/span>。同時(shí),這些對象在JVM生命周期內(nèi)只需要被創(chuàng)建一次,因此它們的存儲位置也通常是固定的。
需要注意的是,如果使用字符串常量或常量表達(dá)式創(chuàng)建不可變對象,這些對象也可能存儲在JVM的常量池中。常量池是方法區(qū)的一部分,用于存儲字符串常量、基本類型常量等。由于常量池中的字符串常量是不可變的,因此它們也被認(rèn)為是不可變對象。
4、在 Java 中定義Immutable Objects的方式有哪些?
在 Java 中,有多種方式可以定義不可變對象。以下是幾種常見的方式:
- 聲明類為 final:通過將類聲明為 final 類型,可以確保該類不能被繼承和修改。這樣可以確保不會發(fā)生對象狀態(tài)的改變。例如:// 不允許子類重寫方法。最簡單的就是將類聲明為final。
public final class ImmutableClass {
// ...
}
- 將所有字段設(shè)置為 final 和 private:通過將類的成員變量聲明為 final,可以確保這些變量在對象創(chuàng)建后不能被修改。例如:
public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
- 不提供 setter 方法:通過只提供 getter 方法,而不提供 setter 方法,可以確保對象的狀態(tài)不能被修改。例如:
public final class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
- 構(gòu)造對象時(shí)賦值:通過在構(gòu)造函數(shù)中初始化對象的成員變量,可以確保對象創(chuàng)建后它們的值不會改變。示例同上。
- 使用不可變集合類:Java 中的 Collections 類提供了一些不可變的集合類,如 Collections.unmodifiableList 和 Collections.unmodifiableMap,它們可以確保集合內(nèi)容在對象創(chuàng)建后不能被修改。例如:
List<String> list = new ArrayList<>();
list.add("foo");
list.add("bar");
List<String> immutableList = Collections.unmodifiableList(list);
以上是一些在 Java 中定義不可變對象的方式,這些方式可以單獨(dú)使用,也可以結(jié)合使用,以創(chuàng)建更加嚴(yán)格的不可變對象。// 在并發(fā)程序中作為鎖的對象應(yīng)該是不可變對象。
到此這篇關(guān)于Java中不可變對象(Immutable Objects)的使用的文章就介紹到這了,更多相關(guān)Java 不可變對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下
相關(guān)文章
劍指Offer之Java算法習(xí)題精講數(shù)組與二叉樹
跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化2022-03-03
java 獲取冒號后面的參數(shù)(正則)實(shí)現(xiàn)代碼
這篇文章主要介紹了java 獲取冒號后面的參數(shù)(正則)實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
java學(xué)生管理系統(tǒng)界面簡單實(shí)現(xiàn)(全)
這篇文章主要為大家詳細(xì)介紹了java學(xué)生管理系統(tǒng)界面的簡單實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
Java如何根據(jù)文件名前綴自動(dòng)分組圖片文件
一大堆文件(比如圖片)堆在一個(gè)目錄下,它們的命名規(guī)則遵循一定的格式,混在一起很難管理,所以本文小編就和大家介紹一下如何使用Java根據(jù)文件名前綴自動(dòng)分組圖片文件吧2025-05-05
Spring項(xiàng)目中Ordered接口的應(yīng)用之全局過濾器(GlobalFilter)的順序控制
在Spring框架,尤其是Spring Cloud Gateway或Spring WebFlux項(xiàng)目中,Ordered接口扮演著重要的角色,特別是在實(shí)現(xiàn)全局過濾器(GlobalFilter)時(shí),用于控制過濾器執(zhí)行的優(yōu)先級,下面將介紹如何在Spring項(xiàng)目中使用Ordered接口來管理Global Filter的執(zhí)行順序,需要的朋友可以參考下2024-06-06

