啥是POJO,啥是JavaBean

612 阅读3分钟

平时遇到遇到有关Java的文章,尤其是Spring Boot的文章,总是可以看到POJO、JavaBean。这都是啥!啥!啥啥啥!!!

今天咱们就一劳永逸,弄清楚这都是 啥!啥!啥!

Plain Old Java Obejects

POJO是Palin Old Java Objects的缩写。字面意思——普通老式的Java对象(一头雾水)?

当我们谈论一个POJO类时,我们所描述的是一个直接的类型,没有对任何特定框架的引用。一个POJO类对我们的属性和方法没有命名规则。

我们创建一个EmployeePojo,它拥有3个属性。看这个类可以应用于任何Java程序中,没有绑定任何框架。

import java.time.LocalDate;
​
public class EmployeePojo {
​
    public String firstName;
​
    public String lastName;
​
    private final 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;
    }
}

但是我们在构建、访问和修改这个类的状态时并没有真正的 遵循任何真正的惯例。缺乏惯例会导致两个问题:

  • 增加了试图了解如何使用它的程序员的学习曲线。
  • 限制了框架的能力更倾向于惯例而非配置,理解如何使用这个类,并且增强其能力。

我们接下来就第二点展开讨论。

反射一个POJO类

  • 首先引入commons-beanutils,依赖

    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
        <version>1.9.4</version>
    </dependency>
    
  • 然后检查EmployeePojo类的属性

    import org.apache.commons.beanutils.PropertyUtils;
    ​
    import java.beans.PropertyDescriptor;
    ​
    public class ReflectionExample {
        public static void main(String[] args) {
            System.out.println("Fields for EmployeePojo are:");
            for (PropertyDescriptor pd : PropertyUtils.getPropertyDescriptors(EmployeePojo.class)) {
                System.out.println("EmployeePojo property: " + pd.getDisplayName());
            }
        }
    }
    ​
    

    执行结果如下,仅打印出 start,另外两个属性并没有显示出来。理想状态下,我们希望看到的是:irstName, lastName,startDate.

    Fields for EmployeePojo are:
    EmployeePojo property: start
    

    这个问题怎么解决呢?好消息是,许多Java库默认支持一种叫做JavaBean的命名规则。

JavaBeans

JavaBean是POJO的子集,JavaBean围绕着我们如何实现他引入了很多严格的规则。

  • 访问级别——属性是私有的,可以暴露getters和setters
  • 方法命名——以getX和setX命名
  • 默认构造器——必须提供一个没有参数的构造方法
  • 可序列化的(Serializable )—— 实现可序列化的接口允许我们存储状态

使用JavaBean改造EmployeePojo

import lombok.Data;
​
import java.io.Serializable;
import java.time.LocalDate;
​
@Data //为了是代码更简洁,使用lombok.Data注释代替getX和setX方法。
public class EmployeeBean implements Serializable {
​
    private static final long serialVersionUID = -3760445487636086034L;
    private String firstName;
    private String lastName;
    private LocalDate startDate;
​
    public EmployeeBean() {
    }
    public EmployeeBean(String firstName, String lastName, LocalDate startDate) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.startDate = startDate;
    }
}

接下来改造一下ReflectionExample

import org.apache.commons.beanutils.PropertyUtils;
​
import java.beans.PropertyDescriptor;
​
public class ReflectionExample {
    public static void main(String[] args) {
        System.out.println("Fields for EmployeeBean are:");
        for (PropertyDescriptor pd : PropertyUtils.getPropertyDescriptors(EmployeeBean.class)) {
            System.out.println("EmployeePojo property: " + pd.getDisplayName());
        }
    }
}

执行结果如下

Fields for EmployeeBean are:
EmployeePojo property: firstName
EmployeePojo property: lastName
EmployeePojo property: startDate

JavaBean的缺点

JavaBean的引入虽然可以解决一些问题,但企业有3点潜在的缺点不容忽视

  • 可变性--由于我们的JavaBeans的setter方法是可变的,这可能导致并发性或一致性问题。
  • 模板--我们必须为所有的属性引入获取器,为大多数属性引入设置器,这其中的大部分可能是不必要的。
  • 零参数构造器--我们经常需要在构造器中设置参数,以确保对象在有效状态下被实例化,但JavaBean标准要求我们提供一个零参数构造器。

看完这期文章,你还会对POJO、JavaBean等概念不明所以吗?欢迎前来讨论~~~

\