这不仅仅是一个语法问题,更是一种核心的编程思想——封装。

为什么需要 get 和 set 方法?
想象一下你在写一个 Student 类,用来表示一个学生:
public class Student {
public String name;
public int age;
}
你可以这样使用它:
Student student = new Student(); student.name = "张三"; student.age = -5; // 问题出现了!年龄可以是负数吗?
上面的代码中,student.age = -5 显然是不合逻辑的,但我们无法在 Student 类内部阻止这种不合理的赋值,这就是直接暴露成员变量的弊端。
get 和 set 方法就是为了解决这个问题而生的,它们是实现封装 的标准方式。

封装的核心思想:
- 隐藏内部实现:类的内部数据(成员变量)不应该被外部直接访问和修改。
- 提供受控的访问:通过公共的方法(
get和set)来暴露对数据的操作,这样我们可以在方法内部添加逻辑,确保数据的有效性和安全性。
get 和 set 方法的命名和语法
语法规范
-
set方法 (Setter / Mutator - 设置器/修改器):- 作用:用于给成员变量赋值。
- 命名:通常以
set开头,后跟成员变量的首字母大写的名称,变量是name,方法就叫setName。 - 参数:必须有一个参数,参数类型与成员变量类型相同,参数值就是我们要设置的值。
- 返回值:通常是
void。
public void set成员变量类型 成员变量名(成员变量类型 参数名) { // 赋值逻辑 this.成员变量名 = 参数名; } -
get方法 (Getter / Accessor - 访问器):- 作用:用于获取成员变量的值。
- 命名:通常以
get开头,后跟成员变量的首字母大写的名称,变量是name,方法就叫getName。 - 参数:通常没有参数。
- 返回值:返回成员变量的类型。
public 成员变量类型 get成员变量名() { // 返回逻辑 return this.成员变量名; }
注意:对于布尔类型的成员变量,
get方法有时会遵循一个特殊的命名规范,用is代替get。boolean isPassed,其get方法可以命名为isPassed(),但这不是强制性的,getPassed()也是可以的。(图片来源网络,侵删)
代码示例
我们用 get 和 set 方法来重构之前的 Student 类:
public class Student {
// 1. 成员变量设为 private,禁止外部直接访问
private String name;
private int age;
// 2. 提供 public 的 get 和 set 方法
// name 的 get 方法
public String getName() {
return this.name;
}
// name 的 set 方法
public void setName(String name) {
// 可以在这里添加逻辑,比如不允许 name 为 null 或空字符串
if (name != null && !name.trim().isEmpty()) {
this.name = name;
} else {
System.out.println("姓名不能为空!");
}
}
// age 的 get 方法
public int getAge() {
return this.age;
}
// age 的 set 方法,加入数据校验逻辑
public void setAge(int age) {
// 确保年龄在合理范围内
if (age > 0 && age < 120) {
this.age = age;
} else {
System.out.println("年龄必须在 1 到 119 岁之间!");
}
}
}
我们再来看如何使用这个改进后的 Student 类:
public class Main {
public static void main(String[] args) {
Student student = new Student();
// 使用 set 方法赋值
student.setName("李四");
student.setAge(20); // 合法
// 尝试设置非法值
student.setAge(-5); // 会打印 "年龄必须在 1 到 119 岁之间!"
student.setName(""); // 会打印 "姓名不能为空!"
// 使用 get 方法获取值
System.out.println("学生姓名: " + student.getName()); // 输出 "学生姓名: 李四"
System.out.println("学生年龄: " + student.getAge()); // 输出 "学生年龄: 20" (非法赋值失败,年龄未被修改)
}
}
通过这种方式,我们成功地控制了对 name 和 age 的访问,保证了数据的合法性。
get 和 set 方法的好处总结
- 数据校验:可以在
set方法中添加校验逻辑,防止非法数据被赋值(如年龄为负数、分数超过100等)。 - 封装性:隐藏了类的内部实现细节,未来如果
Student类的name存储方式变了(比如从String变成了ID和DisplayName的组合),我们只需要修改Student类内部的get和set方法,而所有使用这个类的代码都不需要改动,这大大提高了代码的可维护性。 - 控制读写权限:
- 如果一个成员变量只希望被读取,不希望被修改,可以只提供
get方法,不提供set方法。 - 如果一个成员变量不希望被外部访问,可以既不提供
get也不提供set方法。
- 如果一个成员变量只希望被读取,不希望被修改,可以只提供
- 附加逻辑:可以在
get或set方法中执行额外的操作。get示例:每次获取salary时,可以自动计算并加上奖金。set示例:每次设置password时,可以自动进行加密处理。
现代 Java 中的 get 和 set
虽然手动编写 get 和 set 方法是基础,但在实际开发中,我们通常会使用一些工具来自动生成它们,以减少重复劳动。
使用 IDE(如 IntelliJ IDEA, Eclipse)生成
几乎所有现代 Java IDE 都支持一键生成 get 和 set 方法。
- IntelliJ IDEA: 在代码编辑区右键 ->
Generate->Getter and Setter...-> 选择要生成的变量 -> 点击OK。 - Eclipse: 在代码编辑区右键 ->
Source->Generate Getters and Setters...-> 选择变量 -> 点击Generate。
IDE 会自动遵循命名规范,并处理好 this 关键字。
使用 Lombok 库(非常流行)
Lombok 是一个 Java 库,它通过注解的方式,在编译时自动为你的类生成 get、set、toString()、equals()、hashCode() 等样板代码。
使用 Lombok 可以让你的代码变得极其简洁。
你需要在项目中添加 Lombok 依赖(在 Maven 的 pom.xml 中):
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version> <!-- 使用最新版本 -->
<scope>provided</scope>
</dependency>
你的 Java 类可以这样写:
import lombok.Getter;
import lombok.Setter;
@Getter // 为所有 private 成员变量自动生成 get 方法
@Setter // 为所有 private 成员变量自动生成 set 方法
public class Student {
private String name;
private int age;
}
或者,你可以更精细地控制,只为特定变量生成:
import lombok.Getter;
import lombok.Setter;
public class Student {
@Getter // 只为 name 生成 get 方法
private String name;
@Setter // 只为 age 生成 set 方法
private int age;
}
使用方式完全一样,但你的源代码却无比清爽。
| 特性 | 手动编写 get/set |
使用 Lombok |
|---|---|---|
| 代码量 | 多,有大量样板代码 | 极少,代码简洁 |
| 可读性 | 方法分散,类可能很长 | 集中关注业务逻辑 |
| IDE 支持 | 完美支持 | 完美支持,需要安装 Lombok 插件 |
| 学习曲线 | 基础,必须掌握 | 需要学习 Lombok 注解 |
| 灵活性 | 最高,可以编写任意复杂逻辑 | 较高,但局限于 Lombok 提供的功能 |
- 对于初学者:必须学会手动编写
get和set方法,并深刻理解其背后的封装思想,这是 Java 面向对象编程的基础。 - 对于实际项目开发:强烈推荐使用 Lombok 来提高开发效率,减少重复代码,但在面试或笔试中,面试官很可能会要求你手写
get和set方法来考察你的基本功。

