posts - 3, comments - 0, trackbacks - 0, articles - 1

导航

公告

java对象生命周期

Posted on 2014-11-25 23:15 午夜星光 阅读(...) 评论(...)  编辑 收藏

  java中一个对象的完整生命周期涉及java平台的很多技术。在创建一个java对象之前,需要先由虚拟机加载该类,然后对该java类进行链接和初始化。初始化完成之后,才创建出该类的对象实例。java对象也有自己的初始化过程,主要通过构造方法完成。当不再有引用指向该对象时,对象占用的内存会在合适的时机被垃圾回收器回收。对象终止机制提供了一种方式在对象被回收之前进行清理工作。

  •  java类的链接

  虚拟机刚启动时,内部只包含java核心类的相关信息。随着程序的运行,不断有新的java类被加载到虚拟机中。java类被加载之后,经过链接和初始化就可以虚拟机中使用了。链接的过程是把java类的字节码中包含的信息与虚拟机中的内部信息进行合并,使java类的代码可以执行。链接的过程包含3个步骤,分别是验证,准备和解析。在链接过程中会对java类的直接父类或父接口进行验证和准备,但对类中形式引用的解析是可选的。

  验证:验证是用来确保java类的字节代码在结构上是正确的。验证过程可能会导致其他java类或接口被加载。字节码格式不正确会抛出java.lang.VerfyError错误。

  准备:准备过程会创建java类中的静态域,并将这些域的值设为默认值。准备过程不会执行代码。

  解析:解析过程是处理所加载的java中包含的形式引用。在解析过程会遇到的一个问题是如何处理复杂的引用关系图,通常有两种策略:1,提前解析:即递归地对形式引用进行解析;2,延迟解析:当真正需要一个形式引用才进行解析。

  • java类的初始化

  当一个java第一次真正使用时,虚拟机会对该java类进行初始化。初始化的主要工作是执行java类中的静态代码块和初始化静态域。在初始化过程中,按出现顺序进行初始化,在初始化之前,它的直接父类也会被初始化,但是java类实现的接口不会被初始化。

  需要注意的是当访问一个java类或接口中的静态域时,只有真正声明这个域的类或接口接口才会被初始化。

  •  对象的创建与初始化 

  在创建对象时,实际的初始化流程实现沿着继承层次结构树往上传递,完成部分初始化工作。到达Object类之后,再沿着层次结构树向下;完成其余的初始化工作,最后回到最初的java类。

  在进行对象创建之前,需要为对象分配内存空间,大小取决于java类及其父类和祖先类包含的所有实例域的数量和类型。如果内存分配成功,则把对象的所有实例域都设为默认值。

  类的构造方法的调用过程分为三步:1,调用父类的构造方法;2,初始化类中的实例域的值(按照出现顺序);3,执行类的构造方法。实际的执行流程会先跳转到父类的构造方法,再沿着继承层次结构树依次往上跳转,直到到达Object类,不在向上跳转,而是执行后两步操作。整个过程是一个典型的递归调用过程。

  • 对象终止

  如果一个java类的对象有自定义的销毁逻辑,那么可以覆写Object类的finalize方法,并在finalize中添加代码。finalize中的这一段处理逻辑称为对象的终止器,但在实际的程序中并不实用。最主要的原因是java语言并没有规定finalize方法的调用时间进行明确规定,只是规定finalize方法一定在对象的内存空间被垃圾回收器回收之前进行调用,然而垃圾回收器的运行时间是不固定的,因此一个对象的回收时间也是不固定的。这双重的不固定性导致finalize运行时间不固定,容易产生与时间有关的错误。
  在finalize方法中要避免创建当前对象的新引用,一个对象的finalize方法只会被调用一次。

  在finalize方法的声明中,finalize方法可能抛出任何类型的异常。如果finalize方法在执行过程出现异常,则抛出的异常会被忽略,finalize调用终止。因为finalize方法是由虚拟机直接调用的,无法在代码中捕获异常,也不会有异常的堆栈信息打印出来。

  在对象被回收之前,父类的终止逻辑也要被调用。在finalize方法实现中,先编写当前类的终止逻辑,再通过super.finalize()来调用父类的finalize方法,为保证父类的finalize方法总被调用,应把当前类的终止逻辑封装在一个try-finally结构中。

  • 对象的复制

  Object类中的clone方法和java.lang.Cloneable接口用来提供标准的对象复制功能。Cloneable是一个不包含任何方法的标记接口,它的作用是作为复制功能相关的标记。如果调用clone方法的类没有实现

Cloneable接口,那么clone方法会抛出java.lang.ClongNotSupportedException异常。实现了Cloneable接口的java类需要提供一个公开的clone方法来覆写Object类的clone方法,因为Object中的clone方法被声明为保护的,如果不进行覆写,外部对象无法访问到clone方法。