Java类加载与初始化

原创 2016年05月31日 15:42:35


一、类的生命周期

1虚拟机的加载机制

  Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制。

类从被加载到虚拟机内存中开始,直到卸载出内存为止,它的整个生命周期包括

 

 

加载(即生成Class对象)->链接(验证+准备+解析)(即相当于jvm编译,会给类静态变量默认值)->初始化(使用前的准备,也是部分初始化JAVA代码开始,如构造函数,和类静态变量的初始值)->使用->卸载

其中验证、准备、解析统称为连接。加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类的加载过程必须按照这个顺序来按部就班地开始,而解析阶段则不一定,它在某些情况下可以在初始化阶段后再开始。

(2)类的加载时机

虚拟机规范中并没强行约束,这点可以交给虚拟机的的具体实现自由把握。

(3)类的初始化时机

在类初始化之前要完成类的加载和连接。类初始化的时机,首次主动使用该类时会触发初始化,

1、遇到new、getstatic、putstatic、invokestatic这四条字节码指令的时候。

     a .用new实例化一个类时

  b.读取或者设置类的静态字段时(不包括被final修饰的静态字段,因为他们已经被塞进常量池了)

  特殊情况:public static final int A = 4 + new Random().nextInt(10);//静态final   变量在编译时不定的情况

  c.以及执行静态方法的时候。

2、使用java.lang.reflect进行反射调用的时候。

3、当初始化一个类的时候,发现其父类还没有初始化,那么先去初始化它的父类。

4、当虚拟机启动的时候,需要初始化main函数所在的类。

以上情况称为称对一个类进行 “主动引用” ,除此种情况之外,均不会触发类的初始化,称为 “被动引用”

接口的加载过程与类的加载过程稍有不同。接口中不能使用static{}块。当一个接口在初始化时,并不要求其父接口全部都完成了初始化,只有真正在使用到父接口时(例如引用接口中定义的常量)才会初始化。

二、对类的“被动引用”(类不会被初始化)

1通过子类引用父类的静态字段,父类会初始化,不会导致子类的初始化


class SuperClass{
    static{
        System.out.println("父类初始化");
    }
    public static int value=100;
}
 
class SubClass extends SuperClass{
    static{
        System.out.println("子类初始化.");
    }
}
 
public class Test1{
    public static void main(String[]args){
        System.out.println(SubClass.value);
    }
    
}

输出结果为:

父类初始化

100

2通过数组引用来引用类,不会触发此类的初始化

class SuperClass{
    static{
        System.out.println("父类初始化");
    }
    public static int value=100;
}
 
public class Test1{
    public static void main(String[]args){
         SuperClass[] s = new SuperClass[5];
    }
    
}

无结果输出,就是不会对SuperClass进行初始化

(3)常量在编译阶段会被存入调用类的常量池中,本质上并没有引用到定义常量类,所以自然不会触发定义常量的类的初始化

class ConstClass
{
    static{
        System.out.println("ConstClass init.");
           }
public final static Stringvalue="hello world";
 }
 
public class Test1
{
    public static void main(String[]args){
     System.out.println(ConstClass.value);
}


输出结果:hello world

只调用ConstClass类中的常量 不会初始化ConstClass类。

三、类在JVM中的工作原理

(1)类的加载

从字节码二进制文件——.class文件将类加载到内存,从而达到类从硬盘上到内存上的一个迁移,所有的程序必须加载到内存才能工作。

将内存中的class放到运行时数据区的方法区内,之后在堆区建立一个java.lang.Class对象,用来封装方法区的数据结构。类加载的最终产物就是堆中的一个java.lang.Class对象。

(2)连接

    1)验证:出于安全性的考虑,验证内存中的字节码是否符合JVM的规范,类的结构规范、语义检查、字节码操作是否合法、这个是为了防止用户自己建立一个非法的XX.class文件就进行工作了,或者是JVM版本冲突的问题,比如在JDK1.7下面编译通过的class(其中包含注解特性的类),是不能在JDK1.4的JVM下运行的。

 

 2)准备:将类的静态变量进行分配内存空间、初始化默认值。注意是初始值。

默认的初始值类型如下:

整数类型(byte、int、short、long):0

浮点类型(float、double):0.0

字符类型(char):(‘\u0000

布尔类型(boolean):false

引用类型(类、接口、数组):null

3)解析:把类的符号引用转为直接引用

(3)类的初始化

版权声明:转载请标明出处 举报

相关文章推荐

深入Java虚拟机JVM类加载初始化学习笔记

1.       Classloader的作用,概括来说就是将编译后的class装载、加载到机器内存中,为了以后的程序的执行提供前提条件。 2.       一...

深入Java虚拟机JVM类加载初始化学习笔记

1. Classloader的作用,概括来说就是将编译后的class装载、加载到机器内存中,为了以后的程序的执行提供前提条件。 2. 一段程序引发的思考: 风中叶老师在他的视频中给了我们一...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

JAVA类加载(初始化)顺序

虚拟机在加载JAVA类的时候,按照一定的顺序进行加载,了解虚拟机的加载顺序,可以有助于我们更好的去解决问题,下面我们来通过实际的现象来观察虚拟机是如何加载并初始化类的。
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)