Java?中?get?和?set?方法詳解及實(shí)現(xiàn)細(xì)節(jié)
一、get 和 set 方法的基礎(chǔ)認(rèn)知
1.1 定義與作用
get 方法(訪問器)和 set 方法(修改器)是面向?qū)ο缶幊讨袑?shí)現(xiàn)封裝的關(guān)鍵技術(shù)。它們提供了一種標(biāo)準(zhǔn)化的方式來訪問和修改類的私有成員變量。在 Java 等面向?qū)ο笳Z言中,為了實(shí)現(xiàn)良好的封裝性,通常會(huì)將類的成員變量聲明為 private,然后通過 public 的 get 和 set 方法來操作這些變量。
這種設(shè)計(jì)模式具有以下特點(diǎn):
- get 方法(獲取器):用于獲取私有成員變量的值,通常以"get"開頭
- set 方法(設(shè)置器):用于修改私有成員變量的值,通常以"set"開頭
- 方法訪問權(quán)限:通常設(shè)為 public 以保證外部可訪問
- 方法命名規(guī)范:遵循 JavaBean 規(guī)范,采用駝峰命名法
示例:一個(gè)完整的 User 類實(shí)現(xiàn)
public class User {
// 私有成員變量
private String name;
private int age;
private String email;
// get方法:獲取name的值
public String getName() {
return name;
}
// set方法:設(shè)置name的值
public void setName(String name) {
this.name = name;
}
// 可以添加更多getter和setter方法
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}1.2 為什么需要 get 和 set 方法
雖然直接將成員變量聲明為 public 可以簡化代碼編寫,但這種做法會(huì)導(dǎo)致嚴(yán)重的設(shè)計(jì)問題:
- 數(shù)據(jù)驗(yàn)證與控制缺失:
- 無法控制變量的賦值規(guī)則
- 例如年齡不能為負(fù)數(shù)、郵箱必須符合格式等
- 示例(帶驗(yàn)證的set方法):
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年齡不能為負(fù)數(shù)");
}
this.age = age;
}
- 內(nèi)部實(shí)現(xiàn)變更的影響:
- 當(dāng)變量的內(nèi)部實(shí)現(xiàn)改變時(shí)(如從String改為Date)
- 會(huì)影響所有直接訪問該變量的代碼
- 通過方法訪問可以保持接口穩(wěn)定
- 封裝性破壞:
- 直接暴露成員變量違反面向?qū)ο笤O(shè)計(jì)原則
- 使得類的內(nèi)部細(xì)節(jié)對外可見
- 額外功能無法添加:
- 無法在獲取或設(shè)置時(shí)執(zhí)行額外操作
- 示例(記錄訪問日志):
public String getName() {
System.out.println("訪問了name屬性");
return name;
}
- 線程安全問題:
- 無法在方法級別添加同步控制
- 示例(線程安全的getter):
public synchronized String getName() {
return name;
}
通過 get 和 set 方法,開發(fā)人員可以在不暴露內(nèi)部實(shí)現(xiàn)的前提下,安全地提供變量的訪問和修改通道,同時(shí)保持對數(shù)據(jù)訪問的完全控制。這種模式是現(xiàn)代面向?qū)ο缶幊痰淖罴褜?shí)踐之一。
二、get 和 set 方法的命名規(guī)范
遵循規(guī)范的命名方式是寫出可維護(hù)、易讀代碼的基礎(chǔ)。在 Java 中,get 和 set 方法作為訪問對象屬性的標(biāo)準(zhǔn)方式,有著嚴(yán)格的命名約定。這些約定不僅被廣泛認(rèn)可,也是 JavaBean 規(guī)范的重要組成部分。
2.1 基本命名規(guī)則詳解
get 方法命名規(guī)則
對于非布爾類型的變量:
- 命名格式為
get+ 首字母大寫的變量名 - 例如:
getName()、getAge()、getSalary() - 方法簽名示例:
public String getName() { return name; }
對于布爾類型的變量:
- 命名格式通常為
is+ 首字母大寫的變量名 - 例如:
isStudent()、isActive()、isAvailable() - 方法簽名示例:
public boolean isStudent() { return student; }
set 方法命名規(guī)則
適用于所有變量類型:
- 命名格式為
set+ 首字母大寫的變量名 - 例如:
setName()、setAge()、setStudent() - 方法簽名示例:
public void setName(String name) { this.name = name; }
2.2 命名示例與應(yīng)用場景
public class Person {
// 成員變量聲明
private String name; // 字符串類型
private int age; // 整型
private boolean married; // 布爾類型
// 正確的get/set方法命名示例
// 非布爾類型的getter
public String getName() {
return name;
}
// 非布爾類型的setter
public void setName(String name) {
this.name = name;
}
// 非布爾類型的getter
public int getAge() {
return age;
}
// 非布爾類型的setter
public void setAge(int age) {
this.age = age;
}
// 布爾類型的getter(使用is前綴)
public boolean isMarried() {
return married;
}
// 布爾類型的setter
public void setMarried(boolean married) {
this.married = married;
}
}實(shí)際應(yīng)用中的注意事項(xiàng)
- 一致性:在整個(gè)項(xiàng)目中應(yīng)保持命名風(fēng)格一致
- 特殊情況處理:
- 對于縮寫詞(如ID),應(yīng)保持首字母大寫(如
getID()而非getId()) - 對于多個(gè)單詞組成的變量名,每個(gè)單詞首字母都應(yīng)大寫(如
getFirstName())
- 對于縮寫詞(如ID),應(yīng)保持首字母大寫(如
- IDE支持:現(xiàn)代IDE(如IntelliJ IDEA、Eclipse)都提供自動(dòng)生成getter/setter的功能,可以確保遵循規(guī)范
遵循這些命名規(guī)范不僅使代碼更易讀,還能確保與各種框架(如Spring、Hibernate)的良好兼容性。
三、get 和 set 方法的實(shí)現(xiàn)細(xì)節(jié)
3.1 參數(shù)與返回值
set 方法
- 返回值:通常返回
void,表示該方法不返回任何值 - 參數(shù):參數(shù)類型必須與對應(yīng)的成員變量類型完全一致
- 例如:對于
private String name成員變量,set 方法應(yīng)為public void setName(String name) - 如果成員變量是自定義對象類型,如
private User user,則 set 方法應(yīng)為public void setUser(User user)
- 例如:對于
get 方法
- 參數(shù):不接收任何參數(shù)
- 返回值:返回值類型必須與對應(yīng)的成員變量類型完全一致
- 例如:對于
private int age成員變量,get 方法應(yīng)為public int getAge() - 如果成員變量是集合類型,如
private List<String> items,則 get 方法應(yīng)為public List<String> getItems()
- 例如:對于
3.2 方法體中的常見操作
在實(shí)際開發(fā)中,get 和 set 方法的方法體往往不只是簡單的賦值和返回,還可能包含以下高級用法:
3.2.1 參數(shù)驗(yàn)證
在 set 方法中可以加入業(yè)務(wù)邏輯驗(yàn)證,確保數(shù)據(jù)有效性:
public void setAge(int age) {
// 驗(yàn)證年齡范圍
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年齡必須在0-150之間");
}
// 驗(yàn)證通過后才賦值
this.age = age;
}
其他驗(yàn)證示例:
- 驗(yàn)證字符串非空:
if (name == null || name.trim().isEmpty()) - 驗(yàn)證郵箱格式:使用正則表達(dá)式匹配
- 驗(yàn)證數(shù)值范圍:
if (price < 0)
3.2.2 觸發(fā)事件
當(dāng)變量值改變時(shí),可以觸發(fā)相關(guān)業(yè)務(wù)邏輯:
private String address;
public void setAddress(String address) {
// 保存舊值用于比較
String oldAddress = this.address;
this.address = address;
// 只有地址真正改變時(shí)才觸發(fā)通知
if (!Objects.equals(oldAddress, address)) {
notifyAddressChanged();
}
}
private void notifyAddressChanged() {
// 實(shí)際業(yè)務(wù)邏輯可能包括:
// 1. 記錄變更日志
// 2. 發(fā)送MQ消息通知其他系統(tǒng)
// 3. 更新相關(guān)緩存
System.out.println("地址已更新為:" + this.address);
}典型應(yīng)用場景:
- 用戶資料變更通知
- 訂單狀態(tài)變更觸發(fā)業(yè)務(wù)流程
- 配置參數(shù)修改時(shí)刷新緩存
3.2.3 延遲加載
在 get 方法中實(shí)現(xiàn)資源的按需初始化:
private List<String> hobbies;
public List<String> getHobbies() {
// 第一次訪問時(shí)才初始化
if (hobbies == null) {
hobbies = new ArrayList<>();
// 可以添加默認(rèn)值
hobbies.add("閱讀");
hobbies.add("運(yùn)動(dòng)");
}
return Collections.unmodifiableList(hobbies); // 返回不可修改的視圖
}其他延遲加載場景:
- 數(shù)據(jù)庫連接的延遲建立
- 大文件的按需加載
- 復(fù)雜計(jì)算的緩存結(jié)果
注意事項(xiàng):
- 需要考慮線程安全問題
- 對于頻繁訪問的屬性可能會(huì)影響性能
- 要確保延遲初始化的對象不會(huì)導(dǎo)致空指針異常
四、get 和 set 方法的使用場景
4.1 JavaBean 規(guī)范詳解
JavaBean 規(guī)范是 Java 平臺(tái)中用于創(chuàng)建可重用組件的標(biāo)準(zhǔn)規(guī)范,其核心要求包括:
- 類訪問權(quán)限
- 類必須聲明為 public,確??梢员黄渌愖杂蓪?shí)例化和訪問。例如:
public class User {
// 類實(shí)現(xiàn)
}
- 構(gòu)造方法要求
- 必須提供一個(gè)無參的公共構(gòu)造方法,這是框架實(shí)例化對象的基礎(chǔ)。例如:
public User() {} // 默認(rèn)構(gòu)造方法
屬性訪問規(guī)范
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}- 所有成員變量應(yīng)該聲明為 private,實(shí)現(xiàn)封裝
- 通過 public 的 getter 和 setter 方法訪問屬性
- 方法命名遵循規(guī)范:getXxx()/setXxx()(布爾類型可用isXxx()) 示例:
- 框架支持優(yōu)勢
- 遵循 JavaBean 規(guī)范的類可以:
- 被 Spring 等框架自動(dòng)實(shí)例化和依賴注入
- 支持 Hibernate 等 ORM 框架的持久化操作
- 實(shí)現(xiàn)對象的深度克隆和序列化
- 方便 IDE 的代碼提示和自動(dòng)補(bǔ)全
4.2 序列化與反序列化機(jī)制
- JSON 序列化過程
- 以 Jackson 為例的序列化流程:
- 通過反射獲取所有 public 方法
- 識(shí)別 getter 方法(is/get 開頭的方法)
- 調(diào)用 getter 獲取屬性值
- 將返回值轉(zhuǎn)換為 JSON 字段
- 特殊字段處理
private transient String password; // 不會(huì)被默認(rèn)序列化
@JsonIgnore
public String getPassword() { // 顯式排除
return password;
}- 即使字段標(biāo)記為 transient,只要存在 getter 仍會(huì)被序列化
- 可使用 @JsonIgnore 注解顯式排除 示例:
- XML 序列化差異
- JAXB 等 XML 序列化工具:
- 依賴 @XmlElement 等注解配置
- 默認(rèn)也會(huì)通過 getter 訪問屬性
- 需要無參構(gòu)造方法重建對象
4.3 主流框架集成原理
Spring 框架集成
依賴注入:通過 setter 方法注入依賴對象
@Autowired
public void setService(UserService service) {
this.service = service;
}
配置綁定:@ConfigurationProperties 通過 setter 綁定配置
MyBatis 結(jié)果映射
<resultMap id="userMap" type="User">
<result property="name" column="user_name"/>
</resultMap>
- 結(jié)果集自動(dòng)映射時(shí)調(diào)用 setter 方法
- 支持通過 setter 進(jìn)行類型轉(zhuǎn)換 示例映射:
- JPA/Hibernate 特性
- 延遲加載通過 getter 方法觸發(fā)查詢
- 屬性變更檢測基于 setter 方法調(diào)用
- 支持在 setter 中添加業(yè)務(wù)邏輯:
public void setAge(int age) {
if(age < 0) throw new IllegalArgumentException();
this.age = age;
}
模板引擎支持
Thymeleaf、JSP EL 表達(dá)式等視圖技術(shù)都依賴 getter 方法訪問屬性:
<div th:text="${user.name}">...</div>
五、使用 get 和 set 方法的注意事項(xiàng)
5.1 不要過度使用
在面向?qū)ο缶幊讨?,并非所有的成員變量都需要提供 get 和 set 方法,過度使用會(huì)破壞封裝性:
- 只用于內(nèi)部計(jì)算的臨時(shí)變量,不需要對外暴露 get/set 方法
- 例如:緩存計(jì)算結(jié)果的計(jì)算器類中的臨時(shí)變量
- 這些變量通常被標(biāo)記為private且不提供任何訪問方法
- 常量(final 修飾的變量)通常只需要 get 方法,不需要 set 方法
- 例如:數(shù)據(jù)庫連接配置中的MAX_CONNECTION_SIZE
- 常量的值在初始化后就不應(yīng)被修改
- 對于不希望被修改的變量,可以只提供 get 方法
- 例如:用戶注冊時(shí)間createTime
- 這種設(shè)計(jì)模式被稱為"只讀屬性"
5.2 避免在 get/set 方法中執(zhí)行耗時(shí)操作
get 和 set 方法應(yīng)該保持簡潔高效,遵循最小驚訝原則:
- 性能影響:
- 數(shù)據(jù)庫查詢或文件IO等操作不應(yīng)放在get/set中
- 在循環(huán)中調(diào)用時(shí),如for(int i=0; i<10000; i++) obj.getValue(),性能問題會(huì)被放大
- 可讀性問題:
- 開發(fā)者通常認(rèn)為get/set是簡單的屬性訪問
- 復(fù)雜的內(nèi)部邏輯會(huì)使代碼難以理解和維護(hù)
- 替代方案:
- 將復(fù)雜操作拆分為獨(dú)立的方法,如calculateTotal()代替getTotal()
5.3 注意封裝性
- 良好的封裝是面向?qū)ο笤O(shè)計(jì)的重要原則:
- 避免鏈?zhǔn)秸{(diào)用破壞封裝:
- 不要像這樣設(shè)計(jì):public User setName(String name) {this.name=name; return this;}
- 這會(huì)導(dǎo)致set操作可以被無限鏈?zhǔn)秸{(diào)用,違反單一職責(zé)原則
- 集合類型的正確處理:
private List<String> tags = new ArrayList<>();
// 危險(xiǎn)做法:外部可以直接修改內(nèi)部集合
public List<String> getTags() {
return tags;
}
// 安全做法1:返回防御性副本
public List<String> getTags() {
return new ArrayList<>(tags);
}
// 安全做法2:返回不可修改視圖(Java)
public List<String> getTags() {
return Collections.unmodifiableList(tags);
}
// 安全做法3:使用不可變集合(Guava)
public ImmutableList<String> getTags() {
return ImmutableList.copyOf(tags);
}5.4 注意線程安全
在多線程環(huán)境下,get/set方法需要特別考慮:
- volatile關(guān)鍵字:
- 適用于基本類型的原子性操作
- 例如:private volatile int counter;
- synchronized關(guān)鍵字:
- 方法級同步:public synchronized void setValue(int value)
- 塊級同步:synchronized(this) { /* 操作 */ }
- 更高級的并發(fā)控制:
- 使用Lock接口及其實(shí)現(xiàn)類
- 使用原子類:AtomicInteger, AtomicReference等
- 對于集合,可以使用ConcurrentHashMap等并發(fā)容器
- 不可變對象:
- 最安全的做法是設(shè)計(jì)不可變對象
- 所有字段設(shè)為final,不提供setter方法
六、get 和 set 方法的自動(dòng)化工具
手動(dòng)編寫 get 和 set 方法不僅繁瑣,還容易出錯(cuò),特別是在處理大型類時(shí),需要為每個(gè)字段都編寫對應(yīng)的訪問方法,既浪費(fèi)時(shí)間又增加了代碼維護(hù)難度。在實(shí)際開發(fā)中,我們可以利用以下工具自動(dòng)生成這些方法,提高開發(fā)效率:
6.1 IDE 自帶功能
主流 IDE 都提供了快速生成 getter 和 setter 的功能:
- Eclipse:在類文件上右鍵→Source→Generate Getters and Setters,可以選擇需要生成方法的字段
- IntelliJ IDEA:使用快捷鍵 Alt+Insert→Getters and Setters,支持全選或部分選擇字段生成
- Visual Studio Code:Java 擴(kuò)展也支持類似功能,可通過命令面板調(diào)用
6.2 Lombok 框架
Lombok 是一個(gè) Java 庫,通過注解自動(dòng)生成 getter 和 setter 方法,極大簡化代碼:
import lombok.Getter;
import lombok.Setter;
// 類級別注解
@Getter @Setter
public class User {
private String name;
private int age;
// 字段級注解
@Getter(AccessLevel.PROTECTED)
private String password;
}使用 Lombok 需要:
- 在項(xiàng)目中引入依賴(Maven/Gradle)
- 在 IDE 中安裝 Lombok 插件(否則會(huì)顯示編譯錯(cuò)誤)
- 啟用注解處理(部分 IDE 需要額外配置)
Lombok 還支持生成構(gòu)造器、toString()、equals()等方法,可以顯著減少樣板代碼。
七、常見問題與解決方案
7.1 命名錯(cuò)誤導(dǎo)致框架無法識(shí)別
當(dāng) getter/setter 方法命名不規(guī)范時(shí),許多依賴反射機(jī)制的框架(如 Spring、Hibernate、Jackson 等)將無法正確識(shí)別和操作對象的屬性。
常見問題表現(xiàn):
- 框架報(bào)錯(cuò)提示找不到屬性或方法
- 序列化/反序列化時(shí)屬性丟失
- 數(shù)據(jù)綁定失敗
解決方法:
- 嚴(yán)格遵循 JavaBean 命名規(guī)范:
- getter 方法:
getXxx()(布爾屬性可以用isXxx()) - setter 方法:
setXxx(參數(shù)類型 value)
- getter 方法:
- 使用 IDE 自動(dòng)生成方法:
- 在 IntelliJ IDEA 中:右鍵 → Generate → Getter and Setter
- 在 Eclipse 中:Source → Generate Getters and Setters
- 使用 Lombok 注解自動(dòng)生成:
@Getter @Setter private String name;
7.2 子類覆蓋父類的 get/set 方法
- 當(dāng)子類需要覆蓋父類的 getter/setter 方法時(shí),需要特別注意:
- 基本規(guī)則:
- 方法簽名必須匹配(方法名和參數(shù)列表)
- 返回值類型必須兼容(相同或更具體的類型)
- 訪問修飾符不能比父類更嚴(yán)格
- Java 5+ 支持協(xié)變返回類型:
public class Parent {
public Number getValue() {
return 0;
}
}
public class Child extends Parent {
@Override
public Integer getValue() { // 合法,Integer 是 Number 的子類
return 1;
}
}- 注意事項(xiàng):
- 覆蓋 setter 方法時(shí),參數(shù)類型必須完全一致
- 避免在覆蓋的方法中改變原始語義
- 可以使用
@Override注解確保正確覆蓋
7.3 循環(huán)依賴問題
在 getter/setter 方法中調(diào)用其他對象的方法時(shí),容易形成循環(huán)依賴,導(dǎo)致以下問題:
典型場景:
class A {
private B b;
public B getB() {
if(b == null) {
b = new B();
b.setA(this); // 循環(huán)設(shè)置
}
return b;
}
}
class B {
private A a;
public A getA() {
if(a == null) {
a = new A();
a.setB(this); // 循環(huán)設(shè)置
}
return a;
}
}- 可能導(dǎo)致的問題:
- 棧溢出(StackOverflowError)
- 無限遞歸調(diào)用
- 死鎖(在多線程環(huán)境下)
- 內(nèi)存泄漏
- 解決方案:
- 避免在 getter/setter 中進(jìn)行復(fù)雜的對象初始化
- 使用延遲加載時(shí)要特別小心
- 考慮使用設(shè)計(jì)模式(如工廠模式)管理對象創(chuàng)建
- 對于必須的循環(huán)引用,可以:
- 使用弱引用(WeakReference)
- 在序列化時(shí)使用
@JsonIgnore等注解避免循環(huán) - 采用 DTO 模式斷開領(lǐng)域?qū)ο蟮闹苯雨P(guān)聯(lián)
到此這篇關(guān)于Java 中 get 和 set 方法詳解(更新版)的文章就介紹到這了,更多相關(guān)java get和set方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java8?CompletableFuture的并行處理用法
Java8中有一個(gè)工具非常有用,那就是CompletableFuture,本章主要講解CompletableFuture的并行處理用法,感興趣的小伙伴可以了解一下2022-04-04
java集合Collection實(shí)現(xiàn)類解析ArrayList?LinkedList及Vector
這篇文章主要為大家介紹了java集合Collection實(shí)現(xiàn)類解析ArrayList?LinkedList及Vector,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03
SpringBoot整合Activiti的項(xiàng)目中實(shí)現(xiàn)抄送功能
本文主要介紹了SpringBoot整合Activiti的項(xiàng)目中實(shí)現(xiàn)抄送功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2026-01-01
java如何把逗號分隔的String字符串轉(zhuǎn)int集合
這篇文章主要介紹了java實(shí)現(xiàn)把逗號分隔的String字符串轉(zhuǎn)int集合,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
深入解析Andoird應(yīng)用開發(fā)中View的事件傳遞
這篇文章主要介紹了深入解析Andoird應(yīng)用開發(fā)中View的事件傳遞,其中重點(diǎn)講解了ViewGroup的事件傳遞流程,需要的朋友可以參考下2016-02-02
Java實(shí)現(xiàn)自定義枚舉值校驗(yàn)器的示例代碼
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)自定義枚舉值校驗(yàn)器的相關(guān)資料,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-02-02
java實(shí)現(xiàn)一個(gè)簡單的網(wǎng)絡(luò)爬蟲代碼示例
這篇文章主要介紹了java實(shí)現(xiàn)一個(gè)簡單的網(wǎng)絡(luò)爬蟲代碼示例,還是挺不錯(cuò)的,這里分享給大家,需要的朋友可以參考下。2017-11-11

