困惑
我们在编写一个类(常见为实体类)时,基本需要写以下代码:
- 类成员变量(或者称为类属性、类的字段)
- 默认构造函数,或带参构造函数
- toString 方法
- 类属性的 getter 和 setter 方法
比如:
package org.example.entity;
public class User {
private Integer uid;
private String name;
private String pwd;
private Integer age;
public User() {
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return super.toString();
}
}
其中一个比较困恼的就是每个类的属性字段,都需要写上一遍 getXX 和 setXX 方法,少还没啥关系,多的话,就有些觉得在做无用功了(不复杂,而且可以认为是一类模板),纯属就是一件费劳动力的事。那有没有相关的工具可以避免手动写这些“无用”的代码呢?这时 Lombok 就派上用场了。
引入 Lombok
先引入 Lombok 依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
说明:
- lombok 最新版本可在 https://search.maven.org/ 检索
- 由于我们只需要 Lombok 自动的帮我们生成一类确定的代码,而不需要包 Lombok 打包进入我们项目的 jar 包中,所以这里我们用 provided 进行限制;(provided 只在编译和测试时有效)
Lombok 注解详解
注解 | 描述 |
---|---|
@Getter/@Setter | 作用类上,生成所有成员变量的getter/setter方法;作用在成员变量上,生成该成员变量的getter/setter方法;可以设定访问权限以及是否懒加载等作用在成员变量上,生成该成员变量的getter/setter方法。可以设定访问权限以及是否懒加载等 |
@ToString | 作用于类,覆盖默认的toString()方法,可以通过of属性限定显示某些字段,通过exclude属性排除某些字段 |
@EqualsAndHashCode | 作用于类,覆盖默认的equals和hashCode |
@NonNull | 主要作用于成员变量和参数中,标识不能为空,否则抛出空指针异常 |
@NoArgsConstructor | 注解在类,生成无参的构造方法 |
@RequiredArgsConstructor | 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段 |
@AllArgsConstructor | 注解在类,生成包含类中所有字段的构造方法 |
@Data | 作用于类上,是@ToString @EqualsAndHashCode @Getter @Setter @RequiredArgsConstructor的集合,生成setter/getter、equals、canEqual、hashCode、toString方法,如果为final属性,则不会为该属性生成setter方法 |
@Log | 作用在类上,生成日志变量。针对不同的日志实现产品,有不同的注解 |
@Builder | 作用在类上,生成实体建造者 |
其中常用的注解有:@Getter/@Setter @Builder 和 @Data
其中 @Builder 一般用在 JDBC 时,给对象赋值是很方便。
代码改写
引入依然后,我们再来改写我们的代码
package org.example.entity;
import lombok.Data;
@Data
public class User {
private Integer uid;
private String name;
private String pwd;
private Integer age;
}
以上用 @Data ,此时的代码就很简洁了,我们在写个测试,看是否能访问到具体的 setter 和 getter:
package org.example;
import org.example.entity.User;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
User user = new User();
user.setUid(110);
user.setName("张三");
user.setPwd("123");
user.setAge(18);
System.out.println(user);
}
}
运行结果:
User(uid=110, name=张三, pwd=123, age=18)
Lombok 原理
Lombok 一个辅助工具,帮助开发者自动完成那些“毫无意义”且重复的代码,虽然开发者使用了 Lombok 没有人为的编写 setter 或 getter 等代码,但不表示这些代码就没有了,实际上这些代码由 Lombok 帮我们“写”了,我们可以查看编译后的字节码(User.class):
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.example.entity;
public class User {
private Integer uid;
private String name;
private String pwd;
private Integer age;
public User() {
}
public Integer getUid() {
return this.uid;
}
public String getName() {
return this.name;
}
public String getPwd() {
return this.pwd;
}
public Integer getAge() {
return this.age;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public void setName(String name) {
this.name = name;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public void setAge(Integer age) {
this.age = age;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User other = (User)o;
if (!other.canEqual(this)) {
return false;
} else {
label59: {
Object this$uid = this.getUid();
Object other$uid = other.getUid();
if (this$uid == null) {
if (other$uid == null) {
break label59;
}
} else if (this$uid.equals(other$uid)) {
break label59;
}
return false;
}
Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age != null) {
return false;
}
} else if (!this$age.equals(other$age)) {
return false;
}
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}
Object this$pwd = this.getPwd();
Object other$pwd = other.getPwd();
if (this$pwd == null) {
if (other$pwd != null) {
return false;
}
} else if (!this$pwd.equals(other$pwd)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof User;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $uid = this.getUid();
result = result * 59 + ($uid == null ? 43 : $uid.hashCode());
Object $age = this.getAge();
result = result * 59 + ($age == null ? 43 : $age.hashCode());
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $pwd = this.getPwd();
result = result * 59 + ($pwd == null ? 43 : $pwd.hashCode());
return result;
}
public String toString() {
return "User(uid=" + this.getUid() + ", name=" + this.getName() + ", pwd=" + this.getPwd() + ", age=" + this.getAge() + ")";
}
}
从以上的字节码可以看出,setter 和 getter 等方法是存在的,这些都是有 Lombok 在编译阶段生成的。