许多的库和规范(例如 JPA, JavaEL)使用 Java Beans 规范,并依赖于该行为。
使用 getters 和 setters 的优点是可以在这些方法内添加代码,例如创建“虚拟”属性,在运行时计算而不是存储在字段中。
此外,使用 getters 和 setters 允许其他框架包装这些方法并提供附加功能,例如更改日志等。在许多情况下,这是通过内部创建子类并覆盖 getters 和 setters 来完成的。用户不会注意到这点,因为这种“编织”或“代理”通常在运行时完成。例如,Hibernate 使用这种方式当调用 getter 访问相关集合或实体时提供延迟加载功能。
更新:
根据请求提供一个“虚拟”属性示例:
假设您有一个Person
bean,它具有 firstName
和 lastName
字段。 你可以通过提供以下 getter 添加一个只读虚拟属性 name
:
public String getName() {
return getFirstName() + " " + getLastName();
}
更新2:
关于为什么需要使用getter和setter的另一个说明:这基本上是由Java的工作方式决定的。像C#这样直接支持属性的语言,可以让您编写类似于person.firstName = "Joe";
的代码,并且如果有setter,则仍然使用它,如果属性是只读的,则抛出错误。因此,如果您为firstName
添加了setter,那些语言会在开发人员不必更改任何内容的情况下将firstName = "Joe"
内部转换为setFirstName("Joe")
- 这是一种相当优雅的解决方案。 :)
由于Java不支持这一点,即使它们没有特殊功能,我们也必须始终提供访问器方法(setter / getter)- 以防将来可能需要更改它们。
Java Beans 设计可以帮助
的例子,正如你所说的那样。如果没有该设计,实现 JPA 惰性加载将会很困难。 - ThomasGetters和Setters确保了基本的面向对象概念
- 封装
。
想象一下,你编写了一个类的代码,另外十几个程序员从你的公司编写了使用你的类的程序。因此,任何人都可以更改您的实例变量,这可能会损害您的代码。
所以你应该:
保持实例变量受保护
(使用访问修饰符,通常是private
)。
创建公共访问器方法
,并强制调用代码使用这些方法而不是直接访问实例变量
。
他们的代码引出了您代码中的错误。
看下面的例子。
public class MyClass{
public int size;
public int weight;
...
}
public class OthersClass {
public static void main (String [] args) {
MyClass myClass= new MyClass();
myClass.size = -5; // Legal but bad logic
}
}
正如你上面描述的那样,JavaBeans 可以被用作 DAO(数据访问对象),用于检索和保存数据到(主要是 SQL)数据库。它们很有用,特别是在你真正关心的只有数据时。
许多人会告诉你,Java Beans比充当“数据传输对象”的普通Java对象要好得多。
但是其他人,例如这位在他著名的书中https://cleansourcecode.files.wordpress.com/2013/10/clean-code.pdf的作者,建议大多数情况下,“bean”和getter和setter并没有太多附加价值(整个第6章都致力于探讨这个问题)。
因此,您应该自己决定(可能与团队成员一起),使用“Java Beans”还是“普通数据传输对象”更好地解决了您的问题。
当然,“beans”强制您使用setter,这使您可以稍后添加验证。另一方面:这种更改修改了您的方法的语义;突然间一个setter执行验证并开始抛出异常可能是完全错误的。因为,如果您更改了方法的契约,则可能不希望在幕后隐含地执行该操作。