区别
== 分两种情况:
- 若比较的是基本数据类型,则比较的是值,只要值相等,就可以
- 若比较的是引用数据类型,则比较的是内存地址。
equals 也是分两种情况:
- 没有重写equals()。通过equals比较俩对象的时候,和==一样的,比较的是内存地址值。
- 重写了equals()方法。一般我们通过重写equals()方法来比较两个对象的内容是否相等。(String中重写了equals()方法,是比较的两个对象的值)
(例子) 没有重写equals
package fuxi.Hascode;
import java.util.HashSet;
import java.util.Objects;
public class Student {
private String name;
private int age;
Student(int age){
this.age=age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public static void main(String[]args){
Student stu=new Student(23);
stu.name="zrf";
Student stu1=new Student(23);
stu1.name="zrf";
HashSet set=new HashSet();
set.add(stu);
set.add(stu1);
for(Object s:set){
System.out.println(s);
}
HashSet set1=new HashSet();
set1.add("1");
set1.add("1");
for(Object s:set1){
System.out.println(s);
}
}
}
按道理因为hashset不能存储一样的值,那么set1和set应该都只有一个值,但是我们的结果却是:
Student{name='zrf', age=23}
Student{name='zrf', age=23}
1
这是为什么?
set1中我们添加的是String,因为String中的equals被重写过,所以它只比较内容是不是一样。
set中我们添加的是Student,当set1添加stu时,set为空,直接添加,当添加stu1时,先比较是否有相同的hashcode,此时调用的是Object中的euqals,比较的是内存地址值,因为stu1与stu是都是new出来的,属于不同的对象,所以内存地址值不同,所以set会直接存入stu1.
正确的写法(重写equals)
package fuxi.Hascode;
import java.util.HashSet;
import java.util.Objects;
public class Student {
private String name;
private int age;
Student(int age){
this.age=age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + 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 age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public static void main(String[]args){
Student stu=new Student(23);
stu.name="zrf";
Student stu1=new Student(23);
stu1.name="zrf";
HashSet set=new HashSet();
set.add(stu);
set.add(stu1);
for(Object s:set){
System.out.println(s);
}
HashSet set1=new HashSet();
set1.add("1");
set1.add("1");
for(Object s:set1){
System.out.println(s);
}
}
}
为什么重写equals的时候要重写hashCode
我们可以看到上面的代码中,重写equals的时候也重写了hashCode这是为什么?在下面的代码中,我们只重写了equals没有重写hashCode,发现结果与第一个一样。
package fuxi.Hascode;
import java.util.HashSet;
import java.util.Objects;
public class Student {
private String name;
private int age;
Student(int age){
this.age=age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + 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 age == student.age &&
Objects.equals(name, student.name);
}
// @Override
// public int hashCode() {
//
// return Objects.hash(name, age);
// }
public static void main(String[]args){
Student stu=new Student(23);
stu.name="zrf";
Student stu1=new Student(23);
stu1.name="zrf";
HashSet set=new HashSet();
set.add(stu);
set.add(stu1);
for(Object s:set){
System.out.println(s);
}
HashSet set1=new HashSet();
set1.add("1");
set1.add("1");
for(Object s:set1){
System.out.println(s);
}
}
}
Student{name='zrf', age=23}
Student{name='zrf', age=23}
1
原因:
就如上面的例子,我们往set中插入对象时,会先判断hashCode是否一样,如果重写了equals,而不重写hashCode,那么hashCode会用Object中的方法,而Object对象中的hashCode方法始终返回的是一个对象的hash地址,而这个地址是永远不相等的。所以这时候即使是重写了equals方法,也不会有特定的效果的,因为hashCode方法如果都不相等的话,就不会调用equals方法进行比较了,所以没有意义了。
hashCode()和euqals()有相关规定:
- 如果两个对象的内容不发生改变,无论发生多少次调用,它的hashCode值都是一样的。
- 如果两个对象根据equals(Object)方法比较是相等的,那么所产生的的hashcode必须一样。
- 如果两个对象产生的hashcode一样,两个对象也不一定相等。
引用:
https://blog.csdn.net/qq_33619378/article/details/92661494
https://baijiahao.baidu.com/s?id=1660514228207272623&wfr=spider&for=pc
https://www.cnblogs.com/Eason-S/p/5894743.html