Lombok采坑

注解介绍

Lombok 注解可以让我们免去每次编写 Java 类的时候需要添加 getter() 和 sertter() 等通用方法。@Data 注解相当于同时添加 @Getter、@Setter、@EqualsAndHashCode 等注解。但是使用 @Data 需要注意该注解生成的 equals 方法只是针对当前类中的字段值进行比较,并不会比较父类中的字段。因此如果使用该注解的类有父类就需要注意添加一条注解 @EqualsAndHashCode(callSuper = true)

问题复现

  • 创建父类
import lombok.Data;
@Data
public class ParentClass {
    private String parentField;
}
  • 创建子类
import lombok.Data;
@Data
public class ChildClass extends ParentClass{
    private String childField;
}
  • 测试比较
public class LombokTest {
    public static void main(String[] args) {
        ChildClass child1 = new ChildClass();
        ChildClass child2 = new ChildClass();
        child1.setChildField("same");
        child2.setChildField("same");
        child1.setParentField("a");
        child2.setParentField("b");
        System.out.println("child1 equals child2: " + child1.equals(child2));
        System.out.println("child1: " + child1);
        System.out.println("child2: " + child2);
    }
}
  • 输出结果

child1 equals child2: true
child1: ChildClass(childField=same)
child2: ChildClass(childField=same)

显然 child1 和 child2 中从父类继承的字段 parentField 不同,但是输出结果却显示两个类相同。
我们在子类中添加两条注解,修改后子类如下:

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ChildClass extends ParentClass {
    private String childField;
}

运行上面的测试程序,输出如下:

child1 equals child2: false
child1: ChildClass(super=ParentClass(parentField=a), childField=same)
child2: ChildClass(super=ParentClass(parentField=b), childField=same)

此时判断 child1 和 child2 是否相等就会使用父类中的信息,可以看出输出结果为不相等。上面 ChildClass 类上面我添加了另外一个注解@ToString(callSuper = true),比较两次输出就可以看出使用该注解可以使子类中的 toString() 方法输出父类中的字段信息。

原理解析

比较子类添加@EqualsAndHashCode(callSuper = true)注解前后的字节码反编译结果,注释处可以发现两个注解均引入对父类的引用。

  • 添加注解前 equals 方法
public boolean equals(final Object o) {
    if (o == this) {
        return true;
    } else if (!(o instanceof ChildClass)) {
        return false;
    } else {
        ChildClass other = (ChildClass)o;
        if (!other.canEqual(this)) {
            return false;
        } else {
            Object this$childField = this.getChildField();
            Object other$childField = other.getChildField();
            if (this$childField == null) {
                if (other$childField != null) {
                    return false;
                }
            } else if (!this$childField.equals(other$childField)) {
                return false;
            }
            return true;
        }
    }
}
  • 添加注解后 equals 方法
public boolean equals(final Object o) {
    if (o == this) {
        return true;
    } else if (!(o instanceof ChildClass)) {
        return false;
    } else {
        ChildClass other = (ChildClass)o;
        if (!other.canEqual(this)) {
            return false;
        } else if (!super.equals(o)) { // 此处增加了对父类equals方法的调用
            return false;
        } else {
            Object this$childField = this.getChildField();
            Object other$childField = other.getChildField();
            if (this$childField == null) {
                if (other$childField != null) {
                    return false;
                }
            } else if (!this$childField.equals(other$childField)) {
                return false;
            }
            return true;
        }
    }
}

比较添加@ToString(callSuper = true)注解前后的反编译代码也有同样结论:

  • 添加注解前 toString 方法
public String toString() {
    return "ChildClass(childField=" + this.getChildField() + ")";
}
  • 添加注解后 toString 方法
public String toString() {
    return "ChildClass(super=" + super.toString() + ", childField=" + this.getChildField() + ")";
    // 调用父类toString方法
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值