zoukankan      html  css  js  c++  java
  • java源码解析之Object类

    Object类介绍

      Object类作为java所有类中的超类,看似很牛,(๑╹ヮ╹๑)好吧,其实确实很牛,毕竟他是所有类的祖先,是java继承体系中真正的根节点,其实我们在学习的过程中慢慢的就会发现,越是底层的类,其功能就越复杂,而越处于上层,其功能反而越简单,但Object真的是这样吗?其实简单仅仅是类内部的方法少,并不是容易学,其反而更加抽象,更加难以理解

    我只举了几个常用的类,java继承是一种树形体系结构,Object是根节点

      Object类是java.lang包下的,java.lang包下的类不需要导入就可以直接使用,因为java只有单继承和多重继承,即每一个类只能有一个父类,但其父亲却同样可以拥有父亲,以此类推即为多重继承。所以对于Object中声明的方法,在我们所见到的类(包括我们自己写的)都具有这些方法,我们一般不会直接使用Object的对象,而是重写继承自Object类的方法,

        /*
         * Object类是类层次结构的根。每个类都有 Object作为超类。所有对象,包括数组,实现这个类的方法。 
         */
    public class Object {    
        /* native:
         * 我们看到了有好几个方法是由native修饰的,那么native方法是什么意思呢?
         * native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。
         * Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI(Java Native Interface)接口调用其他语言来实现对底层的访问。 
         * JNI是Java本机接口,是一个本机编程接口,它是JDK的一部分。JNI允许Java代码使用以其他语言编写的代码和代码库。
         *  InvocationAPI(JNI的一部分)可以用来将Java虚拟机(JVM)嵌入到本机应用程序中,从而允许程序员从本机代码内部调用Java代码。
         */
    
        private static native void registerNatives();
        /*
         * registerNatives():
         * 顾名思义,在类初始化时调用registerNatives()方法进行本地方法的注册,也就是初始化java原生方法(native修饰)映射到对应的其他语言描述方法,比如c语言的方法
         * 我们可以发现用native修饰的方法都没有具体的方法体(类似于抽象方法),因为不需要java来实现,是使用其他语言实现的。直接调用即可,而且同时用final修饰,我们都无法重写
         * 但是hashCode()却不一样,并没有final修饰,而hashCode()的重写对于散列数据结构大有用处。所以说hashCode()既是一个native方法也是一个java方法。 
         */
        static {
            registerNatives();
        }
        /*    
         * getClass():
         * getclass()方法返回该 Object运行时类,一般在反射时,我们想得到某个类的class对象,可以通过对象.getClass()获得,但几乎不常用,因为既然都有对象了就不用反射了。
         */
        public final native Class<?> getClass();
        /*
         * hashCode():
         * 学习hashCode(),需要先学习equals(Object obj),hashCode()一般不单独使用,hashCode()的功能是在比较俩个对象是否相等的时候提高比较效率,比如在一些hashSet、hashTable等
         * 数据结构中,不允许存在相同的元素,所以每次插入元素都要和已经存在的元素依次进行比较,如果依次对每个元素调用equals(Object obj),对于大量数据来说太慢了,hashCode()便是在哈希表
         * 结构中提高比较速率的利器,如果俩个元素的hashCode()不同,则equals(Object obj)就不必比较了,因为肯定不同;如果俩个元素的hashCode()相同,则再比较equals(Object obj)
         * 于是我们得出了一个结论:hashCode()相同,equals(Object obj)不一定相同;hashCode()不同,equals(Object obj)一定不同;equals(Object obj)相同,hashCode()一点相同;
         * 但是有一个前提,必须同时重写equals(Object obj)和hashCode()。
         */
        public native int hashCode();
        /*
         * equals(Object obj):
         * equals(Object obj)方法是比较俩个对象是否相等的主要方法,通过源码我们可以看出如果某个类不重写equals(Object obj)方法,那么equals(Object obj)就是==,
         * 而==比较的是基本类型的内容,引用类型的地址,其实无论基本类型还是引用类型,==比较的都是栈内存中的值,可以去看一下JVM的内存模型就明白了。言归正传,不重写equals(Object obj)的话
         * 和==的功能一样,我们可以通过系统的模板一键重写,重写默认比较的是所有属性的值,也可以根据自己的实际需求,去改写自己需要的功能。
         * String类默认重写了此方法。
         */
        public boolean equals(Object obj) {
            return (this == obj);
        }
        /*
         * 返回一个此类的克隆对象,二者具有相同的属性,二者拥有独立的属性存储空间,分别位于堆内存中的俩快空间中,不相互影响,但是也不是绝对的,因为存在浅克隆和深克隆的区别,我会用一篇文章来介绍深克隆和浅克隆
         * 这里注意区别a = b 和  a = b.clone(),他们在堆内存中的存储不一样。
         */
        protected native Object clone() throws CloneNotSupportedException;
        /*
         * toString():
         * 最最最常用的方法,如果你定义一个类,而不去重写toString()的话,那你每一次想看看该类的某个对象的某些属性,你就不得不写一堆getXxx()方法,简直了。其实在输出一个字符串对象a时,输出的就是
         * a.toString();我们在类中重写此方法后,直接输出就是调用此方法,也就是依次遍历对象的所有属性。但是System.out.println(a)和System.out.println(a.toString())是有区别的
         * 当a对象没有实例化时,其中一个会报出NullPointException,至于是哪个,自己动手去试试不就知道了嘛。
         */
        public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
        /*
         * notify():
         * 接下来的俩个方法(notify()和wait())都是在多线程中使用的,至于为什么多线程的方法要写在Object中,这就难以琢磨了!
         * notify()唤醒一个在这个对象的监视器上等待的单个线程。什么是监视器呢,我们知道一个CPU一次只能处理一个进程(线程),那么是谁保证只能有一个进程进入CPU呢,
         * 别忘了,每个进程都是自私的,他可不管里面有没有其他同类。所以我们需要一套规则,需要一个上帝来制约所有的进程,监视器就是这个上帝,他负责某些进程,来维护他们之间的秩序。
         * 唤醒的线程不是得到CPU的使用权,而是和其他就绪线程竞争。也就是将阻塞状态转换为就绪状态,并不是立即执行。
         * 
         */
        public final native void notify();
        /*
         * notifyAll():
         * notifyAll()唤醒一个在这个对象的监视器上等待的所有线程,只要记住唤醒的线程不是得到CPU的使用权,而是和其他就绪线程竞争。
         */
        public final native void notifyAll();
        /*
         * wait(long timeout):
         * wait(long timeout)使当前线程等待另一个线程调用此对象的方法或 notify() notifyAll()方法,或一个指定的时间流逝,API上的谷歌翻译,有点拗口,其实我也不明白什么意思
         * 我猜测大致是,wait方法是一个线程进行等待状态,等待多长时间有参数决定,时间到后自动唤醒,或者在等待期间又其他进程调用其的notify或者notifyAll方法进行唤醒。
         * 而wait(0)代表无限期的等待。因为等待0秒毫无意义!
         * 通过下面的源码,我们可以很明确的看出:wait()==wait(0)==wait(0,0)都是无限期的等待,直到被notify() notifyAll()唤醒
         */
        public final native void wait(long timeout) throws InterruptedException;
        /*
         * 
         */
        public final void wait(long timeout, int nanos) throws InterruptedException {
            if (timeout < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (nanos < 0 || nanos > 999999) {
                throw new IllegalArgumentException("nanosecond timeout value out of range");
            }
    
            if (nanos > 0) {
                timeout++;
            }
    
            wait(timeout);
        }
        /*
         * 
         */
        public final void wait() throws InterruptedException {
            wait(0);
        }
        /*
         * finalize():
         * 当垃圾收集确定没有对对象的引用时,由对象上的垃圾收集器调用。子类重写 finalize方法配置系统资源或执行其他清理。垃圾回收机制中的方法,我会用一章来详细讲解垃圾回收机制
         */
        protected void finalize() throws Throwable {
        }
    }
  • 相关阅读:
    20200209 ZooKeeper 3. Zookeeper内部原理
    20200209 ZooKeeper 2. Zookeeper本地模式安装
    20200209 Zookeeper 1. Zookeeper入门
    20200206 尚硅谷Docker【归档】
    20200206 Docker 8. 本地镜像发布到阿里云
    20200206 Docker 7. Docker常用安装
    20200206 Docker 6. DockerFile解析
    20200206 Docker 5. Docker容器数据卷
    20200206 Docker 4. Docker 镜像
    Combining STDP and Reward-Modulated STDP in Deep Convolutional Spiking Neural Networks for Digit Recognition
  • 原文地址:https://www.cnblogs.com/gollong/p/9329557.html
Copyright © 2011-2022 走看看