美文网首页
2021-02-09 考个与Lombok有关的题目

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

作者: Children乏 | 来源:发表于2021-02-09 15:30 被阅读0次

    第一题

    请问以下代码输出的结果是什么?
    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实现,还多用了个中间类去承载属性值,之后统一通过构造方法注入,站在执行方法栈的角度看也会觉得是多此一举

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

    相关文章

      网友评论

          本文标题:2021-02-09 考个与Lombok有关的题目

          本文链接:https://www.haomeiwen.com/subject/usfcxltx.html