工作中大量重复毫无技术的去书写get()、set()方法,不推荐手写,也不推荐利用idea中的工具类等等操作
而是使用lombok中的注解来一套搞定。
既然lombok能够搞定,那么需要理解一下是如何来搞定这一切的。
lombok除了get/set,还有一些其他的可以使用的。
可以去看一下官网:
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
lombok是一款比较常用的工具,可以用来帮助开发人员消除java中的冗长代码(也就是毫无技术可言的重复性工作),尤其是对于简单的java对象(POJO),通过注解实现这一目的。
Lombok可以简化我们的代码书写方式。
Lombok的原理:
JSR269:插件化注解处理API
JDK6提供的特性,在javac编译期间利用注解搞事情。在编译期间可以利用lombok的注解方式来进行将生成的代码添加到字节码文件中去。我们利用Lombok注解生成的字节码文件中是包含了的。
最常用的注解
可以自动的帮助我们生成get/seter、toString、hashcode和equals方法,但是呢,我们可以看到这种使用方式:
@Data public class User { private String name; }
在idea中看到对应的class目录:
public class User { private String name; public User() { } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof User)) { return false; } else { User other = (User)o; if (!other.canEqual(this)) { return false; } else { Object this$name = this.getName(); Object other$name = other.getName(); if (this$name == null) { if (other$name != null) { return false; } } else if (!this$name.equals(other$name)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof User; } public int hashCode() { int PRIME = true; int result = 1; Object $name = this.getName(); int result = result * 59 + ($name == null ? 43 : $name.hashCode()); return result; } public String toString() { return "User(name=" + this.getName() + ")"; } }
可以看到其中的方法已经在上面对应好了,而且生成的还是当前类中的属性。
但是问题就出现在这里,我再写一个父类:
@Data public class Person { private Integer id; }
然后让其子类来进行继承:
@Data @EqualsAndHashCode(callSuper = true) public class User extends Person{ private String name; }
编译后的Java如下所示:
public class User extends Person { private String name; public User() { } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String toString() { return "User(name=" + this.getName() + ")"; } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof User)) { return false; } else { User other = (User)o; if (!other.canEqual(this)) { return false; } else if (!super.equals(o)) { return false; } else { Object this$name = this.getName(); Object other$name = other.getName(); if (this$name == null) { if (other$name != null) { return false; } } else if (!this$name.equals(other$name)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof User; } public int hashCode() { int PRIME = true; int result = super.hashCode(); Object $name = this.getName(); result = result * 59 + ($name == null ? 43 : $name.hashCode()); return result; } }
可以看到在equals方法中多了一个判断
if (!super.equals(o)) return false;
@EqualsAndHashCode(callSuper = true)的作用就在于将子类和父类中的属性都来进行比较,举个例子进行说明:
父类Person:
@Data public class Person { private Integer id; }
子类User:
@Data public class User extends Person{ private String name; }
测试方法:
@Test void contextLoads() { User user1 = new User(); User user2= new User(); user1.setId(1); user2.setId(2); user1.setName("1"); user2.setName("1"); boolean equals = Objects.equals(user1, user2); log.info("两个对象是否是相等的?------>{}",equals); //true }
但是如果加了@EqualsAndHashCode(callSuper = true)
父类:
@Data public class Person { private Integer id; }
子类:
@Data @EqualsAndHashCode(callSuper = true) public class User extends Person{ private String name; }
再次运行测试类得到的却是false,那么为什么会有这样子的结果?
我们可以在不加@EqualsAndHashCode(callSuper = true)和不加的情况下分别看下class文件
不加@EqualsAndHashCode(callSuper = true)
public class User extends Person { private String name; public User() { } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof User)) { return false; } else { User other = (User)o; if (!other.canEqual(this)) { return false; } else { Object this$name = this.getName(); Object other$name = other.getName(); if (this$name == null) { if (other$name != null) { return false; } } else if (!this$name.equals(other$name)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof User; } public int hashCode() { int PRIME = true; int result = 1; Object $name = this.getName(); int result = result * 59 + ($name == null ? 43 : $name.hashCode()); return result; } public String toString() { return "User(name=" + this.getName() + ")"; } }
加了@EqualsAndHashCode(callSuper = true)
public class User extends Person { private String name; public User() { } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String toString() { return "User(name=" + this.getName() + ")"; } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof User)) { return false; } else { User other = (User)o; if (!other.canEqual(this)) { return false; } else if (!super.equals(o)) { return false; } else { Object this$name = this.getName(); Object other$name = other.getName(); if (this$name == null) { if (other$name != null) { return false; } } else if (!this$name.equals(other$name)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof User; } public int hashCode() { int PRIME = true; int result = super.hashCode(); Object $name = this.getName(); result = result * 59 + ($name == null ? 43 : $name.hashCode()); return result; } }
综合这两个情况来进行对比,可以看到加了@EqualsAndHashCode(callSuper = true)之后,生成的equals方法中多了一个判断:
if (!super.equals(o)) { return false; }
这里是在访问父类中的equals方法来进行判断,但是有时候我们希望使用到父类中的属性,有时候希望使用到子类中的属性。
所以我们需要根据当前的场景来进行选择,我现在使用的是直接将@EqualsAndHashCode(callSuper = false)
public class User extends Person { private String name; public User() { } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String toString() { return "User(name=" + this.getName() + ")"; } public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof User)) { return false; } else { User other = (User)o; if (!other.canEqual(this)) { return false; } else { Object this$name = this.getName(); Object other$name = other.getName(); if (this$name == null) { if (other$name != null) { return false; } } else if (!this$name.equals(other$name)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof User; } public int hashCode() { int PRIME = true; int result = 1; Object $name = this.getName(); int result = result * 59 + ($name == null ? 43 : $name.hashCode()); return result; } }
可以看到这里和不加@EqualsAndHashCode是一样的,但是为了有些场景我们又需要不加上,所以需要根据自己的场景来进行判断
@Accessors(chain=true)
链式访问,该注解设置chain=true
,生成setter方法返回this,代替了默认的返回void。
@Data @Accessors(chain=true) public class User { private Integer id; private String name; private Integer age; public static void main(String[] args) { User user=new User().setAge(31).setName("pollyduan"); System.out.println(user); } }
@Accessors(fluent = true)
与chain=true
类似,区别在于getter和setter不带set和get前缀。但是这个尽量不要使用,因为很多框架都是通过get/set方法来进行赋值的
@Data @Accessors(fluent=true) public class User { private Integer id; private String name; private Integer age; public static void main(String[] args) { User user=new User().age(31).name("pollyduan"); System.out.println(user); } }
@Accessors(prefix = “f”)
去除掉属性的前缀之后生成的set方法:
@Data @Accessors(prefix = "f") public class User { private String fName = "Hello, World!"; public static void main(String[] args) { User user=new User(); user.setName("pollyduan");//注意方法名 System.out.println(user); } }
无参构造
public User() { }
当前类中的属性的有参构造:
public User(String name) { this.name = name; }
这个方法可以用也可以不用,我这里不用,做个记录。