什么是 JavaBean
JavaBean 就是符合特定约定的普通 Java 类,就像标准化的乐高积木——大家都遵守统一规格,框架才能自动拼装
很多框架(Spring、MyBatis、Jackson等)都依赖这套约定来自动操作你的对象
不是什么高级技术,就是一套写类的规矩
JavaBean 的四大规范
| 规范 | 说明 | 示例 |
|---|---|---|
| private 字段 | 所有属性用 private 修饰(参见 访问修饰符 最小权限原则) | private String name; |
| public getter/setter | 每个字段提供公开的访问方法 | getName() / setName() |
| 无参构造器 | 必须有一个无参数的构造方法 | public User() {} |
| 实现 Serializable | 可选但推荐,让对象能序列化传输 | implements Serializable |
1 | import java.io.Serializable; |
getter/setter 命名规范
这不是随便取名的,有严格规则,框架靠这个规则通过反射找到你的字段:
| 字段类型 | getter 命名 | setter 命名 |
|---|---|---|
| 普通类型 | getXxx() |
setXxx(Type value) |
| boolean 类型 | isXxx() |
setXxx(boolean value) |
1 | private String name; // → getName() / setName() |
坑:字段名第二个字母大写时不做变换
private String uRL; → getuRL() 而不是 getURL()
所以字段名别搞奇怪的大小写,老老实实用驼峰命名
为什么框架需要 JavaBean
框架通过反射自动操作你的对象,反射需要规则来找方法和字段
Spring 依赖注入
Spring 创建对象时调用无参构造器,然后通过 setter 注入属性值
1 | // Spring 配置(简化版) |
MyBatis 数据库映射
查询结果自动映射到 JavaBean:数据库的 user_name 列 → 调用 setUserName()
1 | // MyBatis 查询结果自动填充到 User 对象 |
JSON 序列化(Jackson / Fastjson)
对象转 JSON 时调 getter,JSON 转对象时调 setter
1 | User user = new User("张三", 25, "zhangsan@test.com"); |
一句话总结:没有 JavaBean 规范,框架就像没有说明书的拼装玩具,不知道怎么操作你的对象
Lombok 简化 JavaBean(企业开发预告)
每个字段都要写 getter/setter,字段多了之后代码又臭又长,Lombok 帮你自动生成
1 | // 不用 Lombok:一堆模板代码 |
1 | // 用 Lombok:一个注解搞定 |
Lombok 是编译时生成代码,不是运行时反射,所以没有性能损耗
企业项目几乎必装 Lombok,IDEA 也需要装 Lombok 插件才能识别
POJO vs JavaBean vs DTO/VO 概念区分
面试和开发中经常混用这几个词,其实它们有区别:
| 概念 | 全称 | 含义 | 特点 |
|---|---|---|---|
| POJO | Plain Old Java Object | 普通的 Java 对象 | 没有任何限制,最宽泛的概念 |
| JavaBean | - | 符合规范的 POJO | 必须有无参构造器 + getter/setter |
| DTO | Data Transfer Object | 数据传输对象 | 用于层与层之间传数据,通常是 JavaBean |
| VO | Value Object / View Object | 视图对象 | 用于返回给前端的数据,通常是 JavaBean |
| Entity | - | 实体类 | 对应数据库表,通常是 JavaBean |
关系:JavaBean ⊂ POJO,DTO/VO/Entity 通常都是 JavaBean
1 | // Entity:对应数据库 users 表 |
为什么要分这么多类?
安全:Entity 可能包含密码等敏感字段,VO 只返回该暴露的
解耦:数据库表结构变了,只改 Entity,VO 不受影响
清晰:看到类名就知道它是干什么的
完整代码示例
1 |
|
常见坑
坑1:写了有参构造器,忘了无参构造器
Java 的规则:如果你不写任何构造器,编译器会自动送你一个无参构造器
但是!一旦你写了有参构造器,自动的无参构造器就消失了
框架创建对象时调无参构造器,找不到就报错
1 | public class User { |
解决:永远显式写一个无参构造器,或者用 Lombok 的 @NoArgsConstructor
坑2:boolean 字段的 getter 命名
boolean active → 方法名是 isActive() 不是 getActive()
但 Boolean active(包装类型大写B)→ 方法名是 getActive()
一不小心就写错,序列化的时候字段名对不上
坑3:字段名以 is 开头
boolean isDeleted → Lombok 生成的 getter 是 isDeleted()(不是 isIsDeleted())
但有些框架会把它识别为字段名 deleted 而不是 isDeleted,导致映射失败
建议:boolean 字段不要以 is 开头,直接用 deleted、active 这种
坑4:Lombok 的 @Data 包含 equals/hashCode
如果类有继承关系,默认生成的 equals 不考虑父类字段,可能导致bug
解决:用 @EqualsAndHashCode(callSuper = true) 让它包含父类
练习题
题1:写一个标准的 JavaBean —— Product 类,字段:name(String)、price(double)、inStock(boolean)
要求:private 字段、getter/setter、无参和有参构造器
注意 boolean 字段的 getter 命名
题2:为什么 MyBatis 查数据库能自动把结果填到 Java 对象里?
答案:MyBatis 通过反射调用无参构造器创建对象,然后根据列名找到对应的 setter 方法调用。这就是为什么必须遵守 JavaBean 规范
题3:Entity、DTO、VO 各自适合在什么层使用?
Entity → 数据库层(Mapper/Repository)
DTO → 服务层(Service),用于接收请求参数
VO → 控制层(Controller),用于返回给前端
三者之间需要做转换,这就是 BeanUtils.copyProperties() 的用武之地
| 上一章 | 目录 | 下一章 |
|---|---|---|
| 内部类与匿名类 | java基础 | String类与字符串操作 |