第一题
请问以下代码输出的结果是什么?
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 @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后,应该会看到这个提示
提示说明了,@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实现,还多用了个中间类去承载属性值,之后统一通过构造方法注入,站在执行方法栈的角度看也会觉得是多此一举
个人认为,轮子坑不坑,好不好用是一方面,自己对这些轮子的了解程度如何也占很大比重。
网友评论