• 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 {
        }
    }
  • 相关阅读:
    [Reproduced]BIOS -- Basic Input and Output System
    What is CSM mode?
    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2 In TextInputLayout
    What is “passive data structure” in Android/Java?
    Android Studio 手动配置 Gradle
    ScrollView内嵌ListView,ListView显示不全及滑动冲突的问题
    Android安全开发之Provider组件安全
    Android permission and uses-permission
    PriorityBlockingQueue(带优先级的阻塞队列)
    Lesson: Generics (Updated)
  • 原文地址:https://www.cnblogs.com/gollong/p/9329557.html
Copyright © 2020-2023  润新知