如果您对@EqualsAndHashCode注解在子类中使用的问题和code注释感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解@EqualsAndHashCode注解在子类中使用的问题的各种细
如果您对@EqualsAndHashCode注解在子类中使用的问题和code注释感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解@EqualsAndHashCode注解在子类中使用的问题的各种细节,并对code注释进行深入的分析,此外还有关于1.“==”,”equals()”,”hashCode()”等的问题、== 和 equals 的区别是什么、两个对象的 hashCode()相同,则 equals()也一定为true?、==、equals()、hashCode、hashCode在集合中的作用、@EqualsAndHashCode的实用技巧。
本文目录一览:- @EqualsAndHashCode注解在子类中使用的问题(code注释)
- 1.“==”,”equals()”,”hashCode()”等的问题
- == 和 equals 的区别是什么、两个对象的 hashCode()相同,则 equals()也一定为true?
- ==、equals()、hashCode、hashCode在集合中的作用
- @EqualsAndHashCode
@EqualsAndHashCode注解在子类中使用的问题(code注释)
由于@EqualsAndHashCode生成的Equals和HashCode方法不会包含父类的属性,所以@EqualsAndHashCode(of=“子类属性”)是不合法的。
那么在子类中如果使用父类已有的Equals和HashCode方法,则可以有两种方法:
1. 不使用@EqualsAndHashCode注解,加上下面方法:
@Override
public boolean equals(Object o) {
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
2. 使用@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
编译后生成的代码如下:
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof BaseEntity)) {
return false;
} else {
BaseEntity other = (BaseEntity)o;
if (!other.canEqual(this)) {
return false;
} else {
return super.equals(o);
}
}
}
protected boolean canEqual(Object other) {
return other instanceof BaseEntity;
}
public int hashCode() {
int result = super.hashCode();
return result;
}
注意事项:用注解@EqualsAndHashCode(callSuper = true)会报告 StackOverFlow错误,原因是生成的hashcode值超过了int数值的范围造成的,如hashcode()方法如下:
public int hashCode() {
int PRIME = true;
int result = super.hashCode();
Object $category = this.getCategory();
result = result * 59 + ($category == null ? 43 : $category.hashCode());
Object $section = this.getSection();
result = result * 59 + ($section == null ? 43 : $section.hashCode());
Object $compileUnitName = this.getCompileUnitName();
result = result * 59 + ($compileUnitName == null ? 43 : $compileUnitName.hashCode());
Object $confirmationType = this.getConfirmationType();
result = result * 59 + ($confirmationType == null ? 43 : $confirmationType.hashCode());
Object $amount = this.getAmount();
result = result * 59 + ($amount == null ? 43 : $amount.hashCode());
Object $controlAmount = this.getControlAmount();
result = result * 59 + ($controlAmount == null ? 43 : $controlAmount.hashCode());
Object $controlDate = this.getControlDate();
result = result * 59 + ($controlDate == null ? 43 : $controlDate.hashCode());
Object $applyDate = this.getApplyDate();
result = result * 59 + ($applyDate == null ? 43 : $applyDate.hashCode());
Object $replyDate = this.getReplyDate();
result = result * 59 + ($replyDate == null ? 43 : $replyDate.hashCode());
Object $reviewAmount = this.getReviewAmount();
result = result * 59 + ($reviewAmount == null ? 43 : $reviewAmount.hashCode());
Object $projectSection = this.getProjectSection();
result = result * 59 + ($projectSection == null ? 43 : $projectSection.hashCode());
Object $compileUnit = this.getCompileUnit();
result = result * 59 + ($compileUnit == null ? 43 : $compileUnit.hashCode());
return result;
}
1.“==”,”equals()”,”hashCode()”等的问题
“==”,”equals()”,”hashCode()”这三个是不同而又有密切联系的概念,下面会梳理相关的知识点进行辨析。
一、”==”是运算符,equals()和hashCode()是函数
二、”==”操作符的用法
#1.如果==的两边都是基本类型变量、包装类对象所组成的表达式,==用于比较两边的表达式的值是否相等——只要两边的表达式的值相等,即使数据类不同,该运算符也会返回true。例如''a'' == 97.0,将会返回 true。
#2如果==的两边是引用类型的变量,==用于判断这两个引用类型的变量是否引用同一块内存,只有当它们引用同一块内存时,==才会返回 true。
三、”equals()”函数的用法
equals()则是一个 java.lang.Object 类的一个方法,因此任何 Java 对象都可调用该方法 与其他对象进行比较。java.lang.Object 类的 equals 方法的实现代码如下:
boolean equals(Object o) {
return this == o;
}
从上面代码可以看出,如果一个类没有重写 java.lang.Object 的 equals()方法时,此时 equals()方法的比较结果与==的比较结果是相同的。
但 Java 允许任何类重写 equals()方法,重写该方法就是让程序员来自己决定两个对象相 等的标准——极端的情况下,我们完全可以设计出 Person 对象与 Dog 对象 equals()比较返回 true 的情况——当然一般不会这么设计。
实际上重写 equals()方法时通常会按如下格式:
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (pass == null) {
if (other.pass != null)
return false;
} else if (!pass.equals(other.pass))
return false;
return true;
}
上面重写 equals()方法用于判断两个 Person 对象是否“相等”,程序只要两个 Person 对 象的 name、pass 相等,程序就可以把这两个 Person 对象当成相等——这是系统业务决定的。
如果业务需要,我们也可以增加更多的参与判断的 Field,当然也可以只根据 name 进行判断 ——只要两个 Person 的 name 相等,就认为两个 Person 相等,这都是由系统的业务决定。
总结起来就是一句话:开发者重写 equals()方法就可以根据业务要求来决定两个对象是 否“相等”。
四、”equals()”和“hashCode()”的不同作用
hashCode()方法与 equals()方法相似,都是来自 java.lang.Object 类的方法,都允许用户定义的子类重写这两个方法。
一般来说,equals()这个方法是给用户调用的,如果你想根据自己的业务规则来判断两个对象是否相等,你可以重写 equals()方法。简单来讲,equals 方法主要是用来判断从表面上看或者从内容上看,两个对象是不是相等。
而 hashCode()方法通常是给其他类来调用的,比如当我们要把两个对象放入 HashSet 时, 由于 HashSet 要求两个对象不能相等,而 HashSet 判断两个对象是否相等的标准是通过equals()比较返回 false、或两个对象的 hashCode()方法返回值不相等——只要满足任意一个 条件都可会认为两个对象不相等。
从这个角度来看,我们可以把 hashCode()方法的返回值当成这个对象的“标识符”,如果两个对象的 hashCode()相等,即可认为这两个对象是相等的。因此当我们重写一个类的 equals()方法时,也应该重写它的 hashCode()方法,而且这两个方法判断两个对象相等的标 准也应该是一样的。
比如两个对象值相同(x.equals(y) == true),但却可以有不同的 hashCode,因为 equals()方法可以由开发者重写,hashCode()方法也可以由开发者来重写,因此它们是否相等并没有必然的关系。
五、Set中重复元素的判断
Set 只是一个接口,它的不同实现类判断元素是否相等的标准是不同的。笼统地说,Set 里的元素是不能重复的,判断元素重复。
对于 HashSet 而言,判断两个对象是否相等是通过 equals()和 hashCode()方法,只要两个对象通过 equals()比较返回 false、或两个对象的 hashCode()不相等,那么 HashSet 就会把它们当成不相同。
对于TreeSet而言,判断两个对象相等的唯一标准是:两个对象通过compareTo(Object obj)比较是否返回 0,与 equals()方法无关。只要两个对象通过 compareTo(Object obj)比较没有返回 0,Java 就会把它们当成两个对象处理——这一点是很多人容易误解的,不过我们可以通的一个示例来说明:
class Z implements Comparable {
int age;
public Z(int age) {
this.age = age;
}
// 重写 equals()方法,总是返回 true
public boolean equals(Object obj) {
return true;
}
// 重写 hashCode()方法,总是返回 1
public int hashCode() {
int h = 1;
return h;
}
// 重写了 compareTo(Object obj)方法,总是返回正整数
public int compareTo(Object obj) {
return 1;
}
}
public class TreeSetTest2 {
public static void main(String[] args) {
TreeSet set = new TreeSet();
Z z1 = new Z(6);
set.add(z1);
// 输出 true,表明添加成功
System.out.println(set.add(z1)); // ①
// 下面输出 set 集合,将看到有两个元素
System.out.println(set);
// 修改 set 集合的第一个元素的 age 变量
((Z) (set.first())).age = 9;
// 输出 set 集合的最后一个元素的 age 变量,将看到也变成了 9
System.out.println(((Z) (set.last())).age);
}
}
true
[practice.equals.Z@1, practice.equals.Z@1]
9
上面程序中两个Z对象通过equals()比较总会返回true,但通过 compareTo(Object obj)比较总是不会返回 0,因此两次向 TreeSet 中添加同一个元素,TreeSet会把它们当成不同的对象进行处理,最后 TreeSet 集合中会显示有两个对象,但实际上是同一个对象。
== 和 equals 的区别是什么、两个对象的 hashCode()相同,则 equals()也一定为true?
== 和 equals 的区别是什么
"==" 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
两个对象的 hashCode()相同,则 equals()?
1. 如果两个对象相等,则hashcode一定也是相同的
2. 两个对象相等,对两个对象分别调用equals方法都返回true
3. 两个对象有相同的hashcode值,它们也不一定是相等的
另外,equals方法被覆盖过,则hashCode方法也必须被覆盖为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。
==、equals()、hashCode、hashCode在集合中的作用
(1)==可用于基本类型和引用类型:当用于基本类型时候,是比较值是否相同;当用于引用类型的时候,是比较对象是否相同。 对于String a = “a”; Integer b = 1;这种类型的特有对象创建方式,==的时候值是相同的。
(2)基本类型没有equals方法,equals只比较值(对象中的内容)是否相同(相同返回true)。
(3)一个类如果没有定义equals方法,它将默认继承Object中的equals方法,返回值与==方法相同
①==和equals的实质。
在JAVA中利用"=="比较变量时,系统使用变量在"栈"中所存的值作为比较的依据。
基本数据类型在"栈"中存的是其内容值,而对象类型在"栈"中存的是地址,这些地址指向"堆"中的对象。
java.lang包中的Object类有public boolean equals(Object obj)方法,它比较两个对象是否相等。
其它对象的equals方法仅当被比较的两个引用指向的对象内容相同时,对象的equals()方法返回true。
总之,"=="和"!="比较的是地址.也可认为"=="和"!="比较的是对象句柄;而equals()比较的是对象内容.或者说,,"=="和"!="比较的是"栈"中的内容,而equals()比较的是"堆"中的内容.
②==操作符。专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相当,只能用==操作符。
Java的基本数据类型为(char,byte,short,int,long,float,double,boolean)。
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(对内存),变量本身也占用一块内存,例如Object obj = new Object()变量obj是一个内存,new Object()是一个内存,此时,变量所对应的内存中存储的数据就是对象占用的那块内存的首地址。对于指向对象内存的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
③构造器形成的差别。对于String和Integer来说,由于他们特有的创建对象的方式。使用构造器和不使用构造器得到一个对象,==方法比较所产生的结果是不同的。 String a = “abc”; String b = "abc"; 此时a==b得到结果为true。String a = new String("abc"); String b = new String("abc");此时a==b得到的结果为false。Integer a = 1; Integer b = 1;此时a==b的结果是true。Integer a = new Integer(1); Integer b = new Integer(1);此时a==b得到的结果为false。
通过这一点其实我们也能够更加容易理解==对内存的实际操作,实际执行的是近似于基本类型比较。
hashCode:
hashcode这个方法是用来鉴定2个对象是否相等的。那你会说,不是还有equals这个方法吗?不错,这2个方法都是用来判断2个对象是否相等的。但是他们是有区别的。
一般来讲,equals这个方法是给用户调用的,如果你想判断2个对象是否相等,你可以重写equals方法,然后在代码中调用,就可以判断他们是否相等了。简单来讲,equals方法主要是用来判断从表面上看或者从内容上看,2个对象是不是相等。举个例子,有个学生类,属性只有姓名和性别,那么我们可以认为只要姓名和性别相等,那么就说这2个对象是相等的。
hashcode方法一般用户不会去调用,比如在hashmap中,由于key是不可以重复的,他在判断key是不是重复的时候就判断了hashcode这个方法,而且也用到了equals方法。这里不可以重复是说equals和hashcode只要有一个不等就可以了!所以简单来讲,hashcode相当于是一个对象的编码,就好像文件中的md5,他和equals不同就在于他返回的是int型的,比较起来不直观。我们一般在覆盖equals的同时也要覆盖hashcode,让他们的逻辑一致。举个例子,还是刚刚的例子,如果姓名和性别相等就算2个对象相等的话,那么hashcode的方法也要返回姓名的hashcode值加上性别的hashcode值,这样从逻辑上,他们就一致了。
要从物理上判断2个对象是否相等,用==就可以了。
@EqualsAndHashCode
1、@Data注解包含了这些注解
* @see Getter
* @see Setter
* @see RequiredArgsConstructor
* @see ToString
* @see EqualsAndHashCode
* @see lombok.Value
1. 此注解会生成equals(Object other) 和 hashCode()方法。
2. 它默认使用非静态,非瞬态的属性
3. 可通过参数exclude排除一些属性
4. 可通过参数of指定仅使用哪些属性
5. 它默认仅使用该类中定义的属性且不调用父类的方法
6. 可通过callSuper=true解决上一点问题。让其生成的方法中调用父类的方法。
另:@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集。
2、@Data就包含了EqualsAndHashCode 重写了hashcode和equals方法
3、EqualsAndHashCode 对于继承父类属性时需要注意的点
通过官方文档,可以得知,当使用@Data注解时,则有了@EqualsAndHashCode注解,那么就会在此类中存在equals(Object other) 和 hashCode()方法,且不会使用父类的属性,这就导致了可能的问题。
比如,有多个类有相同的部分属性,把它们定义到父类中,恰好id(数据库主键)也在父类中,那么就会存在部分对象在比较时,它们并不相等,却因为lombok自动生成的equals(Object other) 和 hashCode()方法判定为相等,从而导致出错。
修复此问题的方法很简单:
1. 使用@Getter @Setter @ToString代替@Data并且自定义equals(Object other) 和 hashCode()方法,比如有些类只需要判断主键id是否相等即足矣。
2. 或者使用在使用@Data时同时加上@EqualsAndHashCode(callSuper=true)注解。
4、测试
@Data
//@EqualsAndHashCode(callSuper=true)
public class UcsAccountLog extends BaseVO implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
}
@Data
public class BaseVO {
public String version;
}
/**
* 首先,是为了支持哈希表类的如之类的底层使用了哈希表的类。
* Java Object规范中int hashCode()方法的约定类容有三个:
* <p>
* (1) 只要对象的equals方法所用到的信息没有修改,那么hashCode方法必须始终如一的返回一个同一整数,在同一应用程序中多次执行中,每一次执行可以不一样。
* <p>
* (2) 如果两个对象的equals方法想到,那么每一个对象单独调用hashCode返回的数字必须相等。
* <p>
* (3) 如果两个对象的equals方法不相等,hashCode方法的返回值可以相等,给不同的对象返回不同的值可以提高哈希表的性能。
* 所有重写 equals的同时 必须重写hashcode
* @param args
*/
public static void main(String[] args) {
UcsAccountLog ucsAccountLog = new UcsAccountLog();
ucsAccountLog.setVersion("1");
ucsAccountLog.setId("2");
UcsAccountLog ucsAccountLog2 = new UcsAccountLog();
ucsAccountLog2.setVersion("2");
ucsAccountLog2.setId("2");
HashSet set = new HashSet();
set.add(ucsAccountLog);
set.add(ucsAccountLog2);
System.out.println(set.size());//1
System.out.println(ucsAccountLog.hashCode() == ucsAccountLog2.hashCode());//true 因为重写了hashcode 所有这里hashcode是相等的
//如果没有重写 hashcode是根据内存地址值
System.out.println(ucsAccountLog.equals(ucsAccountLog2));//true
//根据hash
System.out.println(ucsAccountLog == ucsAccountLog2);//false ==比较的是对象的地址
}
如果子类
//@EqualsAndHashCode(callSuper=true)
没有添加这一行,则输出结果是 true true false 和我们期望的结果不符合
因为@EqualsAndHashCode默认不继承父类 就是说 重写hashcode和equals的时候 不包含父类的字段值,所有只会比较自己对象里面的字段值 显然这是错误的
打开注解 则输出正确结果 false false false
关于@EqualsAndHashCode注解在子类中使用的问题和code注释的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于1.“==”,”equals()”,”hashCode()”等的问题、== 和 equals 的区别是什么、两个对象的 hashCode()相同,则 equals()也一定为true?、==、equals()、hashCode、hashCode在集合中的作用、@EqualsAndHashCode的相关信息,请在本站寻找。
本文标签: