2021-02-09 考个与Lombok有关的题目

2021-02-09  本文已影响0人  Children乏

第一题

请问以下代码输出的结果是什么?
a. true true
b. false false
c. true false
d. false true

import com.google.common.collect.Sets;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.Set;

public class Demo {

    @Getter
    @Setter
    public static class Father {
        private Long id;
    }

    @Data
    public static class Son extends Father {
        private String name;
    }

    public static void main(String[] args) {
        Set<Father> set = Sets.newHashSet();

        Son s1 = new Son();
        s1.setId(1L);
        s1.setName("1");
        System.out.println(set.add(s1));

        Son s2 = new Son();
        s2.setId(2L);
        s2.setName("1");
        System.out.println(set.add(s2));
    }
}

答案:c. true false

第一个输出为true无需多言
第二个输出为何为false?

认知中,s1和s2的id属性值不同
先查下@Data的注释

/**
 * Generates getters for all fields, a useful toString method, and hashCode and equals implementations that check
 * all non-transient fields. Will also generate setters for all non-final fields, as well as a constructor.
 * <p>
 * Equivalent to {@code @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode}.
 * <p>
 * Complete documentation is found at <a href="https://projectlombok.org/features/Data.html">the project lombok features page for &#64;Data</a>.
 * 
 * @see Getter
 * @see Setter
 * @see RequiredArgsConstructor
 * @see ToString
 * @see EqualsAndHashCode
 * @see lombok.Value
 */

@Data等价于组合使用
@Setter @Getter @RequiredArgsConstructor @ToString @EqualsAndHashCode

来看下@EqualsAndHashCode的源码中的callSuper()方法

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
   /**
     * Call on the superclass's implementations of {@code equals} and {@code hashCode} before calculating
     * for the fields in this class.
     * <strong>default: false</strong>
     */
    boolean callSuper() default false;
}

可以知道,只添加@Data注解的类,默认不会调用父类的equals/hashCode方法
上面的例子中,在比较s1和s2的时候,只比较了name字段,发现相同,故s2不会被加入Set中。

使用IDEA的小伙伴,当在子类使用了@Data后,应该会看到这个提示

IDEA泛黄提示
提示说明了,@Data带来的@EqualsAndHashCode,在生成equals/hashCode方法时,默认不调用其父类的equals/hashCode方法
即使它的父类不是java.lang.Object
并且建议你显示添加@EqualsAndHashCode(callSuper = false),证明你确实不打算调用父类的方法是(intentional,故意的),以消除这个泛黄的提示

至于为什么@EqualsAndHashCode要这么做?
你想啊,当你写一个类,默认继承java.lang.Object
当你加了@EqualsAndHashCode注解,若是默认调用了父类(java.lang.Object)的equals/hashCode方法,那还有意义吗?
Lombok不会帮你去判断这个类的父类是不是java.lang.Object,直接默认不调用父类完事儿
当然这也延伸出一种使用标准,就是使用@Data的类,不要有继承关系

但本质上,是要学会自己用
——鲁迅(并没有说过)

第二题

接下来,手动在Son类加上@EqualsAndHashCode(callSuper = true),示意要调用父类的方法,并稍微修改了属性值

请问以下代码输出的结果是什么?
a. true true
b. false false
c. true false
d. false true

import com.google.common.collect.Sets;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

import java.util.Set;

public class Demo2 {

    @Getter
    @Setter
    public static class Father {
        private Long id;
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    public static class Son extends Father {
        private String name;
    }

    public static void main(String[] args) {
        Set<Father> set = Sets.newHashSet();

        Son s1 = new Son();
        s1.setId(1L);
        s1.setName("1");
        System.out.println(set.add(s1));

        Son s2 = new Son();
        s2.setId(1L);
        s2.setName("1");
        System.out.println(set.add(s2));
    }
}

答案:a. true true
第一个输出true无需多言
第二个,为何是true?两个对象的id和name属性都相同,不是调用父类的equals/hashCode方法了吗?

嗯,问题就在这,你看父类的equals/hashCode方法重写了吗?
没重写,所以父类调用的实际是java.lang.Object的equals/hashCode方法

public class Object {
    public boolean equals(Object obj) {
        return (this == obj);
    }

    public native int hashCode();
}

总结:
Lombok确实很好用,但也有不少大佬说Lombok带来了很多坑。


大佬的聊天记录

使用Lombok,代码虽然简化了,但肯定会隐藏一些细节。这些细节对于有一定资历的程序员来说是烂熟于心的,但对于新入行的同学,以及刚接触Lombok的同僚来说确实不太友好。

像我目前的项目,如果没有lombok,每写/改一个字段就要连带一个getter和setter,相当于工作量直接翻三倍。

另一方面,Lombok的@Builder方法我个人就觉得很鸡肋

不仅影响了这个类的构造方法(@Builder的实现需要依赖于这个类必须有个全参构造方法,而类的构造方法有可能会影响到其他的一些中间件使用)

而且跟一行行的Set属性没什么本质区别,并不能节约多少代码
(当然业务不同吧,也不否认首次用@Builder敲代码会很爽,但爽过之后是要还债的)

看了下@Builder实现,还多用了个中间类去承载属性值,之后统一通过构造方法注入,站在执行方法栈的角度看也会觉得是多此一举

个人认为,轮子坑不坑,好不好用是一方面,自己对这些轮子的了解程度如何也占很大比重。

上一篇 下一篇

猜你喜欢

热点阅读