java源码学习-详解Object类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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源码和自己的一些看法,如有不足或者错误的地方,还请大家多多指教,共同进步。本文内容纯属原创,转载请注明出处,谢谢!

 




































































































以上是关于java源码学习-详解Object类的主要内容,如果未能解决你的问题,请参考以下文章

java.util.Objects 源码学习

Java线程池详解

单例设计模式详解+源代码+JDK源码应用——Java设计模式系列学习笔记

Java学习笔记3.5.4 继承 - Object类

Java基础1----Object类解析

Java开发基础知识之学习篇——Object类