到底什么是POJO?
概述
POJO即“Plain Old Java Object”,下面我们将POJO与JavaBean进行比较,以及如何将POJO转换为JavaBeans。
Plain Old Java Object
什么是POJO?
一般当我们谈论POJO时,描述的是一种简单的类型,没有涉及到任何框架。POJO对属性和方法没有命名约定。
当我们创建一个员工POJO,它具有三个属性:fisrtName、lastName、startDate。
public class EmployeePojo {
public String firstName;
public String lastName;
private LocalDate startDate;
public EmployeePojo(String firstName, String lastName, LocalDate startDate) {
this.firstName = firstName;
this.lastName = lastName;
this.startDate = startDate;
}
public String name() {
return this.firstName + " " + this.lastName;
}
public LocalDate getStart() {
return this.startDate;
}
}
EmployeePojo可以被任何Java程序使用,因为它没有框架的束缚。但是,我们并没有遵循任何真正的约定来构造、访问、或者修改字段的值。缺乏约定会导致两个问题:
- 使用它的人会增加学习难度。
- 它可能会限制框架支持约定而不是配置,了解如果使用它以及扩展。
为了探究第二点,我们使用反射来获取EmployeePojo的属性。这样,我们将发现它的一些局限性。
对POJO进行反射
添加BeanUtils的Maven依赖到项目中:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
接下来,让我们使用反射获取POJO的属性:
List<String> propertyNames =
Arrays.stream(PropertyUtils.getPropertyDescriptors(EmployeePojo.class)).map(PropertyDescriptor::getDisplayName)
.collect(Collectors.toList());
System.out.println(propertyNames);
执行代码,我们将看到:
[start]
是不是很懵逼?我们只看到了start (getStart),PropertyUtils找不到其他两个属性,甚至是真实的属性。
如果你使用Jackson一样的其他库来处理,同样也会遇到这个问题。理想情况下,我们将看到的结果是:firstName,lastName,startDate。好的消息是,许多的Java库默认支持JavaBean的命名约定。
JavaBeans
什么是JavaBean?
JavaBean仍然是POJO,但是它遵守一组严格的规则:
- 访问级别 - JavaBean的属性必须是私有的,get、set方法是public
- 方法名称 - getter和setter遵循getX和setX的约定(对于Boolean,isX替代getter)
- 默认构造函数 - 必须存在无参的构造函数,一遍可以在不提供参数的情况下创建实例,例如:序列化期间
- 可序列化 - 实现Serializable接口,允许存储状态
EmployeePojo转换为JavaBean
我们尝试将EmplyeePojo转换为JavaBean:
public class EmployeeBean implements Serializable {
private static final long serialVersionUID = 5570916775939868315L;
private String firstName;
private String lastName;
private LocalDate startDate;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
}
对JavaBean进行反射
当我们对JavaBean进行时,获得了属性的完整列表:
[firstName, lastName, startDate]
是否使用JavaBeans
这里展示了JavaBeans的一种用法。每个设计都需要权衡,当我们使用JavaBeans时,还应该注意一些潜在的问题:
- 可变性 - 我们的JavaBeans由于使用setter方法,随时可以修改。这可能导致一些并发问题或者一致性问题
- 灵活性 - 一般我们必须为所有的属性设置一个值,其中大部分可能都是没有必要的。例如使用JPA修改密码时,我可能只需要userId和password
- 无参构造函数 - 我们经常通过有参构造函数来确保对象以有效的状态实例化,但是JavaBean标准要求我们提供了无参构造函数
结论
我们将POJO与JavaBeans进行了比较,POJO是一个没有任何约束且没有特定框架绑定的Java对象,而JavaBean时具有严格约定的POJO的一种特殊类型。