Java 类的生命周期

来源:互联网 发布:mac淘宝买软件 编辑:程序博客网 时间:2024/06/05 17:13

Java 类的生命周期

发表于7个月前(2015-04-03 22:38)   阅读(179) | 评论(0) 11人收藏此文章, 我要收藏
0

尖er货来了!亚马逊AWS AWSome Day 免费云计算培训开始报名  

摘要 不能做一个只能完成工作,却不知道为啥可以完成工作的 程序设计师。 那么现在瞅瞅JVM的类和对象初始化的底层机制。
Java 类的生命周期

目录[-]

  • 上图展示的是类生命周期流向;在本文里,我只打算谈谈类的"初始化"以及"对象实例化"两个阶段。
  • 类初始化
  •  Java虚拟机管理类和对象的生命周期;
  • (1)类的生命周期从类被加载,连接,初始化开始,到类被卸载结束;
  • (2)类处于生命周期时,它的二进制数据位于运行时方法区内,在堆区还有一个相应的描述类的Class类的对象;
  • (3)只有当类处于生命周期中时,Java程序才能够使用它。
  • 1.Java虚拟机及程序的生命周期
  • Java 编译器在编译每个类时都会为该类至少生成一个实例初始化方法--即 "<init>()" 方法。此方法与源代码中的每个构造方法相对应,如果类没有明确地声明任何构造方法,编译器则为该类生成一个默认的无参构造方法,这个默认的构造器仅仅调用父类的无参构造器,与此同时也会生成一个与默认构造方法对应的 "<init>()" 方法. 
  • 2.类的加载,连接和初始化
  • 参考博文:http://www.ibm.com/developerworks/cn/java/j-lo-clobj-init/


    上图展示的是类生命周期流向;在本文里,我只打算谈谈类的"初始化"以及"对象实例化"两个阶段。

    类初始化

    类"初始化"阶段,它是一个类或接口被首次使用的前阶段中的最后一项工作,本阶段负责为类变量赋予正确的初始值。

    Java 编译器把所有的类变量初始化语句和类型的静态初始化器通通收集到 <clinit> 方法内,该方法只能被 Jvm 调用,专门承担初始化工作。

    除接口以外,初始化一个类之前必须保证其直接超类已被初始化,并且该初始化过程是由 Jvm 保证线程安全的。另外,并非所有的类都会拥有一个 <clinit>() 方法,在以下条件中该类不会拥有 <clinit>() 方法:

    • 该类既没有声明任何类变量,也没有静态初始化语句;

    • 该类声明了类变量,但没有明确使用类变量初始化语句或静态初始化语句初始化;

    • 该类仅包含静态 final 变量的类变量初始化语句,并且类变量初始化语句是编译时常量表达式。


     Java虚拟机管理类和对象的生命周期;

    参考博文:http://blog.csdn.net/jbuilder3/article/details/5549104

    (1)类的生命周期从类被加载,连接,初始化开始,到类被卸载结束;

    (2)类处于生命周期时,它的二进制数据位于运行时方法区内,在堆区还有一个相应的描述类的Class类的对象

    (3)只有当类处于生命周期中时,Java程序才能够使用它。

    1.Java虚拟机及程序的生命周期

    (1)通过java命令运行一个Java程序时,启动一个Java虚拟机进程;

    (2)Java虚拟机进程从启动到终止的过程,称为Java虚拟机生命周期;

    (3)程序生命周期和Java虚拟机生命周期是一致的,因为Java虚拟机进程从创建起的任务就是执行Java程序。

    基础说明:

    Java 编译器在编译每个类时都会为该类至少生成一个实例初始化方法--即 "<init>()" 方法。此方法与源代码中的每个构造方法相对应,如果类没有明确地声明任何构造方法,编译器则为该类生成一个默认的无参构造方法,这个默认的构造器仅仅调用父类的无参构造器,与此同时也会生成一个与默认构造方法对应的 "<init>()" 方法. 

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Test {
        public Test(String name) {
            super();
            this.name = name;
        }
        private String name;
        public static void main(String[] args) {
            Test test=new Test("1223344yuuuw");
            System.out.println(test.name);
            new Person().eat(new Apple());
        }
    }


    2.类的加载,连接和初始化

    a.Java程序要使用某个类时,Java虚拟机要确保这个类被加载,连接和运行,其中连接包括验证,准备和解析。

    b.加载:查找并加载类的二进制数据;

    c.连接

      c.1 验证:确保加载类的正确性;

      c.2 准备:为静态变量分配内存,并将其初始化为默认值;

      c.3 解析:将类中的符号引用转换为直接引用。

    d初始化:

       给类的静态变量赋予正确的初始值

    (1)加载(加载的最终目标是实现将编译后的class文件(class文件采用字节码,是JVM的机器语言)装入内存运行时数据区的方法区中,并在内存运行时数据区的堆区生成一个class对象,这个对象可以引用到方法区中的类定义)

         1.1 加载需要完成:

           1.1.1 将类的.class文件中的二进制数据读到内存中的运行时数据区的方法区;

           1.1.2 在堆区创建一个java.lang.Class对象(对象都放在堆区),用于封装类在方法区内的数据结构。

         1.2 加载的最终产品是位于运行时数据区堆区的java.lang.Class对象,Class对象封装了类在方法区的数据结构,并向Java程序提供访问类在方法区内的数据结构的接口

         1.3 类的加载由加载器完成

            1.3.1 Java虚拟机自带的加载器(如果Java虚拟机是一个C++程序,则这些加载器是这个C++程序的一部分)

                     包括启动类加载器,扩展类加载器和系统类加载器《后两个都是java.lang.Class类的实例》

            1.3.2 用户自定义的类加载器

                     java.lang.Class的子类的实例,用户可以通过它定制类的加载方式(用户自定义的类加载器使Java具有动态连接的特性,即Java无需在编译时确定需要的组件<类>,在运行时动态确定需要加载的类)

         类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载过程中遇到.class文件缺失,类加载器等到程序首次调用类的时候报错    

         Java中的类加载器采用父亲委托机制,使用加载器加载类是,首先看其父亲是否能够完成类的加载,如果可以,则由父亲完成类的加载,返回加载的类的java.lang.Class对象,注意,加载器之间的父子关系并不是java中普通的继承关系,而是一种包含关系,具有父子关系的类也许是不同的类型。

    (2)连接

           在连接阶段对静态变量分配内存(静态变量是类作用域变量,仅在类加载时分配一次内存),并赋予默认值。

    (3)初始化

    说了这么多,类的初始化时机就是在"在首次主动使用时",那么,哪些情形下才符合首次主动使用的要求呢?

    首次主动使用的情形:

    • 创建某个类的新实例时--new、反射、克隆或反序列化;

    • 调用某个类的静态方法时;

    • 使用某个类或接口的静态字段或对该字段赋值时(final字段除外);

    • 调用Java的某些反射方法时

    • 初始化某个类的子类时

    • 在虚拟机启动时某个含有main()方法的那个启动类。

    除了以上几种情形以外,所有其它使用JAVA类型的方式都是被动使用的,他们不会导致类的初始化。

           类的初始化过程是执行类的初始化语句,包括静态变量的声明语句,以及静态代码块,静态代码块的作用即是为静态变量赋初始化值。


    0 0
    原创粉丝点击