一、简介
Getters 和 Setters 在检索和更新封装类外部变量的值方面发挥着重要作用。 setter 更新变量的值,而 getter 读取变量的值。
在本教程中,我们将讨论不使用getter/setter 的问题、它们的重要性以及在 Java 中实现它们时要避免的常见错误。
2. Java 中没有 Getter 和 Setter 的生活
考虑一下当我们想要根据某些条件更改对象的状态时的情况。如果没有 setter 方法,我们如何才能实现这一目标?
- 将变量标记为公共、受保护或默认变量
- 使用点 (.) 运算符更改值
让我们看看这样做的后果。
3. 无需 Getter 和 Setter 即可访问变量
首先,为了在没有 getter/setter 的情况下访问类外部的变量,我们必须将它们标记为 public、protected 或 default。 因此,我们失去了对数据的控制,并损害了基本的OOP原则——封装。
其次,由于任何人都可以从类外部直接更改非私有字段, 因此我们无法实现不变性。
第三,我们无法为变量的变化提供任何条件逻辑。假设我们有一个 Employee 类,其字段为 退休年龄 :
public class Employee {
public String name;
public int retirementAge;
// Constructor, but no getter/setter
}
请注意,这里我们将字段设置为公共,以允许从 Employee 类外部进行访问。现在,我们需要更改员工的 退休年龄 :
public class RetirementAgeModifier {
private Employee employee = new Employee("John", 58);
private void modifyRetirementAge(){
employee.retirementAge=18;
}
}
在这里, Employee 类的任何客户都可以轻松地使用 退休年龄 字段做他们想做的事情。 无法验证更改。
第四,如何实现类外部对字段的只读或只写访问?
getter 和 setter 会来拯救你。
4. Java中Getter和Setter的意义
在众多好处中,让我们介绍一下使用 getter 和 setter 的一些最重要的好处:
- 它帮助我们实现封装,用于隐藏类内结构化数据对象的状态,防止未经授权的直接访问它们
- 通过将字段声明为私有并仅使用 getter 来实现不变性
- Getter 和 Setter 还允许将来更容易添加的附加功能,例如验证、错误处理。因此我们可以添加条件逻辑并根据需要提供行为
- 我们可以提供不同的字段访问级别;例如,get(读访问)可以是公共的,而set(写访问)可以是受保护的
- 控制正确设置属性值
- 有了 getter 和 setter,我们实现了 OOP 的又一关键原则,即抽象,即隐藏实现细节,这样就没有人可以直接在其他类或模块中使用字段
5. 避免错误
以下是实现 getter 和 setter 时应避免的最常见错误。
5.1.将 Getter 和 Setter 与公共变量一起使用
可以使用点 (.) 运算符在类外部访问公共变量。对公共变量使用 getter 和 setter 是没有意义的:
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
}
在这种情况下,任何可以用 getter 和 setter 完成的事情也可以通过将该字段简单公开来完成。
根据经验,我们需要 根据实现封装的需要始终使用最受限制的访问修饰符。
5.2.直接在 Setter 方法中分配对象引用
当我们直接在 setter 方法中分配对象引用时,这两个引用都指向内存中的单个对象。因此,使用任何引用变量所做的更改实际上是在同一个对象上进行的:
public void setEmployee(Employee employee) {
this.employee = employee;
}
但是,我们可以使用深层复制将所有元素从一个对象复制到另一个对象。因此, 该 对象的状态变得独立于现有(传递的)员工对象:
public void setEmployee(Employee employee) {
this.employee.setName(employee.getName());
this.employee.setRetirementAge(employee.getRetirementAge());
}
5.3.直接从 Getter 方法返回对象引用
类似地,如果 getter 方法直接返回对象的引用,任何人都可以从外部代码使用此引用来更改对象的状态:
public Employee getEmployee() {
return this.employee;
}
让我们使用 getEmployee() 方法并更改 退休年龄:
private void modifyAge() {
Employee employeeTwo = getEmployee();
employeeTwo.setRetirementAge(65);
}
这会导致原始对象的不可恢复的损失。
因此,我们应该返回对象的副本,而不是从 getter 方法返回引用。一种这样的方式如下:
public Employee getEmployee() {
return new Employee(this.employee.getName(), this.employee.getRetirementAge());
}
然而,我们还应该记住,在 getter 或 setter 中创建对象的副本可能并不总是最佳实践。例如,在循环中调用上述 getter 方法可能会导致昂贵的操作。
另一方面,如果我们希望我们的集合保持不可修改,那么从 getter 返回集合的副本是有意义的。然后我们必须确定哪种方法最适合特定情况。
5.4.添加不必要的 Getter 和 Setter
通过使用 getter 和 setter,我们可以控制成员变量的访问和赋值。但在许多地方,事实证明这是没有必要的。此外,它使代码变得冗长:
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
简单地为类中的私有字段定义公共 getter 和 setter 相当于将该字段设为公共而不需要 getter 和 setter。因此,建议仔细考虑是否为所有字段定义访问器方法。
六,结论
在本教程中,我们讨论了在 Java 中使用 getter 和 setter 的优缺点。我们还讨论了在实现 getter 和 setter 时要避免的一些常见错误,以及如何正确使用它们