java 基础类Object及接口Cloneable 源码分析

目录

简介

普通方法

registerNatives

getClass

hashCode

equals

clone

clone方法对于的Cloneable接口

toString

与线程有关的方法

notify及notifyAll

wait的三个方法

finalize


简介

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

java 基础类Object及接口Cloneable 源码分析_第1张图片

 

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

普通方法

registerNatives

用于注册本地方法

    /**
     * 
     * 

顾名思义,在类初始化时调用registerNatives()方法进行本地方法的注册,也就是初始化java原生方法(native修饰)映射到对应的其他语言描述方法,比如c语言的方法. * 我们可以发现用native修饰的方法都没有具体的方法体(类似于抽象方法),因为不需要java来实现,是使用其他语言实现的。直接调用即可,而且同时用final修饰,我们都无法重写 * 但是hashCode()却不一样,并没有final修饰,而hashCode()的重写对于散列数据结构大有用处。所以说hashCode()既是一个native方法也是一个java方法。 *

在你的Java类中,声明一个本地方法(最好是静态的)名称registerNatives(或任何其他名称,这并不重要)。 * 在你的本地代码中,定义一个名为的函数Java__registerNatives, * 其中包含对JNI函数的调用RegisterNatives。 确保在你的Java代码中,registerNatives在调用其他本地方法之前调用Java 方法。 */ private static native void registerNatives(); static { registerNatives(); }

getClass

返回这个类运行时的class

    /**
     * 
     * 

返回这个类运行时的class。返回的class对象是一个被当前所表示类的静态同步方法锁住的对象。 * *

结果实际的类型是Class , 这里的|X|是调用getClass方法对象的静态类型的擦除结果。 * 例如,对下面的代码块不需要强制转换 * *

* {@code Number n = 0; }
* {@code Class c = n.getClass(); } *

* * @return The {@code Class} object that represents the runtime * class of this object. * @jls 15.8.2 Class Literals */ public final native Class getClass();

hashCode

返回这个对象的哈希码的值

    /**
     * 

返回这个对象的哈希码的值。这个方法是为了支持哈希表,例如hashmap * *

通常hashcode的约定是: * *

    *
  • 当java程序执行时,对同一个对象调用多次hashcode方法,必须一致地返回相同的integer, * 前提是没有修改用equals进行比较的信息。 * 这个integer,不需要在一个java程序执行时与另一个相同的java程序执行时相同。(hashcode可以考虑用内存地址) * *
  • 如果两个对象根据equals方法是相同的,那么对两个对象分别调用hashcode方法,必须产生相同的integer结果。 * *
  • 如果两个对象根据equals方法是不相同的,那么对两个对象分别调用hashcode方法,不需要产生不同的integer结果。 * 尽管,程序员应该注意到,不相同的对象产生不同的hashcode可能改善哈希表的效果。 *
* *

与实际情况一样,由object类定义的hashcode方法确实对不同的对象返回不同的结果。 * (这通常是通过转换对象的内存地址变成一个integer实现的,但是java变成语言不需要这种实现技术。 * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */ public native int hashCode();

equals

表明另一个对象是否与这个对象相同

    /**
     * 

表明另一个对象是否与这个对象相同。 * *

equals方法实现了对非空对象引用的等价关系。 * *

    * *
  • 这是自反性的。对于任何非空引用x,x.equals(x)应该返回true. * *
  • 这是对称的,对于任何非空引用x和y,x.equals(y)应该返回true,当且仅当y.equals(x)返回true * *
  • 这是可传递的。对于任何非空引用x,y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)应该返回true * *
  • 这是一致的,对于任何非空引用x和y,多次调用x.equals(y)应该一致地返回true或者false, * 前提是不修改对象的equals比较中使用的信息。 * *
  • 对于任何非空引用x, x.equals(null)应该返回false * *
*

object类的equals方法实现了最可能识别的对象间等价关系,那就是,对于任何非空引用x和y, * 这个方法返回true,当且仅当x和y引用了同一个对象(x==y为true) * *

注意,当equals方法被重写时,hashcode方法通常也需要被重写, * 这是为了维持对于hashcode方法的基本约定,就是相同的对象必须有相同的hashcode * * * @param obj the reference object with which to compare. * @return {@code true} if this object is the same as the obj * argument; {@code false} otherwise. * @see #hashCode() * @see java.util.HashMap */ public boolean equals(Object obj) { return (this == obj); //根据引用判定是否相同 }

clone

创造并返回这个对象的copy。

    /**
     * 

创造并返回这个对象的copy。copy的确切含义可能依赖于这个对象的类。 * 通常的目的是:对于任何对象x, x.clone() != x 为true, * 并且x.clone().getClass() == x.getClass() 为true,但这些不是绝对的要求。 * *

典型的例子是x.clone().equals(x) 为true,但这不是绝对的要求。 * *

按照约定,返回的对象应该通过调用super.clone来获得。如果一个类和它所有的超类(除了Object) * 遵循这个约定,那就会x.clone().getClass() == x.getClass() * *

按照约定,有这个方法返回的对象应该不依赖于这个对象(被克隆的对象)。为了满足不依赖性, * 这可能有必要在返回对象前修改它的一个或多个属性。 * 典型地,这意味着复制任何由被克隆对象的内部深度结构的可变对象并且将这些对象的引用替换。 * 如果一个类仅仅包含基本属性或者对不可变对象的引用,通常情况下,返回的对象内没有属性要修改。 * *

object类的clone方法执行了一个特定的克隆操作。 * 第一,如果这个对象的类没有实现cloneable接口,会抛出CloneNotSupportedException。 * 注意:所有的数组被认为实现了cloneable接口并且一个数组类型为T[]的对象,clone方法返回的对象类型也是T[],T是任意引用或者基本类型。 * 然而,这个方法创造了这个对象的一个新实例,并且以这个对象的具体属性的内容,初始化了新对象的所有属性,就好像是通过赋值那样。 * 属性的值不少它们自己克隆的。因此,这个方法执行了对这个对象的浅复制而不是深复制。 * *

object类它自己没有实现cloneable接口,所以调用一个object类的对象的clone方法会导致抛出运营时错误CloneNotSupportedException * * @return a clone of this instance. * @throws CloneNotSupportedException 如果这个对象的类不支持cloneable接口,会抛出CloneNotSupportedException。 * 覆盖了clone方法的子类也能抛出这个错误来显示这个对象不能被克隆。 * @see java.lang.Cloneable */ protected native Object clone() throws CloneNotSupportedException;

clone方法对于的Cloneable接口

/**
 * 
 * 

一个实现了cloneable接口的类代表着object类的clone方法是合法的,来对这个类的实例做一个属性对属性的复制。 * *

对一个没有实现cloneable接口的实例调用object的clone方法,会导致抛出CloneNotSupportedException * *

按照约定,实现这个接口的类应该覆盖object的clone方法。 * *

注意:这个接口没有包含clone方法。因此,不可能仅仅凭借实现这个接口来克隆一个对象。 * 即使这个克隆方法通过反射来调用,也不能保证它将成功。 * * @author unascribed * @see java.lang.CloneNotSupportedException * @see java.lang.Object#clone() * @since JDK1.0 */ public interface Cloneable { }

toString

返回这个对象的字符串表示。

    /**
     * 

返回这个对象的字符串表示。通常,toString方法返回用文字表示这个类的字符串。 * 这个结果应该是一个简洁的,充满信息的,诞生又利于人阅读的表示。 * 通常建议所有的子类覆盖这个方法。 * *

Object类的toString方法返回一个字符串,由这个类的实例的类名字,@, * 无位数的十六进制的哈希值组合而成。换言而之,这个字符串等价于 getClass().getName() + '@' + Integer.toHexString(hashCode()) * * @return a string representation of the object. */ public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }

与线程有关的方法

notify及notifyAll

唤醒一个或所有正在这个对象监视器上等待的线程。

    /**
     * 
     * 

唤醒一个正在这个对象监视器上等待的线程。 * 如果有多个线程在这个对象上等待,它们中的一个被选择,从而被唤醒。 * 这个选择是任意的并且由实现来决定。 * 一个线程通过调用wait方法中的一种来在一个对象上的监视器上等待。 * *

被唤醒的线程将不能继续进行,直到当前线程放弃在这个对象上的锁。 * 被唤醒的线程将与其他线程以通常的方式竞争,那些线程可能积极地竞争同步该对象, * 在成为下一个锁住改对象的线程前,被唤醒的线程在竞争上没有可信的优势或劣势。 * *

这个方法应该仅仅被拥有这个对象的监视器的线程调用。 * 一个线程以下面三种方式之一拥有这个对象的监视器。 * *

    *
  • 通过执行该对象的同步实例方法(该对象的类中带synchronized关键字的方法) *
  • 通过执行在该对象上同步的synchronized语句的主体。 *
  • 对于类型是Class的对象,通过执行一个该类的静态同步方法 *
*

* 同一时间,只能有一个线程拥有一个对象的监视器 * * @throws IllegalMonitorStateException 如果当前线程没有拥有这个对象的监视器 * @see java.lang.Object#notifyAll() * @see java.lang.Object#wait() */ public final native void notify(); /** *

唤醒所有在这个对象的监视器上等待的线程。 * 一个线程通过调用wait方法中的一种来在一个对象上的监视器上等待。 * *

被唤醒的线程将不能继续进行,直到当前线程放弃在这个对象上的锁。 * 被唤醒的线程将与其他线程以通常的方式竞争,那些线程可能积极地竞争同步该对象, * 在成为下一个锁住改对象的线程前,被唤醒的线程在竞争上没有可信的优势或劣势。 * *

这个方法应该仅仅被拥有这个对象的监视器的线程调用。 * * @throws IllegalMonitorStateException 如果当前线程没有拥有这个对象的监视器 * @see java.lang.Object#notify() * @see java.lang.Object#wait() */ public final native void notifyAll();

wait的三个方法

让当前线程等待,直到另一个线程调用这个对象的notify或者notifyAll方法,或者已经过去指定的时间

    /**
     * 

让当前线程等待,直到另一个线程调用这个对象的notify或者notifyAll方法,或者已经过去指定的时间 * *

当前线程必须拥有这个对象的监视器。 * *

这个方法将当前线程(调用这个方法的线程T)放置于这个对象的等待集中,然后 * 放弃该对象上的任何和所有同步声明。线程出于线程调度的目的被禁用,并且处于休眠状态, * 直到下面四样事情之一发生: * *

    * *
  • 一些其他的线程调用这个对象的notify方法,并且这个线程T碰巧被选择为被唤醒的线程。 * *
  • 一些其他的线程调用这个对象的notifyAll方法。 * *
  • 一些其他的线程调用线程T的interrupt方法,打断了线程T。 * *
  • 指定的实际时间已经过去了。如果timeout为0,那么,实际的时间不会被考虑,线程会一致等待到被唤醒。 * *
* *

线程T然后被从这个对象的等待集中被移除,并且重新启用线程调度。 * 它然后与其他线程以通常的方式竞争在该对象上同步的权利。 * 一旦它得到该对象的所有权,它在该对象上所有的同步声明被恢复到wait方法被调用时的状态。 * 线程T然后从wait方法的调动中返回。 * 因此,从wait方法返回时,这个对象和线程T的同步状态与调用wait方法时完全一样。 * *

一个线程也能在没有被notify,interrupt,或者超时的情况下被唤醒,那叫做伪唤醒。 * 虽然这个很少在实践中发生,应用程序必须测试导致线程被唤醒的条件来防止它。如果条件不满足,则继续等待。 * 换言而之,等待应该总是在循环中发生,像下面这个: * *

     *     synchronized (obj) { //对obj进行同步,在同步块中wait
     *         while (<condition does not hold>) //当条件不满足时循环
     *             obj.wait(timeout);  //调用obj的wait方法
     *         ... // 根据情况采取适当的行动
     *     }
     * 
* *

对于更多信息可以看 java并发编程艺术(2版)的3.2.3章 * 或者effective java(2001)的第50项 * *

如果当前线程在它等待前或者等待中,被interrupt方法打断,就会抛出InterruptedException。 * 在这个对象的锁状态没有恢复到上述之前,这个异常不会被抛出。 * *

注意:当wait方法将当前线程放入这个对象的等待集中时,它仅仅解锁这个对象。 * 当前线程可能同步的其他对象在线程wait时,任然被锁住。 * *

这个方法应该仅仅被拥有这个对象的监视器的线程调用。 * 可以看notify方法,查看如何拥有这个对象的监视器的方法。 * * * @param timeout 等待的最大时间,单位为毫秒 * @throws IllegalArgumentException 如果timeout的值是负的 * @throws IllegalMonitorStateException 如果当前线程没有拥有这个对象的监视器 * @throws InterruptedException 如果当前线程在等待notify之前或者之时被任意线程interrupt,会抛出这个异常。 * 当异常抛出时,当前线程的interrupted状态被清除。 * * @see java.lang.Object#notify() * @see java.lang.Object#notifyAll() */ public final native void wait(long timeout) throws InterruptedException; /** *

让当前线程等待,直到另一个线程调用这个对象的notify或者notifyAll方法,或者已经过去指定的时间 * *

这个方法与有一个参数的wait方法类似,但它允许更好地控制在放弃前等待notify的时间量。 * 时间量以纳秒测量,公式为: * *

*
     * 1000000*timeout+nanos
* *

在所有其他的方面,这个方法与使用一个参数的wait方法一样。 * 尤其是,wait(0, 0)与wait(0)相同。 * *

当前线程必须拥有这个对象的监视器。线程放弃监视器的控制权并且等待,直到下面两个条件之一发生: * *

    * *
  • 另一个线程notify等待在这个对象的监视器的线程,通过调用notify或者notifyAll方法。 * *
  • 特定的时间过去了,时间大小为timeout的毫秒+nanos的纳秒 * *
* *

这个线程然后等待,直到它重新拥有监视器的拥有权,然后恢复执行(执行wait后面的代码)。 * *

与一个参数的版本一样,interrupt和伪唤醒是可能的,这个方法应该总是在循环中被使用。 *

     *     synchronized (obj) {
     *         while (<condition does not hold>)
     *             obj.wait(timeout, nanos);
     *         ... // Perform action appropriate to condition
     *     }
     * 
* 这个方法应该仅仅被拥有这个对象的监视器的线程调用。 * 可以看notify方法,查看如何拥有这个对象的监视器的方法。 * * @param timeout 等待的最大时间,单位为毫秒 * @param nanos 额外的时间,在纳秒的范围内 * 0-999999. * @throws IllegalArgumentException 如果timeout的值是负的或者nanos的值不在0-999999之内 * @throws IllegalMonitorStateException 如果当前线程没有拥有这个对象的监视器 * @throws InterruptedException 如果当前线程在等待notify之前或者之时被任意线程interrupt,会抛出这个异常。 * 当异常抛出时,当前线程的interrupted状态被清除。 */ public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { //校验timeout throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { //校验nanos throw new IllegalArgumentException( "nanosecond timeout value out of range"); } //如果是1.6版本,那就是 // nanos 大于 500000 即半毫秒 就timout 加1毫秒 // 特殊情况下: 如果timeout为0且nanos大于0,则timout加1毫秒 //if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { // timeout++; //} //java中最小的时间单位还是毫秒,可能是由于操作系统做不到纳秒级别的精确度(或者是不需要精确到纳秒级别),因此jdk中做了一个近似处理的操作。 if (nanos > 0) { //注意:这个是1.8版本的,如果有nanos,那就执行毫秒数+1 timeout++; } //调用wait的一个参数的方法 wait(timeout); } /** * 让当前线程等待,直到另一个线程调用这个对象的notify或者notifyAll方法。 * 换言而之,这个方法仿佛执行了wait(0) (实际上就是调用了这个方法) * *

当前线程必须拥有这个对象的监视器。这个线程放弃了监视器的拥有权,并且等待, * 直到另一个线程调用这个对象的notify或者notifyAll方法。 * 这个线程然后等待直到它能重新获得监视器的拥有权,然后恢复执行。 * *

与一个参数的版本一样,interrupt和伪唤醒是可能的,这个方法应该总是在循环中被使用。 *

     *     synchronized (obj) {
     *         while (<condition does not hold>)
     *             obj.wait();
     *         ... // Perform action appropriate to condition
     *     }
     * 
* 这个方法应该仅仅被拥有这个对象的监视器的线程调用。 * 可以看notify方法,查看如何拥有这个对象的监视器的方法。 * * @throws IllegalMonitorStateException 如果当前线程没有拥有这个对象的监视器 * @throws InterruptedException 如果当前线程在等待notify之前或者之时被任意线程interrupt,会抛出这个异常。 * 当异常抛出时,当前线程的interrupted状态被清除。 * @see java.lang.Object#notify() * @see java.lang.Object#notifyAll() */ public final void wait() throws InterruptedException { wait(0); }

finalize

    /**
     * 
     * 

当垃圾收集确定没有对这个对象的引用时,垃圾收集器调用对象的这个方法。 * 子类可以覆盖finalize方法,来处理系统资源或者执行其他的清理。 * *

finalize通常的约定是如果当java虚拟机已经确定: * 当除了一些其他的类或者准备被结束的对象的终结过程中采取的措施外, * 还没有死亡的线程不再有途径访问到这个对象,调用这个方法。 * finalize方法可以采取任何措施,包括让其他线程能重新访问这个对象。 * 然而,finalize普通的目的是在对象被不可撤回地丢弃前,执行清理活动。 * 举个例子,一个代表着一个输入/输出的连接的对象的finalize方法 * 可能在执行显式的io事务,以便让对象被永久地丢弃前,断开连接。 * *

object类的finalize方法没有执行特殊的行为,它就直接返回了(啥都没干)。 * object的子类可能覆盖这个定义。 * *

java编程语言不能保证哪个线程会调用给定对象的finalize方法。 * 然而,它保证,调用finalize方法的线程不会在调用方法时持有任何用户可见的同步锁。 * 如果finalize方法抛出一个没有被捕获的异常,异常会被忽视,对象的终结过程结束。 * *

在一个对象的finalize方法已经被调用后,不会有其他的行动, * 直到java虚拟机再次确定任何活着的线程不再能访问到这个对象, * 包括其他准备终结的类或者对象可能的行动, * 这次确定时,对象可能被抛弃。 * *

一个给定的对象的finalize方法不会被java虚拟机调用超过一次。 * *

finalize方法抛出的任何异常会导致对象的终结过程结束,但是异常被忽略了。 * * @throws Throwable 被这个方法抛出的异常 * @see java.lang.ref.WeakReference * @see java.lang.ref.PhantomReference * @jls 12.6 Finalization of Class Instances */ protected void finalize() throws Throwable { }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(java,源码分析)