大话Object类里面的方法

用自己通俗的语言来解释Object类的方法

registerNatives()

    private static native void registerNatives();
    static {
        registerNatives();
    }

这个方法的作用是将Object类里面的本地方法(native修饰的)进行注册,注册完以后就会生成一个java本地方法名–>C/C++函数的对应列表。
如果不懂就可以这么理解。
我要调用Object的hashCode()方法–>JVM老哥来执行这个方法了–>咦,这个方法是本地方法我要去C/C++里面找执行的具体方法–>打开我的注册表我要看看这个方法对应C/C++的哪个函数–>找到了是JVM_IHashCode函数–>我去调用这个方法了。
如果不注册,那么在java中执行本地方法的时候就不知道要调用C/C++的哪个函数,现在知道这个作用了吧。

getClass()

    public final native Class<?> getClass();

native修饰的,表明是本地方法,返回此Object的运行时类,什么是运行时类?就是这个Object的引用实实在在的在堆内存中存在的那个对象的类,万物皆对象,返回的这个类就是Class类的对象。有点儿绕?那就简答举个例子说下吧,
1.我建了个类叫Persion—>这个类被加载了(里面记载的类的元数据,都有啥方法,字段,类名叫啥等等一系列数据)
2.程序启动的时候也加载了类—>Class这个类也被加载了(里面也记载了Class这个类的元数据,他的定义的方法就是获取类的元数据的方法,比如getFields(),获取这个类的字段,获取方法等等)
3.我new了一个Persion对象,然后调用了getClass()方法,返回了一个Class对象
4.我用Persion对象可以调用persion类的方法,比如我调用persion的skip()方法让我这个对象可以跳。
5.我用返回的Class对象可以调用class类的方法,比如我调用class的getFields()方法让我知道persion这个类都有啥字段。
这样子解释应该清楚了吧,废话有点儿多,见谅。

equals()

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

这个方法是用来比较两个对象是否相等,在这里直接用的==比较,说明只有地址相同即同一个对象才说明相等,但是很多场景下认为只要某些元素相等就认为是同一个字段,所以常常需要对这个方法进行重写。

    @Override
    public boolean equals(Object o) {
        if (this == o) return true; //同一个对象肯定相等
        if (o == null || getClass() != o.getClass()) return false; //对象类型不同则不相等
        Test test = (Test) o;
        return Objects.equals(name, test.name) && //可根据自己业务场景判断两个对象相等的逻辑
                Objects.equals(age, test.age);   //这里name和age字段相等则认为两个对象相等,
    }

下面是String源码里面重写的equals方法

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;  //同一个对象则相等
        }
         //这里可以用instanceof是因为String类是final的不能被继承,不会有子类来钻空子,其他不是final的类就要用getClass来保证是同一个类型,上面的代码里面就是用的getClass来判断两个对象是不是同一个类。
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true; //字符串长度和字符串内容相等则认为两个对象相等
            }
        }
        return false;  //不属于String类型则不相等
    }

hashCode()

    public native int hashCode();

作用:我认为就是对equals的一个扩展,因为在某些散列表中(比如hashmap,hashset等)要经常判断是否是同一个对象,如果用equals比较的话,数据量很大的情况下,每次一个对象都要和集合中的所有对象做equals比较,这样就太耗费资源了,所以引用了hashcode,在比较是否是同一个对象的时候,先比较hashcode值有没有相等的,因为hashcode是int值,比较起来很容易,如果hashcode相等那么再比较equals是否相等,这样就大大降低了equals的次数,提高了效率。
hashcode和equals关系:

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

看这里重写的hashcode方法,是通过name和age两个属性的值再加上某种算法算出来的一个int值,和上面重写的equals方法对比可以得知。
1.两个方法用的字段需要相等,既然都是唯一标识是否是相等对象,那么肯定属性特征都一样,你说鼻子嘴巴相同就是同一个人,我总不能说鼻子耳朵相同是一个人吧。
2.equals方法相等,那么hashcode方法肯定相等。
3.hashcode方法是通过某种算法算出来的值,所以有可能出现一个人鼻子加嘴巴算出来的值等于腿加胳膊算出来的值,所以hashcode相等,equals不一定相等。
4.重写equals必须重写hashcode,也就是第一条说的,你equals标识一个人嘴巴加鼻子相等,那你得告诉我hascode也是鼻子加嘴巴算hash值啊。
总的来说hashcode就是防止在集合中用equals比较两个对象是否相等,大大的节约了资源增大了效率。
至于有人问hashcode到底是怎么生成的,答案就是JVM根据某种策略生成的,那到底是哪种策略了?谁知道谁孙子!!!反正我是不知道。

clone()

protected native Object clone() throws CloneNotSupportedException;

问题一:什么是深拷贝和浅拷贝
答:深拷贝相当于就是拷贝一个对象的时候,对象里面的属性是引用类型的都要再拷贝一份,可以理解为又new了一个对象。浅拷贝是在拷贝一个对象的时候,新生成的对象里面的属性引用类型和原对象是同一个引用,相当于你这个对象里面的属性是单例的,不管拷贝多少份或者是new多少份,都是指向同一个对象。网上找了个图如下:
在这里插入图片描述
问题二:clone方法实现的是深拷贝还是浅拷贝
答:浅拷贝
问题三:要想实现深拷贝怎么弄
答:在要拷贝的类里面重写clone方法,然后把对象里面的引用也都clone一份。
问题四:怎么能使用clone()方法
答:1.需要实现Cloneable接口。2.重写clone方法,因为clone方法的访问修饰符是protected的,所以要覆盖并且为public的
问题五:clone有啥用
答:这个简单,顾名思义,你就是要一个对象的分身,就可以使用克隆,这样对分身对象的操作就不会影响到原有对象了。

toString()

return getClass().getName() + "@" + Integer.toHexString(hashCode());

这个就是返回类名+@+对象的哈希值转化为16进制的无符号整数的String类型。
我们本来是要看能看懂的一个对象的表现形式,结果给了一堆这玩意儿谁看得懂,所以需要通过这个方法查看类信息的类都要重写。

wait(),notify(),notifyAll()

都是native修饰的方法,具体源码我也看不到,简单说下作用。
首先他们都要用在synchronized同步块里面。
线程A进到了synchronized修饰的同步方法里面,拿到了这个方法的锁对象,然后别的线程就进不来这个方法了,然后线程A就在这个同步方法里面跑代码啊跑代码,跑了一会儿突然发现了wait()方法,这个方法告诉我要把锁释放了,并且我不能再去和别的线程去抢这个锁了,我等静静的看着别的线程吃肉,然后我在旁边流口水。线程A不能继续跑了,那就在门外苦逼的候着吧。
线程B进到了一个同步方法里面,拿到了这个方法的锁对象,也是跑代码啊跑代码,然后看见了一个notify()或者notifyAll()方法,然后就通知这个锁对象上处于wait的线程,notify()是随机通知一个,不一定是谁,notifyAll()是通知所有的需要拿这把锁的处于wait()状态的线程,你们可以去竞争这个锁了,线程B接下来该执行啥还是执行啥,这里只是相当于吼了一嗓子。
线程A此时听到了线程B的叫唤,恶狗一样的去和其他线程竞争这把锁了,竞争上了以后就把刚才wait()之后的代码跑完,这个就是大致的过程,当然wait()方法也可以指定的时间再去有机会去和别的线程抢这把锁。这里要注意的就是同一个锁,同一个锁。
至于wait()和notify()用于线程同步的各种其他的情况,我也就不详细的讨论了。

结尾

终于有时间可以静静的写下博客了,前段时间太忙了,各种改来改去的需求,各种填坑挖坑,今天周五,明天不上班,想想都有点儿小激动了。

猜你喜欢

转载自blog.csdn.net/weixin_44130081/article/details/89404931
今日推荐