面试系列之Object类详解及重写equals为何要重写hashCode

大家都知道Object类是所有类的父类,任何类都默认继承Object,因此省略了extends Object关键字

Object类中所定义的方法,是所有对象都具备的方法。

Object类型可以储存任何对象

  • 作为参数,可以接受任何对象
  • 作为返回值,可返回任何对象

Object类的getClass,notify(),notifyAll(),wait()等方法被定义为final类型,因此不能重写。

1、实现对象的浅复制的clone()方法

保护方法,实现对象的浅复制,只有实现了cloneable接口才可以调用该方法,否则抛出CloneNotSupportException异常。

主要是java里除了8种基本类型传参是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里讲参数改变,就需要在类中复写clone方法。

2、获得运行时类型的getCalss()方法

final方法,获得运行时类型

3、释放资源的finalize()方法

当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。

垃圾对象:没有有效引用指向此对象时,为垃圾对象

垃圾回收:由GC销毁垃圾对象,释放数据存储空间

自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象

手动回收机制:使用System.gc(),通知JVM进行垃圾回收

4、用于哈希查找的hashCode()方法

可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashcode方法。

如果不重写hashCode,在hashMap中添加两个equals的对象,会将两个对象都加入进去。

5、使当前线程等待该对象的锁wait()方法

wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait方法一致等待,直到获得锁或者被中断,也可以设置一个超时时间,如果在规定时间内没有获得锁就返回。

6、toString()方法

该方法比较多,一般都有子类覆盖

7、equals()方法

默认比较两个对象地址是否相等,可进行重写,比较两个对象的内容是否相等。

8、nofify()方法

该方法唤醒在该对象上等待的某个线程

9、notifyAll()方法

该方法唤醒在该对象上等待的所有线程

下面我们详细说下hashCode()和equals()这两个方法

JDK中Object的hashcode()方法,JVM根据一定的规则将与对象相关的信息(比如对象的存储地址、对象的字段等)映射成一个数值,这个数值称为散列值。hashCode()方法返回的hash值并不能表示对象的内存地址。只能说是对象内存地址的一种表现形式(可能计算的时候只使用了对象内存地址的一部分)

我们知道对象都保存在堆内存中,堆里边维护了一张哈希表,哈希码的作用就是去确定这个对象在这个哈希表的一个索引的位置,哈希表是一个key-value的形式进行存储的,特点就是通过key快速的去找到一个value的值,key就是这个索引,即哈希码,我们可以通过这个哈希码快速的找到这个对象在堆里边的一个具体位置。如果两个对象相等,那么hashcode一定是相等的。对这两个对象进行equals比较,也是返回true。

hashCode() 和equals()用来标识对象,两个方法协同工作用来判断两个对象是否相等。对象通过调用Object.hashCode()生成哈希值,由于不可避免的会存在哈希冲突的情况,因此,hashCode相同时,还需要再调用equals进行一次值的比较。若hashCode不同,将直接判定两个对象不同。跳过equals,加快了冲突的处理效率。

hashCode的作用,主要是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、Hash Map和Hash Table。当集合要添加新的对象时,先调用这个对象的hash Code方法,得到对应的hash Code值,实际上在Hash Map的具体实现中会用一个table保存已经存进去的对象的hashCode值。如果table中没有该hashCode值,他就可以直接存进去。不用进行任何的比较。如果存在该hashCode值,就调用它的equals方法与新元素进行比较,相同的话就不存在了,不相同就散列其他的地址。

hashCode的常规协定:

1、在Java应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须返回同一个整数。

2、如果两个对象根据equals方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。

3、如果两个对象根据equals方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生相同的整数结果。如果不同,则可以提高散列表的性能。

为什么重写equals的同时还要重写hashCode??

public class Woman {

   String  name;
   Integer age;

  public Woman(String name, Integer age) {
    this.name = name;
    this.age = age;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    Woman student = (Woman) o;
    return Objects.equals(name, student.name) &&
        Objects.equals(age, student.age);
  }
}
public class StringTest {
  public static void main(String[] args) {

    HashMap<Woman,Integer> map = new HashMap<>();
    Woman s1 = new Woman("西施",16);
    Woman s2 = new Woman("西施",16);
    map.put(s1,16);
    System.out.println("s1:"+ map.get(s1));
    System.out.println("s2:" + map.get(s2));
    System.out.println("s1.equals(s2):" + s1.equals(s2));
    System.out.println("s1.hashCode()" + s1.hashCode());
    System.out.println("s2.hashCode()" + s2.hashCode());

  }
}

执行结果:

可以看到,s1和s2是等价的,但是,map.get(s2)并没有拿到我们想要获取的对象。因为woman只重写了equals方法,并没有重写hashCode方法,所以s1和s2的hash值不一样,所以s2的hash值是无法正确找到s1hash值所对应值。说明了如果只实现equals方法而没有实现hashCode方法,将会在使用散列数据结构时遇到问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值