CodeGym /课程 /JAVA 25 SELF /Getter 和 Setter:语法与最佳实践

Getter 和 Setter:语法与最佳实践

JAVA 25 SELF
第 15 级 , 课程 2
可用

1. 什么是 Getter 和 Setter

如果把对象想象成保险箱,它的私有字段就是保险箱的内容,而 getter 和 setter 是通往各个小格子的钥匙。Getter 用来查看里面有什么,Setter 则能把新的东西小心地放进去(当然,前提是不把比如说刺猬塞进文件夹里)。

Getter

Getter 是一个 public 方法,它返回 private 字段的值。它的名字通常以 get + 首字母大写的字段名开头。

public class Person {
    private String name; // 私有字段

    // 字段 name 的 getter
    public String getName() {
        return name;
    }
}

Setter

Setter 是一个 public 方法,用于修改私有字段的值。它的名字以 set + 首字母大写的字段名开头。

public class Person {
    private String name;

    // 字段 name 的 setter
    public void setName(String name) {
        this.name = name;
    }
}

针对 boolean 字段

对于 boolean 类型的字段,约定在 getter 中使用前缀 is

private boolean active;

public boolean isActive() {
    return active;
}

public void setActive(boolean active) {
    this.active = active;
}

2. 语法与命名约定

Java 很严格,但并不古板。有一套行之有效的约定,使你的代码对其他开发者(以及一个月后的你自己)更易理解。

  • Getter: public Type getImyaPolya()
  • Setter: public void setImyaPolya(Type value)
  • boolean 的 Getter: public boolean isImyaPolya()

字段名在方法名中以大写字母开头:如果字段是 age,则方法是 getAge()setAge()

这套约定遵循 JavaBeans 风格,因此 IDE、库和框架可以自动发现你的 getter 和 setter。比如在使用 Spring 或 JavaFX 时,需要的时候这些方法会被“魔法般地”调用。

3. 代码示例

我们来做一个教学项目——一个简单的“联系人”应用(类似电话本)——并为它添加正确的 getter 和 setter。

示例:带私有字段和 getter/setter 的 Contact 类

public class Contact {
    private String name;
    private String phone;
    private int age;
    private boolean favorite;

    // Getter
    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

    public int getAge() {
        return age;
    }

    public boolean isFavorite() {
        return favorite;
    }

    // Setter
    public void setName(String name) {
        this.name = name;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public void setAge(int age) {
        // 校验示例:年龄不能是负数
        if (age < 0) {
            System.out.println("年龄不能是负数!");
            return;
        }
        this.age = age;
    }

    public void setFavorite(boolean favorite) {
        this.favorite = favorite;
    }
}

在应用中的使用

Contact friend = new Contact();
friend.setName("伊万·伊万诺夫");
friend.setPhone("+1-999-123-45-67");
friend.setAge(25);
friend.setFavorite(true);

System.out.println("姓名:" + friend.getName());
System.out.println("电话:" + friend.getPhone());
System.out.println("年龄:" + friend.getAge());
System.out.println("已收藏:" + (friend.isFavorite() ? "是" : "否"));

在 setter 中进行校验的示例

请注意,我们在 setAge 中添加了一个简单的检查:如果年龄为负,就不修改字段并输出警告。这是保护对象免受不正确数据影响的简单方式。

4. 最佳实践:如何做得更好

并非所有字段都需要 public setter

有时字段应为只读——例如在创建对象时设置、之后不再改变的唯一标识符。这种情况下就不要写 setter:

public class Contact {
    private final int id; // final——初始化后无法修改

    public Contact(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    // 没有 setId!
}

使用 getter/setter 来控制访问与校验

public void setName(String name) {
    if (name == null || name.trim().isEmpty()) {
        System.out.println("姓名不能为空!");
        return;
    }
    this.name = name;
}

不要直接暴露内部的可变对象

如果你有一个字段——比如电话号码列表:

private String[] phones;

不应该通过 getter 直接返回它:

public String[] getPhones() {
    return phones; // 不推荐!
}

这样的代码允许外部代码随意修改列表——这会破坏封装!

更合理的做法:返回数组的副本:

public String[] getPhones() {
    return Arrays.copyOf(phones, phones.length); // 返回副本
}

或者直接克隆:

public String[] getPhones() {
    return phones.clone(); 
}

让 getter 和 setter 简洁明了

  • 不要在 getter/setter 中编写复杂的业务逻辑——它们的职责很简单:控制访问,并在必要时进行校验。
  • 如果字段不应该被修改——就不要提供 setter。
  • 如果字段不应该被外部访问——就不要提供 getter。

5. 在 IDE 中自动生成 getter/setter

手写访问器并不有趣,尤其当类有十来个字段时。好在现代 IDE(例如 IntelliJ IDEA、Eclipse、带插件的 VS Code)都可以自动生成。

在 IntelliJ IDEA 中

  1. 打开类,把光标放在类体内部。
  2. 按下 Alt + Insert(或 Code -> Generate...)。
  3. 选择 Getter and Setter
  4. 勾选需要的字段并点击 OK。

搞定! 你的 getter 和 setter 会像变魔法一样生成。

在 Eclipse 中

  1. 打开类。
  2. 右键 — SourceGenerate Getters and Setters...
  3. 选择字段并点击 OK。

在 VS Code(配合 Java Extension Pack)

  1. 打开类文件。
  2. 在命令面板(Ctrl+Shift+P)中输入 Generate getters and setters
  3. 按照提示操作。

6. 让你的应用更进一步:封装的实际运用

在前面的课程中,你构建了一个用于存储联系人的简单应用。现在我们可以改进它,把字段设为私有,并仅通过 getter/setter 提供访问。

改造前(反面示例):

public class Contact {
    public String name;
    public String phone;
    public int age;
}

问题:任何代码都可以这样做:

Contact c = new Contact();
c.age = -1000; // 现在我们的通讯录里出现了吸血鬼!

改造后(正面示例):

public class Contact {
    private String name;
    private String phone;
    private int age;

    public void setAge(int age) {
        if (age < 0) {
            System.out.println("年龄不能是负数!");
            return;
        }
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    // 其余的 getter/setter...
}

现在就不可能在外部不小心(或故意)把对象弄坏了。

7. 计算属性与不可变属性的 getter/setter

有时值不是存储在字段里,而是按需计算:

public class Rectangle {
    private int width;
    private int height;

    public int getArea() {
        return width * height;
    }
}

面积不需要 setter —— 它不能被直接设置,只能通过修改宽或高来改变。

8. Getter/Setter 的常见错误

错误 1:Getter/Setter 破坏了封装。
如果 getter 返回对内部可变对象的引用(例如列表),外部代码就能绕过所有检查任意修改它。这会动摇封装的根本。

错误 2:Setter 不进行数据校验。
如果 setter 只是简单赋值而不检查,你可能会得到不正确的对象状态(例如负年龄或空姓名)。

错误 3:为所有字段自动生成 setter。
IDE 可以为所有字段生成 setter,但这并不总是对的!例如标识符(id)通常不需要 setter。

错误 4:在 getter/setter 中放入复杂逻辑。
Getter 和 Setter 应当保持简洁。如果出现复杂的业务逻辑,应将其提取到单独的方法中。

错误 5:违反命名约定。
如果把 getter 命名为 fetchName() 而不是 getName(),某些框架和库将无法识别它。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION