当前位置: 首页 > 图灵资讯 > 技术篇> 作为所有类的顶层父类,没想到Object的魔力如此之大!

作为所有类的顶层父类,没想到Object的魔力如此之大!

来源:图灵教育
时间:2024-02-04 13:51:58

写在开头

在最后一篇博客文章中,我们提到了Java面向对象的四个特征,其中在谈到“抽象”特征时,我们做了一个介绍,引出了今天的英雄Object。作为所有类别的顶级父亲,Object被视为James.Gosling的哲学思维高度总结了事务的自然和社会行为。

源码分析

在跟进Object类的源代码中,我们可以看到类的注释对其进行了总结性的注释。在这里插入图片描述

Object主要提供11种方法。您可以在源代码中逐一跟进。每种方法都有详细的英语注释。养成良好的英语注释习惯是合格程序员必备的基本技能。

/** * 方法一 */public final native Class<?> getClass()/** * 方法二 */public native int hashCode()/** *方法三 */public boolean equals(Object obj)/** * 方法四 */protected native Object clone() throws CloneNotSupportedException/** * 方法五 */public String toString()/** * 方法六 */public final native void notify()/** * 方法七 */public final native void notifyAll()/** * 方法八 */public final native void wait(long timeout) throws InterruptedException/** * 方法九 */public final void wait(long timeout, int nanos) throws InterruptedException/** * 方法十 */public final void wait() throws InterruptedException/** * 方法十一 */protected void finalize() throws Throwable { }
getClass()

getClass()是Java的native 该方法用于返回当前运行中的对象 Class 对象,使用 final 关键字修改,不允许子类重写。我们可以在源码中到达,这种方法的返回是Class。Class 通过类存储类结构信息,可以通过类存储类结构信息 Class 对象的方法取出相应的信息:名称、属性、方法、结构方法、父亲、界面和注释等信息。

hashCode()

也是native 该方法主要用于返回对象的哈希码,如哈希表 JDK Hashmap在中间。

equals()

默认比较对象的地址值是否相等,子类可以重写比较规则,如String 重写该方法,以比较字符串的值是否相等。

clone()

native 该方法用于创建和返回当前对象的副本。

toString()

哈希码返回类名称实例 16 进制字符串。建议 Object 所有子类都重写这种方法。

notify()

native 方法,不能重写。唤醒在这个对象监视器上等待的线程(监视器相当于锁定的概念)。如果有多个线程在等待,只会随意唤醒一个。

notifyAll()

native 方法,不能重写。跟着。 notify 同样,唯一的区别是唤醒所有在这个对象监视器上等待的线程,而不是一个线程。

wait(long timeout)

native方法,不能重写。执行暂停线程。注:sleep 该方法没有释放锁,而是 wait 释放锁的方法 ,timeout 等待时间。

wait(long timeout, int nanos)

多了 nanos 参数表示额外时间(以纳秒为单位,范围为 0-999999)。 因此,需要增加超时时间 nanos 纳秒。

wait()

让持有对象锁的线程进入等待,不能设置超时间,不会被唤醒,会一直等待。

finalize()

垃圾回收器回收时触发的操作实例

总结高频面试考点

虽然Object在日常代码开发中很少直接使用,但考虑到其独特的地位,还是有很多相关的面试考点。今天我们来总结一下。

1.浅拷贝、深拷贝、引用拷贝的区别?

浅复制:基本类型的属性将直接复制,引用类型的属性复制:复制堆内存中的变量和变量指向堆内存中的对象指针,而不是堆内存中的对象,即复制对象与原始对象共享相同的内部对象。在这里插入图片描述深度复制:深度复制将完全复制整个对象,包括该对象所包含的内部对象。在这里插入图片描述引用副本:简单地说,引用副本是指向同一对象的两种不同的引用副本。在这里插入图片描述

2.如何在Java中实现浅拷贝和深拷贝

实际上实现浅拷贝很简单,实现浅拷贝很简单 Cloneable 接口,重写 clone() 在clone()方法中调用父类objectclone()方法。

public class TestClone {     public static void main(String[] args) throws CloneNotSupportedException {        Person p1 = new Person(1, "ConstXiong");///创建对象 Person p1        Person p2 = (Person)p1.clone();///克隆对象 p1        p2.setName("其不答");//修改 name属性p2,namep1没有改变        System.out.println(p1);        System.out.println(p2);    }    } /** * person类 */class Person implements Cloneable {        private int pid;        private String name;        public Person(int pid, String name) {        this.pid = pid;        this.name = name;        System.out.println("Person constructor call");    }     public int getPid() {        return pid;    }     public void setPid(int pid) {        this.pid = pid;    }     public String getName() {        return name;    }     public void setName(String name) {        this.name = name;    }     @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }     @Override    public String toString() {        return "Person [pid:"+pid+", name:"+name+"]";    }    }

那么如何实现深度拷贝呢?这里有两种方法:对象属性的Class 也实现 Cloneable 当克隆对象时,接口也是手动克隆属性。方法二:结合序列化(JDK java.io.Serializable 完成深拷贝,JSON格式,XML格式等。).

3.==和equals有什么区别?
**区别**== 是关系运算符,equals() 这是一种方法,结果都返回了布尔值Object 的 == 和 equals() 比较都是地址,功能相同**== 功能:**基本类型,比较值是否等于引用类型,比较内存地址值是否相等,不能比较没有父子关系的两个对象**equals()方法的作用:**JDK 一般来说,中类已经重写了。 equals(),如果内容自定义类没有重写,则进行比较 equals()父类(默认)将被调用 Object 类)的 equals() 方法,Object 的 equals() 比较使用了 this == obj可以根据需求逻辑重写对象 equals() 方法(重写 equals 一般来说,方法必须重写 hashCode 方法)
为什么说重写equals方法也要重写hashcode方法?

equals()方法是判断两个对象是否相等的重要方法。Object中默认比较地址,但在实际使用中意义不大。比如两个字符串,我们比较的初衷肯定是他们的字符串内容是否相等,而不是内存地址。典型的是String内部的重写equals。

hashCode()方法是C或C++实现的本地方法,用于获取物体的哈希码值(散列码)。该物体在哈希表中的索引位置可以通过代码值来确定,这是通过线程局部状态实现的随机值。子类可以通过重写该方法重新设计hash值。使用hashcode方法可以在一定程度上判断两个对象是否相等,因为如果两个对象相等,他们的索引位置必须相同。此时,hashcode获得的哈希码自然相同,但这种情况可能无法建立。哈希码相等的两个对象不一定相等,因为哈希碰撞 。

看完这两种方法的特点,我们大概就能明白,这两种方法的合作需要保证两个对象是否真的相等。equals在逻辑上是相等的,hashcode在物理上是相等的。如果我们在重写equals()方法时不重写配套的hashcode方法,会导致两个对象在逻辑上是相等的,但在物理上是不同的。例如,集合Hashmap的底层实现是数据+链表/红黑树。通过计算hash找到位置,通过equals判断元素相等。此时,如果只重写equals,如果hash不重写,逻辑上会有两个相等的数字,不同的位置会导致混乱。