欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

复习equals、hashCode的知识点

程序员文章站 2024-03-22 17:42:04
...

Object 内部equals实现

public boolean equals(Object obj) {
        return (this == obj);
    }

上述的代码表明,如果是调用Object的equals,实际上是比较两个对象的内存地址是否一致。

equals和==区别

这个问题在面试中是经常被问,我们都知道equals是比较两个对象的值,而==是比较的两个对象的内存地址。但是从严格意义上说是有问题的。

            Car c= new Car(12);
            Car c1 =new Car(23);
            System.out.println(c.equals(c1));//false
            System.out.println(c==c1);//false

 

这里你在调用equals实际上是调用的是Object的equals(还是比较的是内存地址)。你可以通过重写equals方法。

重写equals的规则

  • 自反性。对于任何非null的引用值x,x.equals(x)应返回true。
  • 对称性。对于任何非null的引用值x与y,当且仅当:y.equals(x)返回true时,x.equals(y)才返回true。
  • 传递性。对于任何非null的引用值x、y与z,如果y.equals(x)返回true,y.equals(z)返回true,那么x.equals(z)也应返回true。
  • 一致性。对于任何非null的引用值x与y,假设对象上equals比较中的信息没有被修改,则多次调用x.equals(y)始终返回true或者始终返回false。
  • 对于任何非空引用值x,x.equals(null)应返回false。(不要使用null.equals(x) 会出现空指针异常)

equals混合了继承

public class Car {
    private int size;
    public Car(int size) {
        super();
        this.size = size;
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj instanceof Car) {
            Car c = (Car)obj;
            return c.size==size; /这里比较的依据是看size
        }
        return super.equals(obj);
    }
}

 

public class AppleCar extends Car {
    private int count;
    public AppleCar(int size, int count) {
        super(size);
        this.count = count;
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj instanceof AppleCar) {
            AppleCar ac = (AppleCar)obj;
            return ac.count==count;
        }
        return super.equals(obj);//这里会调用父类的Car的equal比较规则,
        //虽然车的类型不同,但是车的size是否一致,作为最终判断依据
        //return false;则这里就表示不是同一种类型的就是不相等
    }
}
            Car c= new Car(23);
            Car c1 =new AppleCar(23,15);
            System.out.println(c.equals(c1));//true
            System.out.println(c1.equals(c));//ture

 

出现这样的问题就是在于instanceof 违法了对称性,你只能顺着实例对象的方向比较。从而我们在不是实例对象的时候,调用父类的equals来比较。

为啥重写equals要重写hashcode

hashCode的意思就是散列码,也就是哈希码。在java中,我们可以使用hashCode()来获取对象的哈希码,其值就是对象的存储地址,hashCode()方法出自Object。

           String s = "ok";
           String t = new String("ok");
           System.out.println(s.hashCode()+" "+t.hashCode());//hashcode的值一样。

String 方法的Hashcode方法

   public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

我们可以看出,字符串s与t拥有相同的散列码,这是因为字符串的散列码是由内容导出的,它重写了Object的Hashcode方法。Object类默认的hashCode方法计算出来的对象存储地址,所以不同的对象,它的地址肯定不一样。

equals和Hashcode

和hashcode重写的equals方法应该是比较两个对象的值是否相等。

    String a = new String("a");
            String b = new String("a");
            System.out.println(a.equals(b));//true
            System.out.println(a==b);//false
            System.out.println(a.hashCode());//97
            System.out.println(b.hashCode());//97

 

由这个例子可以看出两个对象的equals(比较的是内容)相等,这两个对象的hashcode,必然相等。如果是同一个对象,那肯定内容相等,所以说必须要覆盖equals,比较内容。

  • 如果两个对象通过调用equals方法是相等的,那么这两个对象调用hashCode方法必须返回相同的整数。
  • 两个对象的hashcode相等。并不代表这两个对象equals相等,通过哈希函数产生的hashcode会1产生一个等价类,在这个等价类中的hashcode值都相等。
  • 如果两个对象通过调用equals方法是不相等的,不要求这两个对象调用hashCode方法必须返回不同的整数。但是程序员应该意识到对不同的对象产生不同的hash值可以提供哈希表的性能。
         Map map = new HashMap<>();
         String s="ok";
         String s1 = "ok";
         map.put(s, "one");
         System.out.println(map.get(s1));//one
         System.out.println(map.get(s));//one
         Car c = new Car();
         Car c1 = new Car();
         map.put(c,"kkk");
         System.out.println(map.get(c));//kkk
         System.out.println(map.get(c1));//null

这里在最后map取值,是根据key的hashcode,来取值,String因为重写了hashcode方法,是根据内容去计算的,所以内容相等,即hashcode相等;而Car的hashcode默认是object,即就是根据对象地址,两个不同的对象,hashcode肯定不一样,所以无法获取值。

上面的方法我们可以通过重写hashcode。我们在重写equals的时候,一定要重写hashcode方法。

重写equals()中getClass与instanceof的区别

一般都是推荐使用 getClass 来进行类型判断,保证是同一个类的对象。但是有些时候还是会用到instanceof,这个主要看需求。

参考引用:Java核心技术基础知识