java.lang.Object中equals()和hashCode()

java.lang.Object中equals()和hashCode()

  • equals()
  • hashCode()
  • “==”比较的是什么
  • 为什么覆写equals()的同时需要覆写hashCode

一、equals()

  • 自反性
    对于任意非null的引用值x,x.equals(x)必须返回true
  • 对称性
    对于任意的非null的引用值x、y,如果x.equals(y)返回true,那么y.equals(x)也必须返回true
  • 传递性
    对于任意的非null的引用值x、y、z如果x.equals(y)返回true,同时y.equals(x)返回true;那么x.equals(z)也要返回true
  • 一致性
    对于任意的非null的引用值x、y,如果equals中需要比较的属性没有改变,那么多次调用x.equals(y)返回值是一样的
  • 对于任意的非null引用值,x.equals(null)肯定会返回false

  • equals()覆写方法

package java_lang_Object;

import java.util.HashMap;

/**
 * Created by luckyboy on 2018/7/1.
 */
public class Person {
    private String name;
    private int age;
    private String address;

    public Person(String name,int age,String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    @Override
    public boolean equals(Object obj) {
        /*1、将传进来的参数Object使用==进行比较,如果参数引用值和对象的隐式参数this引用值的引用地址一样,
        * 那么返回true,否则返回false
        */
        if(this == obj){
            return true;
        }
        /**
        *使用instanceof判断传递进来的参数是否是该类对象,如果不是则返回false,如果是则进行下一步
        */
        if(!(obj instanceof Person)){
            return false;
        }
        /**
        *将方法参数转换成该类的类型
        */
        Person p = (Person) obj;
        /**
        *对于类中每个需要检查的域,我们都需要判断参数的域是否和该对象中的对应的域相匹配
        *如果域是基本类型,那么我们直接使用"=="进行判断
        *如果域是引用类型,我们可以调用引用类型的equals方法进行判断
        *对于引用类型的检查,建议使用下面的方式检查是否匹配
        *(this.field == o.field) ||((field != null) && field.equals(o.field))
        */
        if(this.name.equals(p.name) &&
                this.age == p.age &&
                this.address == p.address){
            return true;
        }
        return false;
    }
    public static void main(String[] args){
        Person p1 = new Person("Zou",22,"Hunan");
        Person p2 = new Person("Zou",22,"Hunan");

        System.out.println("p1.hashCode = " + p1.hashCode());
        System.out.println("p2.hashCode = " + p2.hashCode());

        System.out.println("p1.equals(p2) = "+ p1.equals(p2));

        HashMap<Person,String> map = new HashMap<Person,String>();
        map.put(p1,"Zou");
        String s = map.get(p2);
        System.out.print(s);

    }
}

二、hashCode()

  • Object方法中的hashCode()

    Object中的hashCode() 返回对象的32位jvm内存地址;如果一个类没有重写hashCode方法,那么对于任意的两个不同的对象,其地址都是不相同的,那么hashCode()返回值是不同的

    public native int hashCode();

    看下面的例子

    @Test
        public void testString(){
            String s1 = "hello";
            String s2 = "hello";
            String s3 = "hel"+"lo";
            String s4 = "hel"+new String("lo");
            String s5 = new String("hello");
            System.out.println("s1 == s2  "+(s1 == s2));
            System.out.println("s1 == s3  "+(s1 == s3));
            System.out.println("s1 == s4  "+(s1 == s4));
            System.out.println("s1 == s5  "+(s1 == s5));
    
            System.out.println("s1.hashCode == "+s1.hashCode());
            System.out.println("s2.hashCode == "+s2.hashCode());
            System.out.println("s3.hashCode == "+s3.hashCode());
            System.out.println("s4.hashCode == "+s4.hashCode());
            System.out.println("s5.hashCode == "+s5.hashCode());
    
            System.out.println("s1.equals(s2)" + (s1.equals(s2)));
            System.out.println("s1.equals(s3)" + (s1.equals(s3)));
            System.out.println("s1.equals(s4)" + (s1.equals(s4)));
            System.out.println("s1.equals(s5)" + (s1.equals(s5)));
        }

    输出结果

    s1 == s2  true
    s1 == s3  true
    s1 == s4  false
    s1 == s5  false
    s1.hashCode == 99162322
    s2.hashCode == 99162322
    s3.hashCode == 99162322
    s4.hashCode == 99162322
    s5.hashCode == 99162322
    s1.equals(s2)true
    s1.equals(s3)true
    s1.equals(s4)true
    s1.equals(s5)true

    从上面的结果可以知道,如果一个方法重写了hashCode()方法,那么返回就不再是内存地址

  • hashCode方法归约

    1、如果两个对象的equals()返回true,那么两个对象的hashCode()返回一致
    2、如果两个hashCode()返回一致,两个对象执行equals()不一定相等
    3、如果一个对象的equals()要比较的属性不发生变化,那么对同一个对象调用多次,那么该对象返回的hashCode方法一致

  • hashCode()重写规则

    1、把某个非零的的常数值保存在一个名为result的int类型变量中
    2、对于对象中每一个关键属性f(equals 中设计需要比较的属性)完成以下步骤

    a、如果该域是boolean类型,则计算f ? 1:0
    b、如果该域是bytecharshortint类型,则计算int(f);
    c、如果该域是long类型,则计算int(f ^ (f>>32))
    d、如果该域是float类型,则计算Float.floatToIntBits(f)
    e、如果该域是double类型,则计算Double.doubleToLongBits(f)得到long类型的数据,然后根据c得到一个int型数值
    f、如果该域是一个引用类型,则计算f == null ?f.hashCode():0
    g、如果该域是一个数组类型,那么需要对数组中每一个元素都进行上面的规则中的计算方法

三、”==”比较的是什么

直接使用==操作符,比较的是两个变量的引用的实例变量的地址

四、为什么覆写equals()的同时需要覆写hashCode

我们可以来看一个Person对象作为key添加到HashMap中的例子

package java_lang_Object;

import java.util.HashMap;

/**
 * Created by luckyboy on 2018/7/1.
 */
public class Person {
    private String name;
    private int age;
    private String address;

    public Person(String name,int age,String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(!(obj instanceof Person)){
            return false;
        }
        Person p = (Person) obj;
        if(this.name.equals(p.name) &&
                this.age == p.age &&
                this.address == p.address){
            return true;
        }
        return false;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }

    public static void main(String[] args){
        Person p1 = new Person("Zou",22,"Hunan");
        Person p2 = new Person("Zou",22,"Hunan");

        System.out.println("p1.hashCode = " + p1.hashCode());
        System.out.println("p2.hashCode = " + p2.hashCode());

        System.out.println("p1.equals(p2) = "+ p1.equals(p2));

        HashMap<Person,String> map = new HashMap<Person,String>();
        map.put(p1,"Zou");
        String s = map.get(p2);
        System.out.print(s);

    }
}

```

输出

p1.hashCode = 1836019240
p2.hashCode = 325040804
p1.equals(p2) = true
null

重写hashCode方法之后

package java_lang_Object;

import java.util.HashMap;

/**
 * Created by luckyboy on 2018/7/1.
 */
public class Person {
    private String name;
    private int age;
    private String address;

    public Person(String name,int age,String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(!(obj instanceof Person)){
            return false;
        }
        Person p = (Person) obj;
        if(this.name.equals(p.name) &&
                this.age == p.age &&
                this.address == p.address){
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        result = 31 * result + (address != null ? address.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }

    public static void main(String[] args){
        Person p1 = new Person("Zou",22,"Hunan");
        Person p2 = new Person("Zou",22,"Hunan");

        System.out.println("p1.hashCode = " + p1.hashCode());
        System.out.println("p2.hashCode = " + p2.hashCode());

        System.out.println("p1.equals(p2) = "+ p1.equals(p2));

        HashMap<Person,String> map = new HashMap<Person,String>();
        map.put(p1,"Zou");
        String s = map.get(p2);
        System.out.print(s);

    }
}
```
输出
```
p1.hashCode = 156624696
p2.hashCode = 156624696
p1.equals(p2) = true
Zou
```

其中主要是HashMap的添加过程是首先将要添加的key进行一次hash操作,然后就映射到了一个桶中;一个对象如果没有重写hashCode(),那么两个

Person p1 = new Person("Zou",22,"Hunan");
Person p2 = new Person("Zou",22,"Hunan");

对象的hashCode()返回值是对应内存的地址,肯定是不相同的。那么这个时候我们再次去查找就找不到我们的信息。相比较Person类重写了hashCode(),那么p1和p2的hashCode()返回值是一样的,这是会将p2映射到p1所在的桶中然后根据equals方法去判断是否相等,相等则返回对应的value

参考文章
http://www.importnew.com/25783.html
http://baijiahao.baidu.com/s?id=1561228085482413&wfr=spider&for=pc
《effective java》

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/80872853