zoukankan      html  css  js  c++  java
  • java源码学习详解Object类

    java语言的学习,研究JDK源码是掌握基本语法之后,提升能力的一个很重要的途径。

    本篇内容主要解决以下内容:

      1)对Object中的方法进行一个简单的总结;

      2)对每个方法进行解读,主要包括注意事项和开发中需要注意的点;

      3)简单描述一下Object中这几个方法的作用与java语言中那些特性相关;

    /*
      Object类是java类层次体系的根类,也就是所有类的父类。所有的类,包括数组,都实现了Object类中的方法。
      类的权限修饰符也很重要啊,看清权限修饰符
    */
    public
    class Object { }
    /*
      registerNatives(),是Object类私有的,主要将本地方法注册到虚拟机中
    */

    private
    static native void registerNatives(); static {   registerNatives(); }
    /*
      public:表示方法是公有的,final修饰,表示每个类得到的字节码对象的地址引用,在内存中的位置是固定的,native修饰,具体实现是有虚拟机来实现
    */
    public final native Class<?> getClass();
    /*
       功能:返回当前对象的hash值
      目的:为java中散列表提供服务
      注意事项:
        1) 在一个java应用的运行期间,同一个对象多次调用这个方法,应该返回同一个整数。
        2) 对同一个对象来说,第一次运行这个程序得到的hashcode值和第二次运行这个程序得到的hashcode值可以不一样
        3) 如果两个对象通过equals(Object)方法判断的结果为true,那么这两个对象调用各自的hashcode方法应该返回相同的整数值
        4) 两个对象通过equals方法返回的结果为false,那么他们各自的hashcode方法的返回值,可以相同,(也可以不相同)。但是作为程序设计员应该意识到两个对象通过equals方法返回的结果应该与hashcode方法的返回值的比较结果一致,
          这样会提高哈希表的性能。这也就是为什么说在重写equals方法的时候,需要重写hashcode方法的缘由。
    */
    public
    native int hashCode();
    /*
      功能:用来表明这个对象和其他的对象是否是相等的。
      特性:
        1 自反性 一个对象应该和自己是相等的
        2 对称性 对于两个非空引用,x,y; x.equals(y)的结果和y.equals(x)一致
        3 传递性 对于任意一个非空引用 x,y,z x.equals(y) == true x.equals(z) == true,则y.equals(z) == true
        4 一致性
        5 唯一性 对于任何非空引用x,x.equals(null) === false

      注意事项:
        1 在没有重写equals方法的时候,对于任意两个非空引用x,y若x.equals(y)则意味着它们指向相同的地址引用
        2 当equals方法被重写的时候,hashcode方法也是需要被重写的,目的就是维护一个契约,equals方法的结果和hashcode方法的结果一致
    */

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

    /*
      权限修饰符:protected,这个很重要,意思也很简单的只有类自己的对象才可以调用这个方法,保证了安全,维护了秩序。
      异常 :CloneNotSupportedException,对象调用clone()方法,必需要实现Cloneable接口(Object类没有实现这个接口 Object obj = new Object(); obj对象没有clone()方法的),否则在运行时抛出此异常
      功能 :创建并返回当前对象的一个副本。 这个副本和原对象并不总是一致的,也就是这是一个浅拷贝(与深度拷贝的详细将在另一篇文章中详细介绍,并给出具体的实现)。具体分析如下:
            1、对于一个非空对象 x.clone() != x,x和x.clone()具有不同的内存地址
            2、x.clone().getClass() == x.getClass()为true
            3、数组类型的接口都实现了Cloneable接口,同时如果数组类型的装载的是基本数据类型(int,double,String等),则使用该方法,在新clone的对象中,该值是存在的
     
    */

    protected
    native Object clone() throws CloneNotSupportedException;
    /*
      功能:返回当前对象的一个字符串表示形式。
      getClass().getName()获取当前的字节码对象后再获取当前的对象的包名+类名
      返回结果:当前对象的包名+类名+"@"+当前对象的hashcode值的16进制的表示形式

      推荐:对所有需要描述类信息的对象重写该方法,因为这样的形式不利于直观的描述对象的信息
    */

    public
    String toString() { return getClass().getName() + "@" Integer.toHexString(hashCode()); }
    /*
      功能:唤醒一个正在等待此对象监视器的单线程
      注意事项:
        1)如果有多个线程均在等待这个对象,那么只有一个线程可以被唤醒,被唤醒的线程是随机的。
        2)通过调用wait方法,实现一个线程对一个对象监视器的等待
        3)只有当前线程放弃当前对象的锁,那么被唤醒的线程才可以执行。但是唤醒的线程并没有特权或者劣势去得到下一个该对象的锁(随机的)
        4)在同一时间,只有一个线程可以得到这个对象监视器
      方法调用:
        1)这个线程对象监视器的主人可以调用这个方法。
      一个线程拥有这个对象监视器一般有三种方法:
        1 实例方法上
    2 方法内代码块(实例方法和静态方法,实例方法内可以是任意对象,静态方法只能是当前类的字节码文件对象)
         3 静态方法上
    */
    public
    final native void notify();

    对象监视器的三种方法:
     1 public class ObjectStudy {
     2 
     3     private Object lock = new Object();
     4     
     5     /**
     6      * 语句的主体在当前类对象上同步
     7      */
     8     public synchronized void test() {
     9         System.out.println("hello test1 ...");
    10     }
    11 
    12     /**
    13      * 通过任意对象来进行同步,可以使用this
    14      */
    15     public void test2() {
    16         System.out.println("hello world");
    17         synchronized (lock) {
    18             System.out.println("hello test2 ...");
    19         }
    20     }
    21 
    22     /**
    23      * 类的同步静态方法
    24      */
    25     public synchronized static void test3() {
    26         System.out.println("hello test3 ...");
    27     }
    28     public static void test4() {
    29         synchronized(new ObjectStudy().getClass()){
    30             System.out.println("hello test3 ...");
    31         }
    32     }
    33 }
    /*
      功能:唤醒所有正在等待此对象的监视器
      注意事项:
        1 虽然所有线程都被唤醒,但在同一时间只有一个线程可以执行
      方法调用参见notify()方法
    */
    public
    final native void notifyAll();
    /*
      功能:使当前线程处于等待状态,直到另一线程调用notify方法或者notifyAll()方法,又或者超过指定时间,该线程开始执行
    */
    public
    final native void wait(long timeout) throws InterruptedException;
    /*
      功能:使线程处于等待状态
      参数:
        long timeout -->等待的最大时间,单位是毫秒
        int nanos -->附加时间,提高精确度,取值范围在0-999999
      异常:
        参数不合格会抛出运行时异常
    */



    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"); } // 对timeout取一个合理的值
    if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {   
      timeout
    ++;
    }
      wait(timeout);
    }
    /*
      
    */
    public
    final void wait() throws InterruptedException { wait(0); }
    /*
      功能:当垃圾收集器认为该对象的引用没有被在任何被引用时,垃圾收集器会调用此方法进行垃圾回收。
      修饰符:protected --> 子类可以重写该方法,去处理系统资源,并进行其他一些清理操作。
    */
    protected
    void finalize() throws Throwable { }

     总结:

      本地方法7个:

                  private static native void registerNatives()

                  public final native Class<?> getClass()

          public native int hashCode()

          protected native Object clone()

                  public final void notify()

                  public final native void notifyAll()

                  public final native void wait(long timeout)

      非本地方法5个:  

            public boolean equals(Object obj)

              public String toString()

            public final void wait(long timeout,int nanos)

            public final void wait()

            protected void finalize()

      静态代码块:

        static {

          registerNatives();

        }

      一、体会权限修饰符使用的魅力,private,public,protected,除了包级默认的修饰符,Object类中全包含了;现在简要的分析一下:

        1) private static native void registerNatives(),这个方法只有Object类自己调用,在Object类加载的时候执行,主要对几个本地方法进行注册(可以理解为将本地方法映射到虚拟机中)

        2) public final native Class<?> getClass(),注意方法前的final修饰符,表明这个方法是由虚拟机来实现的,子类不能够重写

        3) public native int hashCode(),这也是一个本地方法,但是却允许子类对其重写

        4) protected native Object clone(),这个方法的权限修饰符是protected,是public又会怎么样呢?

          a)对protected关键字进行一下解读,在同一个包下,该类的对象可以访问到protected修饰的方法,该类的子类可以在任何情况下访问到父类的protected修饰的方法

          b)如果一个类没有重写clone()方法,那么只有创建在该类中的类的对象才可以访问到clone()方法,因为此时访问的是Object类的clone()方法,此时对clone()方法的访问是基于子父类的关系访问到的,在这种情况下,如果在其他的类中访问clone()方法,

           是无法访问的,因为Object和当前类不在同一个包下。

          c)这个权限修饰符只能是protected,原因是保证clone()方法的可控性

          d)建议子类在对Object类中clone()方法进行重写时,权限修饰符仍为protected,除非你可以保证一切尽在掌控之中。

        5) protected void finalize(),修饰符是protected,可以参考 4)

      二、对方法功能进行简要概述

        1 registerNatives() 私有方法,注册本地方法

        2 getClass(),获取字节码对象,与java中反射机制有关

        3 hashCode(),为java中哈希数据结构提供支持

        4 toString(),对对象进行描述

        5 clone(),提供对象克隆

        6 notify、notifyAll、wait方法和java中的线程有关

        7 finalize,与垃圾回收相关

        8 equals(),用于判断两个对象是否相等

      三、关于Object类的思考

        1、权限修饰符的使用,在写程序的时候,认真思考一下,使用什么的样的权限修饰符,你是否真的搞明白了权限修饰符的用法?

        2、final、native关键字的理解,当然还有构造方法、静态代码块,构造代码块,静态方法,静态成员变量的执行顺序是怎样的?因为我们看到Object类中有静态代码块,看到了就思考一下。

        3、这有一个很有趣的问题,notify、notifyAll、wait方法这些和多线程有关的类,为什么设置在Object类中?关于这几个方法的详细解读,将在介绍多线程时,进行描述。

        4、关于一个常见问题的答案,重写equals()方法,为什么要重写hashcode()方法,可以JDK源码中找到合适的答案(在上文中已经描述的很清楚了)。

        5、在学习的过程中,一定要对概念有深刻的理解概念,不能人云亦云。

      四、小结

        以上内容来自于JDK源码和自己的一些看法,如有不足或者错误的地方,还请大家多多指教,共同进步。本文内容纯属原创,转载请注明出处,谢谢!

  • 相关阅读:
    校验函数
    声明
    主程序(开始检查)
    活代码LINQ——09
    活代码LINQ——08
    活代码LINQ——07
    活代码LINQ——06
    活代码LINQ——05
    活代码LINQ——04
    活代码LINQ——03
  • 原文地址:https://www.cnblogs.com/dreamfor123/p/6653037.html
Copyright © 2011-2022 走看看