“equals” 和 “”=="" 的区别
1. equals
1.1 作用
判断两个对象是否相等,返回值为boolean类型。
1.2 底层原理
在Object类种,equals的判断方法如下:
public boolean equals(Object obj) {
return (this == obj);
}
可以看到,Object 类种的 equals 方法其实就是 == 方法,两者相同。
那equals到底有何区别?
因为equals可以根据业务需要,实现你想要的比较方法。
通过equals(Object obj)括号内传入的对象,通过判断该对象的值、类型、是否为null等,返回与原对象是否相等,实现业务需求。
1.3 equals() 和 hashCode()的关系
1.3.1 不会创建“类对应的散列表”
”不会创建类对应的散列表“,指的是我们不会再HashSet,Hashtable,HashMap等这些本质是散列表的数据结构中,用到该类。例如,不会创建该类的HashSet集合。
在这种情况下,hashCode() 和 equals() 没有关系。
例如:
public class demo2 {
public static void main(String[] args) {
Persion p1 = new Persion("a", 1);
Persion p2 = new Persion("a", 1);
Persion p3 = new Persion("b", 1);
System.out.println("p1.equals(p2)" + p1.equals(p2));
System.out.println("p1.equals(p3)" + p1.equals(p3));
System.out.println("p1的HashCode:" + p1.hashCode());
System.out.println("p2的HashCode:" + p2.hashCode());
System.out.println("p3的HashCode:" + p3.hashCode());
}
private static class Persion{
String name;
int sex;
public Persion(String name,int sex){
this.name = name;
this.sex = sex;
}
@Override
public boolean equals(Object obj){
if(this==obj){
return true;
}
if(this.getClass() != obj.getClass()){
return false;
}
Persion persion = (Persion) obj;
return name.equals(persion.name) && sex == persion.sex;
}
}
}
运行结果:
p1.equals(p2)true
p1.equals(p3)false
p1的HashCode:1950409828
p2的HashCode:1229416514
p3的HashCode:2016447921
结果分析:
p1,p2虽为两个不同的对象,但因为equals()没有比较对象的地址值,所以p1和p2相等,但hashcode()不等。
1.3.2 会创建“类对应的散列表”
会在HashSet、Hashtable、HashMap等这些本质是散列表的数据结构种,用到该类。在这种情况下,该类的 hashCode() 和 equals() 是有关系的。
如果两个对象相等(equals()两对象时返回true),那它们的hashCode()的值一定相同。
如果两个对象hashCode()相等,它们并不一定相等(哈希冲突)。
因此,在这种情况下判断两对象相等的,需要重写equals()和hashCode()方法。
(1)只重写equals()方法
public static void main(String[] args) {
Person p1 = new Person("aa",1);
Person p2 = new Person("aa",1);
Person p3 = new Person("bb",0);
HashSet<Person> hashSet = new HashSet<>();
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
System.out.println("p1.equals(p2) : " + p1.equals(p2));
System.out.println("p1: " + p1.hashCode() + ", p2: " + p2.hashCode());
System.out.println(hashSet);
}
private static class Person{
private String name;
private int sex;
public Person(String name,int sex){
this.name = name;
this.sex = sex;
}
@Override
public String toString() {
return name + "+" + sex;
}
@Override
public boolean equals(Object obj){
if(obj == null){
return false;
}else if(this == obj){
return true;
}else if(this.getClass() != obj.getClass()){
return false;
}
Person person = (Person)obj;
return name.equals(person.name) && sex==person.sex;
}
运行结果:
p1.equals(p2) : true
p1: 1950409828, p2: 1229416514
[bb+0, aa+1, aa+1]
结果分析:
由此可知,只重写equals()方法,返回值为true时,hashCode()不一定相同。且set集合中有重复元素p1和p2。由此可知,p1和p2是不相等的。
(2)重写queals()和hashCode()方法:
public static void main(String[] args) {
Person p1 = new Person("aa",1);
Person p2 = new Person("aa",1);
Person p3 = new Person("bb",0);
Person p4 = new Person("AA",1);
HashSet<Person> hashSet = new HashSet<>();
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
hashSet.add(p4);
System.out.println("p1.equals(p2) : " + p1.equals(p2));
System.out.println("p1: " + p1.hashCode() + ", p2: " + p2.hashCode());
System.out.println("p1.equals(p4) : " + p1.equals(p4));
System.out.println("p1: " + p1.hashCode() + ", p4: " + p4.hashCode());
System.out.println(hashSet);
}
private static class Person{
private String name;
private int sex;
public Person(String name,int sex){
this.name = name;
this.sex = sex;
}
@Override
public String toString() {
return name + "+" + sex;
}
/**
* 重写hashCode算法,对name的值进行大写转换,然后计算hashCode
*/
@Override
public int hashCode(){
int nameHash = name.toUpperCase().hashCode();
return nameHash;
}
@Override
public boolean equals(Object obj){
if(obj == null){
return false;
}else if(this == obj){
return true;
}else if(this.getClass() != obj.getClass()){
return false;
}
Person person = (Person)obj;
return name.equals(person.name) && sex==person.sex;
}
}
运行结果:
p1.equals(p2) : true
p1: 2080, p2: 2080
p1.equals(p4) : false
p1: 2080, p4: 2080
[aa+1, bb+0, AA+1]
结果分析:
当重写 hashCode() 和 equals() 后,
比较p1和p2,hashCode相等,且equals()也相同,所以p1和p2相等;
比较p1和p4,hashCode相等,但equals()不相等,所以p1和p4不相等。
2. ==
2.1 作用
比较两个对象的堆内存地址,返回值为boolean类型。
2.2 基本数据类型比较
他们是作为常量在方法区中的常量池里面以HashSet策略存储起来的,一个常量只会对应一个地址,所以当参数相同时,他们的引用都是指向同一地址的。因此基本数据类型和String常量是可以直接通过==来直接比较的。
2.3 包装类型比较
除了Float和Double之外,其它6种都是实现了常量池的,因此对于这些数据类型而言,一般也会直接通过==来判断是否相等。
但是有一个问题:
当数据超出数据类型存储范围时,如何比较?
例如:
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b);
System.out.println(a == b);
输出结果是:
true、false
因为当超出数据类型范围时,会创建新的对象,此时,两对象的地址值不同,==的结果也就是false了。
总结
- 相同对象,无论何时调用hashCode(),返回值必须相等。
- 比较两对象时,若hashCode()相等时,两对象不一定相等,必须通过hashCode()和equals()方法同时判断,才能够确认两对象相同。
- 重写equals()函数,必须重写hashCode()函数。