文章16 | 阅读 7110 | 点赞0
在java.lang.Object中有两个实例方法——equals和hashCode。这两个方法就像孪生兄弟一样,重写equals,就要重写hashCode。至于为什么?可以看这篇博客《java中==,equals,hashcode》补补课。现在,我们来看看如何手动重写equals和hashCode方法。可以,使用Intellij IDEA的快捷键生成equals和hashCode方法:
在Template的下拉框中有着不同的选项用于生成equals和hashCode方法,我们选择java.util.Objects.equals and hashCode (java 7+),利用jdk1.7 的Objects工具类。上图的可选项1是指是否将从父类继承的字段包含到生成的equals方法中,可选项2是指是否使用getter方法,如果不是getter方法(student.getName()),则使用对象.成员变量(student.name)的形式直接访问成员变量。
@Getter
@Setter
@ToString
// @EqualsAndHashCode
public class Student {
private String name;
private Integer age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name) &&
Objects.equals(age, student.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
可以看到生成的代码中使用Objects的类方法equals(Object o)和hash()。同样的问题,生成的方法占据了不小的篇幅。
@EqualsAndHashCode的使用很简单,只需在Student类加上@EqualsAndHashCode后,编译,再查看编译后的文件。
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Student)) {
return false;
} else {
Student other = (Student)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;
}
Object this$age = this.getAge();
Object other$age = other.getAge();
if (this$age == null) {
if (other$age != null) {
return false;
}
} else if (!this$age.equals(other$age)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Student;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $age = this.getAge();
result = result * 59 + ($age == null ? 43 : $age.hashCode());
return result;
}
出于文章篇幅的考虑,只贴出了由@EqualsAndHashCode注解生成的代码。可以看到生成访问控制符为protected的canEqual(Object other)方法。
可以看到,只要属性全部相等,student和student1的equals方法就返回true。但是 == 永远判断是内存地址,所以当某个类重写了equals方法后,就要使用equals方法去做判断。
package lombok;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** * Generates implementations for the {@code equals} and {@code hashCode} methods inherited by all objects, based on relevant fields. * <p> * Complete documentation is found at <a href="https://projectlombok.org/features/EqualsAndHashCode">the project lombok features page for @EqualsAndHashCode</a>. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
/** * Any fields listed here will not be taken into account in the generated {@code equals} and {@code hashCode} implementations. * Mutually exclusive with {@link #of()}. * <p> * Will soon be marked {@code @Deprecated}; use the {@code @EqualsAndHashCode.Exclude} annotation instead. * * @return A list of fields to exclude. */
String[] exclude() default {};
/** * If present, explicitly lists the fields that are to be used for identity. * Normally, all non-static, non-transient fields are used for identity. * <p> * Mutually exclusive with {@link #exclude()}. * <p> * Will soon be marked {@code @Deprecated}; use the {@code @EqualsAndHashCode.Include} annotation together with {@code @EqualsAndHashCode(onlyExplicitlyIncluded = true)}. * * @return A list of fields to use (<em>default</em>: all of them). */
String[] of() default {};
/** * Call on the superclass's implementations of {@code equals} and {@code hashCode} before calculating for the fields in this class. * <strong>default: false</strong> * * @return Whether to call the superclass's {@code equals} implementation as part of the generated equals algorithm. */
boolean callSuper() default false;
/** * Normally, if getters are available, those are called. To suppress this and let the generated code use the fields directly, set this to {@code true}. * <strong>default: false</strong> * * @return If {@code true}, always use direct field access instead of calling the getter method. */
boolean doNotUseGetters() default false;
/** * Any annotations listed here are put on the generated parameter of {@code equals} and {@code canEqual}. * This is useful to add for example a {@code Nullable} annotation.<br> * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br> * up to JDK7:<br> * {@code @EqualsAndHashCode(onParam=@__({@AnnotationsGoHere}))}<br> * from JDK8:<br> * {@code @EqualsAndHashCode(onParam_={@AnnotationsGohere})} // note the underscore after {@code onParam}. * * @return List of annotations to apply to the generated parameter in the {@code equals()} method. */
AnyAnnotation[] onParam() default {};
/** * Placeholder annotation to enable the placement of annotations on the generated code. * @deprecated Don't use this annotation, ever - Read the documentation. */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
@interface AnyAnnotation {}
/** * Only include fields and methods explicitly marked with {@code @EqualsAndHashCode.Include}. * Normally, all (non-static, non-transient) fields are included by default. * * @return If {@code true}, don't include non-static non-transient fields automatically (default: {@code false}). */
boolean onlyExplicitlyIncluded() default false;
/** * If present, do not include this field in the generated {@code equals} and {@code hashCode} methods. */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {}
/** * Configure the behaviour of how this member is treated in the {@code equals} and {@code hashCode} implementation; if on a method, include the method's return value as part of calculating hashCode/equality. */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
/** * Defaults to the method name of the annotated member. * If on a method and the name equals the name of a default-included field, this member takes its place. * * @return If present, this method serves as replacement for the named field. * 是指当一个方法的名称和变量名相同时,包含方法进入equals,不包含字段。 */
String replaces() default "";
}
}
本文已经收录在Lombok注解系列文章总览中,并继承上文中所提的特别说明。
源码地址:gitee
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/cauchy6317/article/details/102522991
内容来源于网络,如有侵权,请联系作者删除!