Significance of Getters and Setters in Java – Java中获取器和设置器的意义

最后修改: 2021年 7月 20日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

Getters and Setters play an important role in retrieving and updating the value of a variable outside the encapsulating class. A setter updates the value of a variable, while a getter reads the value of a variable.

Getters和Setters在检索和更新封装类外的变量值方面发挥着重要作用。一个setter更新了一个变量的值,而一个getter则读取了一个变量的值。

In this tutorial, we’ll discuss the problems of not using getters/setters, their significance, and common mistakes to avoid while implementing them in Java.

在本教程中,我们将讨论不使用getters/setters的问题,它们的意义,以及在Java中实现它们时应避免的常见错误。

2. Life Without Getters and Setters in Java

2.Java中没有Getters和Setters的生活

Think about a situation when we want to change the state of an object based on some condition. How could we achieve that without a setter method?

想一想,当我们想根据一些条件来改变一个对象的状态时。如果没有setter方法,我们怎么能实现这个目标呢?

  • Marking the variable as public, protected, or default
  • Changing the value using a dot (.) operator

Let’s look at the consequences of doing this.

让我们来看看这样做的后果。

3. Accessing Variables Without Getters and Setters

3.不使用Getters和Setters访问变量

First, for accessing the variables outside a class without getters/setters, we have to mark those as public, protected, or default. Thus, we’re losing control over the data and compromising the fundamental OOP principle – encapsulation.

首先,对于访问类外没有getters/setters的变量,我们必须将这些变量标记为public、protected或default。这样,我们就失去了对数据的控制,并损害了基本的OOP原则 – 封装

Second, since anyone can change the non-private fields from outside the class directly, we cannot achieve immutability.

其次,由于任何人都可以从类外直接改变非私有字段,我们无法实现不可更改性。

Third, we cannot provide any conditional logic to the change of the variable. Let’s consider we have a class Employee with a field retirementAge:

第三,我们不能为变量的变化提供任何条件逻辑。让我们考虑一下,我们有一个类Employee,有一个字段retirementAge

public class Employee {
    public String name;
    public int retirementAge;

// Constructor, but no getter/setter
}

Note that, here we’ve set the fields as public to enable access from outside the class Employee. Now, we need to change the retirementAge of an employee:

请注意,在这里我们将字段设置为公共字段,以便能够从类Employee之外访问。现在,我们需要改变雇员的retirementAge

public class RetirementAgeModifier {

    private Employee employee = new Employee("John", 58);

    private void modifyRetirementAge(){
        employee.retirementAge=18;
    }
}

Here, any client of the Employee class can easily do what they want with the retirementAge field. There’s no way to validate the change.

在这里,任何Employee类的客户都可以轻松地对retirementAge字段做他们想做的事。没有办法验证这个变化。

Fourth, how could we achieve read-only or write-only access to the fields from outside the class?

第四,我们如何能实现从类外对字段的只读或只写访问?

There come getters and setters to your rescue.

这时,获取器和设置器就会来救你。

4. Significance of Getters and Setters in Java

4.Java中获取器和设置器的意义

Out of many, let’s cover some of the most important benefits of using getters and setters:

在众多的好处中,让我们介绍一下使用getters和setters的一些最重要的好处。

  • It helps us achieve encapsulation which is used to hide the state of a structured data object inside a class, preventing unauthorized direct access to them
  • Achieve immutability by declaring the fields as private and using only getters
  • Getters and setters also allow additional functionalities like validation, error handling that could be added more easily in the future. Thus we can add conditional logic and provide behavior according to the needs
  • We can provide different access levels to the fields; for example, the get (read-access) may be public, while the set (write-access) could be protected
  • Control over setting the value of the property correctly
  • With getters and setters, we achieve one more key principle of OOP, i.e., abstraction, which is hiding implementation details so that no one can use the fields directly in other classes or modules

5. Avoiding Mistakes

5.避免错误的发生

Below are the most common mistakes to avoid while implementing getters and setters.

以下是在实现getters和setters时要避免的最常见的错误。

5.1. Using Getters and Setters With Public Variables

5.1.使用公有变量的获取器和设置器

Public variables can be accessed outside the class using a dot (.) operator. There is no sense in using getters and setters for public variables:

公有变量可以在类外使用点(.)操作符进行访问。对公有变量使用getters和setters是没有意义的。

public class Employee {
    public String name;
    public int retirementAge;

    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    } 
    // getter/setter for retirementAge
}

In this case, anything that can be done with getters and setters can also be done by making the field simply public.

在这种情况下,任何可以用getters和setters做的事情,也可以通过使字段简单地公开来完成。

As a rule of thumb, we need to always use the most restricted access modifiers based on the need to achieve encapsulation.

作为一条经验法则,我们需要根据实现封装的需要,始终使用限制最多的访问修改器。

5.2. Assigning Object References Directly in the Setter Methods

5.2.在setter方法中直接分配对象引用

When we assign object reference directly in the setter methods, both these references point to a single object in memory. So, changes made using any of the reference variables are actually made on the same object:

当我们在setter方法中直接分配对象引用时,这些引用都指向内存中的一个对象。因此,使用任何一个引用变量所做的改变实际上是在同一个对象上进行的。

public void setEmployee(Employee employee) {
    this.employee = employee;
}

However, we can copy all the elements from one object to another object using a deep copy. Due to this, the state of this object becomes independent of the existing (passed) employee object:

然而,我们可以使用deep copy将一个对象中的所有元素复制到另一个对象。由于这个原因,这个对象的状态变得独立于现有的(传递的)雇员对象。

public void setEmployee(Employee employee) {
    this.employee.setName(employee.getName());
    this.employee.setRetirementAge(employee.getRetirementAge());
}

5.3. Returning Object References Directly From the Getter Methods

5.3.从Getter方法中直接返回对象引用

Similarly, if the getter method returns the reference of the object directly, anyone can use this reference from the outside code to change the state of the object:

同样地,如果getter方法直接返回对象的引用,任何人都可以从外部代码中使用这个引用来改变对象的状态。

public Employee getEmployee() {
    return this.employee;
}

Let’s use this getEmployee() method and change the retirementAge:

让我们使用这个 getEmployee()方法,并改变retirementAge:

private void modifyAge() {
    Employee employeeTwo = getEmployee();
    employeeTwo.setRetirementAge(65);
}

This leads to the unrecoverable loss of the original object.

这导致了原始对象的不可恢复的损失。

So, instead of returning the reference from the getter method, we should return a copy of the object. One such way is as below:

因此,我们不应该从getter方法中返回引用,而应该返回一个对象的副本。一个这样的方法如下。

public Employee getEmployee() {
    return new Employee(this.employee.getName(), this.employee.getRetirementAge());
}

However, we should also keep in mind that creating copies of objects within the getter or setter might not always be a best practice. For example, calling the above getter method in a loop could result in an expensive operation.

然而,我们也应该记住,在getter或setter中创建对象的副本可能并不总是一种最佳做法。例如,在一个循环中调用上述getter方法可能导致昂贵的操作。

On the other hand, if we want that our collection should remain unmodifiable, it would make sense to return a copy of the collection from a getter. We then have to determine which approach suits best in a certain situation.

另一方面,如果我们希望我们的集合保持不可修改的状态,那么从getter中返回一个集合的副本就很有意义。然后我们必须确定哪种方法在某种情况下最适合。

5.4. Adding Unnecessary Getters and Setters

5.4.添加不必要的获取器和设置器

By having getters and setters, we can control the access and assignment of the member variables. But, in many places, it turns out to be unnecessary. Moreover, it makes the code verbose:

通过拥有getters和setters,我们可以控制成员变量的访问和分配。但是,在许多地方,它被证明是不必要的。此外,它使代码变得冗长。

private String name;

public String getName() {
    return name;
}

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

Simply defining public getters and setters for a private field in a class is equivalent to making the field public without getters and setters. So, it’s always advisable to decide thoughtfully whether to define accessor methods for all the fields or not.

简单地为一个类中的私有字段定义公共的获取器和设置器,相当于在没有获取器和设置器的情况下将该字段公开。因此,最好是深思熟虑地决定是否为所有字段定义访问器方法。

6. Conclusion

6.结语

In this tutorial, we discussed the pros and cons of using getters and setters in Java. We also discussed some common mistakes to be avoided while implementing getters and setters, and how to use those appropriately

在本教程中,我们讨论了在Java中使用getters和setters的利与弊。我们还讨论了在实现getters和setters时应避免的一些常见错误,以及如何恰当地使用这些错误。