lombok 遇到的问题
@Data 注解的理解
@Data 注解其实是多个注解的集合,他完成了多个注解的功能,分别是:
- @Getter
- @Setter
- @RequiredArgsConstructor
- @ToString
- @EqualsAndHashCode
有时候我们为了方便getter和setter方法的简单化,直接使用了@Data注解代替,很可能会产生意想不到的问题,特别是@EqualsAndHashCode,下面将对这个注解进行解释。
@EqualsAndHashCode 注解
定义一个Person类,使用@EqualsAndHashCode注解后,我们先看看会产生什么事情
- 源码:
/**
* @author xiaoming
*/
@EqualsAndHashCode
public class Person {
private int sex;
private int age;
private String name;
public static void main(String[] args) {
System.out.println("run");
}
}
- 编译之后
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package lombok;
public class Person {
private int sex;
private int age;
private String name;
public Person() {
}
public static void main(String[] args) {
System.out.println("run");
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Person)) {
return false;
} else {
Person other = (Person)o;
if (!other.canEqual(this)) {
return false;
} else if (this.sex != other.sex) {
return false;
} else if (this.age != other.age) {
return false;
} else {
Object this$name = this.name;
Object other$name = other.name;
if (this$name == null) {
if (other$name == null) {
return true;
}
} else if (this$name.equals(other$name)) {
return true;
}
return false;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Person;
}
public int hashCode() {
int PRIME = true;
int result = 1;
int result = result * 59 + this.sex;
result = result * 59 + this.age;
Object $name = this.name;
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
}
可以看出,lombok在编译的时候重写了三个方法 :
- hashCode
- canEqual
- equals
equals方法对各个参数多进行了校验,如果我们想使用引用进行equals方法比较的话,@Data就不能使用了。
这个时候可能会有同学思考了,如果涉及到继承,对子类添加注解,那子类会调用父类的equals 方法吗?
接着做实验,添加子类 Coder 继承 Person
- 源码
/**
* @author xiaoming
*/
@EqualsAndHashCode
public class Coder extends Person {
private boolean loveJava;
public static void main(String[] args) {
System.out.println("run");
}
}
- 编译之后
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package lombok;
public class Coder extends Person {
private boolean loveJava;
public Coder() {
}
public static void main(String[] args) {
System.out.println("run");
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Coder)) {
return false;
} else {
Coder other = (Coder)o;
if (!other.canEqual(this)) {
return false;
} else {
return this.loveJava == other.loveJava;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Coder;
}
public int hashCode() {
int PRIME = true;
int result = 1;
int result = result * 59 + (this.loveJava ? 79 : 97);
return result;
}
}
不能看出,equals 方法和 hashCode方法 只对子类成员进行了比较
那我们如何继承父类的equals方法呢?使用 callSuper = true
- 源码
/**
* @author xiaoming
*/
@EqualsAndHashCode(callSuper = true)
public class Coder extends Person {
private boolean loveJava;
public static void main(String[] args) {
System.out.println("run");
}
}
- 编译后
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package lombok;
public class Coder extends Person {
private boolean loveJava;
public Coder() {
}
public static void main(String[] args) {
System.out.println("run");
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Coder)) {
return false;
} else {
Coder other = (Coder)o;
if (!other.canEqual(this)) {
return false;
} else if (!super.equals(o)) {
return false;
} else {
return this.loveJava == other.loveJava;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Coder;
}
public int hashCode() {
int PRIME = true;
int result = super.hashCode();
result = result * 59 + (this.loveJava ? 79 : 97);
return result;
}
}
equals方法调用了super.equals方法和super.hashCode方法
查看注解的callSuper定义, 默认是false,当致为true的时候比较子类域成员之前会调用父类的equals和hashCode
/**
* Call on the superclass's implementations of {@code equals} and {@code hashCode} before calculating for the fields in this class.
* <strong>default: false</strong>
*
* @return Whether to call the superclass's {@code equals} implementation as part of the generated equals algorithm.
*/
boolean callSuper() default false;
lombok注解和用户自定义优先级
我们经常会使用@Data注解方便快捷,但是我们又想对toString方法自定义,那在同时使用的情况下会发生什么情况呢?
- 源码
/**
* @author xiaoming
*/
@EqualsAndHashCode
public class Person {
private int sex;
private int age;
private String name;
public static void main(String[] args) {
System.out.println("run");
}
@Override
public String toString() {
return "user defined";
}
}
- 编译之后
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package lombok;
public class Person {
private int sex;
private int age;
private String name;
public Person() {
}
public static void main(String[] args) {
System.out.println("run");
}
public String toString() {
return "user defined";
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Person)) {
return false;
} else {
Person other = (Person)o;
if (!other.canEqual(this)) {
return false;
} else if (this.sex != other.sex) {
return false;
} else if (this.age != other.age) {
return false;
} else {
Object this$name = this.name;
Object other$name = other.name;
if (this$name == null) {
if (other$name == null) {
return true;
}
} else if (this$name.equals(other$name)) {
return true;
}
return false;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Person;
}
public int hashCode() {
int PRIME = true;
int result = 1;
int result = result * 59 + this.sex;
result = result * 59 + this.age;
Object $name = this.name;
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
}
通过代码不难看出,toString方法使用了我们自定义的
所以说优先级是用户自定义的高(其实大家思考一下也很容易想到)
总结
使用插件和注解会给我们带来很多的方便,也会让代码变得简洁,但是我们需要对这些注解真正的了解,不然出现问题的话会难以排除