杰瑞科技汇

Java中get/set方法为何必须存在?

什么是 getset 方法?

getset 方法通常被称为 访问器(Accessor)修改器,它们是一种特殊的公共方法,用于获取和修改一个类的私有字段的值。

Java中get/set方法为何必须存在?-图1
(图片来源网络,侵删)

核心思想: 将类的字段(成员变量)设置为 private(私有),然后通过 public(公共)的 getset 方法来间接地访问和修改这些字段,这种设计模式被称为 封装


为什么需要 getset 方法?(封装的好处)

直接暴露类的字段(将字段设为 public)被认为是不好的编程实践,因为它会破坏封装性,使用 getset 方法主要有以下几个关键好处:

a) 数据保护

你可以通过 set 方法来控制对私有字段的修改,你可以添加逻辑来防止无效的值被赋给字段。

例子:

Java中get/set方法为何必须存在?-图2
(图片来源网络,侵删)
public class Person {
    private int age; // 年龄不能是负数
    // set 方法可以加入验证逻辑
    public void setAge(int age) {
        if (age >= 0) {
            this.age = age;
        } else {
            System.out.println("年龄不能为负数!");
        }
    }
    // get 方法用于安全地获取值
    public int getAge() {
        return this.age;
    }
}

agepublic 的,任何人都可以将其设为负数,但通过 setAge 方法,我们可以轻松地阻止这种情况。

b) 灵活性

将来如果需求发生变化,你只需要修改 getset 方法的内部实现,而所有调用这些方法的代码都不需要改变。

例子: 假设你决定存储年龄时,不仅要存数字,还要存一个时间戳,记录年龄是何时设置的。

public class Person {
    private int age;
    private long lastUpdatedTimestamp;
    // 修改 set 方法,增加新功能
    public void setAge(int age) {
        if (age >= 0) {
            this.age = age;
            this.lastUpdatedTimestamp = System.currentTimeMillis(); // 新增逻辑
        } else {
            System.out.println("年龄不能为负数!");
        }
    }
    // 可以新增一个 get 方法来获取时间戳
    public long getLastUpdatedTimestamp() {
        return this.lastUpdatedTimestamp;
    }
    // getAge 方法保持不变
    public int getAge() {
        return this.age;
    }
}

所有调用 person.setAge(25) 的地方都无需修改,但它们现在享受到了记录时间戳的新功能。

Java中get/set方法为何必须存在?-图3
(图片来源网络,侵删)

c) 便于调试和日志记录

你可以在 getset 方法中轻松地添加日志或断点,来跟踪哪些代码在何时访问或修改了你的数据。

例子:

public void setAge(int age) {
    System.out.println("尝试设置年龄为: " + age); // 调试日志
    if (age >= 0) {
        this.age = age;
    } else {
        System.out.println("年龄不能为负数!");
    }
}

d) 延迟计算

get 方法可以不直接返回一个存储的值,而是动态计算并返回。

例子:

public class Circle {
    private double radius;
    public Circle(double radius) {
        this.radius = radius;
    }
    // get 方法用于计算面积,而不是存储它
    public double getArea() {
        System.out.println("正在计算面积..."); // 日志
        return Math.PI * radius * radius;
    }
}

getset 方法的命名约定

在 Java 中,有非常明确的命名约定来遵循:

  • set 方法:

    • 方法名以 set 开头。
    • 后面紧跟字段名的首字母大写形式,这个过程称为 PascalCase驼峰命名法
    • 有且仅有一个参数,参数类型与字段类型相同,参数名通常与字段名相同。
    • 返回类型为 void

    格式: public void setFieldName(fieldType fieldName) { ... }

  • get 方法:

    • 方法名以 get 开头。
    • 后面紧跟字段名的首字母大写形式。
    • 没有参数。
    • 返回类型与字段类型相同。

    格式: public fieldType getFieldName() { ... }

布尔类型的特例: 对于布尔类型的字段(boolean),get 方法的命名有一个常见的替代方案,可以读起来更像一个自然的问题。

  • 标准命名:public boolean isAlive() { ... }
  • 也可以使用:public boolean getAlive() { ... } (虽然不常见,但语法正确)

推荐使用 is 前缀,因为它更符合英语习惯。


代码示例

下面是一个完整的、遵循上述约定的 Student 类示例。

// Student.java
public class Student {
    // 1. 将字段设为 private,实现数据隐藏
    private String name;
    private int age;
    private boolean isGraduated;
    // 2. 提供一个公共的构造器来初始化对象
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        this.isGraduated = false; // 默认值
    }
    // ====== Getter 方法 ======
    // 用于获取私有字段的值
    public String getName() {
        return this.name;
    }
    public int getAge() {
        return this.age;
    }
    public boolean isGraduated() { // 布尔类型使用 is 前缀
        return this.isGraduated;
    }
    // ====== Setter 方法 ======
    // 用于修改私有字段的值
    public void setName(String name) {
        // 可以在这里添加验证逻辑,name 不能为 null 或空字符串
        if (name != null && !name.trim().isEmpty()) {
            this.name = name;
        } else {
            System.out.println("姓名不能为空!");
        }
    }
    public void setAge(int age) {
        if (age > 0) {
            this.age = age;
        } else {
            System.out.println("年龄必须大于 0!");
        }
    }
    public void setGraduated(boolean graduated) {
        isGraduated = graduated;
    }
}

如何使用这个类:

// Main.java
public class Main {
    public static void main(String[] args) {
        // 创建一个 Student 对象
        Student student1 = new Student("张三", 20);
        // 使用 get 方法获取值
        System.out.println("学生姓名: " + student1.getName()); // 输出: 学生姓名: 张三
        System.out.println("学生年龄: " + student1.getAge());   // 输出: 学生年龄: 20
        System.out.println("是否毕业: " + student1.isGraduated()); // 输出: 是否毕业: false
        // 使用 set 方法修改值
        student1.setAge(21);
        System.out.println("修改后的年龄: " + student1.getAge()); // 输出: 修改后的年龄: 21
        // 尝试设置一个无效的年龄
        student1.setAge(-5); // 输出: 年龄必须大于 0!
        System.out.println("年龄仍然是: " + student1.getAge()); // 输出: 年龄仍然是: 21
        // 尝试设置一个无效的姓名
        student1.setName(""); // 输出: 姓名不能为空!
        System.out.println("姓名仍然是: " + student1.getName()); // 输出: 姓名仍然是: 张三
    }
}

现代 Java 的简化:Lombok

手动为每个字段编写 getset 方法(以及 toString, equals, hashCode 等)会非常繁琐且容易出错,为了解决这个问题,社区和工具库提供了很多简化方案,其中最流行的是 Lombok

Lombok 通过注解在编译时自动为你生成这些样板代码。

使用 Lombok 的 Student 类:

import lombok.Getter;
import lombok.Setter;
@Getter // 为所有 private 字段生成 get 方法
@Setter // 为所有 private 字段生成 set 方法
public class Student {
    private String name;
    private int age;
    private boolean isGraduated;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        this.isGraduated = false;
    }
}

或者,你可以更精确地控制:

import lombok.Getter;
import lombok.Setter;
public class Student {
    @Getter // 只为 name 生成 get 方法
    private String name;
    @Setter @Getter // 为 age 生成 set 和 get 方法
    private int age;
    @Getter // 只为 isGraduated 生成 get 方法 (会命名为 isGraduated)
    private boolean isGraduated;
    // ... 构造器 ...
}

使用 Lombok 后,你的 Main 类调用方式完全不变,但代码量大大减少,可读性更高,Lombok 已经成为现代 Java 项目中非常常见的工具。


特性 描述
目的 实现 封装,是面向对象编程的四大特性之一。
核心 将字段设为 private,通过 publicget/set 方法访问。
好处 数据保护、灵活性、便于调试、支持延迟计算。
命名 setFieldName(fieldType field)getFieldName(),布尔类型可用 isFieldName()
现代实践 使用 Lombok 等工具自动生成 get/set 方法,减少样板代码,提高开发效率。

掌握 getset 方法是理解 Java 面向对象编程的基石,它不仅是一种语法,更是一种重要的设计思想。

分享:
扫描分享到社交APP
上一篇
下一篇