精华内容
参与话题
问答
  • 虚拟机类加载机制分析与理解

    万次阅读 2020-05-12 22:05:24
    一、类加载的时机 二、类加载的基本过程 三、类加载器与双亲委派模型的分析 四、Java模块化兼容性及模块化下的类加载器 参考文献、书籍和链接 1.周志明,深入理解Java虚拟机(第三版),机械工业出版...

    备注:相关内容后续陆续总结,最近没时间!

    一、类加载的时机

     

    二、类加载的基本过程

     

    三、类加载器与双亲委派模型的分析

     

    四、Java模块化兼容性及模块化下的类加载器

     

     

    参考文献、书籍和链接

    1.周志明,深入理解Java虚拟机(第三版),机械工业出版社,2015.10.

    2.周志明,深入理解Java虚拟机(第二版),机械工业出版社,2020.03.

    展开全文
  • 虚拟机类加载机制

    2019-03-22 15:15:41
    虚拟机类加载说白了就是将java源文件编译成的class文件加载到Java虚拟机的内存中,从而使得class文件生效。 类加载的时机 说到类加载的时机,就不得不提类加载的生命周期了,加载——验证——准备——解析——初始化...

    虚拟机类加载说白了就是将java源文件编译成的class文件加载到Java虚拟机的内存中,从而使得class文件生效。

    类加载的时机

    说到类加载的时机,就不得不提类加载的生命周期了,加载——验证——准备——解析——初始化——使用——卸载。七个阶段。书中说解析和初始化的位置可以互换,是为了支持java语言的动态绑定导致的。这点我暂时不知道,不做研究先。

    不过我们一起来探讨下类加载什么情况下会立即触发初始化呢。
    java虚拟机规范中明确规定了五种情况必须立即对类进行初始化:

    1. 遇到new、getstatic、putstatic或者invokestatic 这4条字节码指令时,如果类没有初始化,则会先触发类进行初始化。这4条指令对应最常见的java代码场景为:使用new关键字实例化对象的时候、读取或者设置一个类的静态变量(static final修饰的变量不算,因为在编译期就把该变量放入常量池中了)、调用一个类的静态方法。
    2. 使用java.lang.reflect包的方法对类进行放射调用时,如果没有初始化,会优先初始化
    3. 初始化一个类的时候,如果发现其父类还没有初始化,会优先初始化其父类
    4. 当虚拟机启动时,用户指定一个要执行的主类(main()方法的类),会优先初始化主类
    5. 如果java.lang.invoke.MethodHandle实例最后解析的结果REF_getstatic、REF_putstatic、ERF_invokestatic的方法句柄,且这个方法的句柄所对应的类没有初始化,则会优先初始化。

    以上的5中场景成为对一个类的主动引用,除此之外,所以引用类的方式都不会触发初始化,成为被动引用。

    下面看看代码:

    package chapter.Seven;
    
    class SuperClass {
    	static{
    		System.out.println("SuperClass init");
    	}
    	public static int value=123;
    	public static final String NAME="QuellanAn";
    }
    
    class SubClass extends SuperClass {
    	static{
    		System.out.println("SubClass init");
    	}
    }
    
    public class NotInitialzation {
    	public static void main(String[] args){
    		System.out.println(SubClass.value);
    	}
    }
    

    main方法中调用“SubClass.value”,value是SuperClass的静态变量。所以触发了上面第一点,所以SuperClass类会被初始化。虽然是通过SubClass调用的,但是SubClass类没有触发上面5点的任何一点,所以不会进行初始化。
    结果:

    SuperClass init
    123
    

    在看一个,就改下main()方法,其他都不不变。

    public class NotInitialzation {
    	public static void main(String[] args){
    		System.out.println(SubClass.NAME);
    	}
    }
    

    同样根据上面第一点,可以发现,NAME是静态常量,在编译期(形成class文件的时候)就已经存在常量池中了。所以SuperClass也是不会初始化的。
    结果:

    QuellanAn
    
    

    上面的例子可以很好的看出什么时候对这个类初始化了什么时候没有。有且只有上面那5中情况才会对类型进行初始化。

    另外说一点,当一个类在初始化时,要求其父类全部都已经初始化了,但是在接口初始化时,并不要求父接口全部初始化,只需要在正真用到哪个父接口就初始化那个。

    类加载的过程

    类加载的过程分为7个阶段,但重要的前面加载——验证——准备——解析——初始化前面5个。下面来依次的说明下。

    加载
    在加载阶段,虚拟机需要完成以下3件事:

    1. 通过一个类的全限定名来获取定义此类的二进制字节流。(全限定名:第一次听到这个词有点摸不着头脑,网上查了一下,才知道是有点绝对路径的意思,比如
      Java类包的定名:com.linux.struct.sort.bubblesort,从最原始最上层的地方援引到具体的对象,这就是全限定名了)
      2.将二进制字节流中所代表的的静态存储结构转化为方法区运行时结构。
      3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个的类的各个数据的访问入口。

    验证
    验证是连接阶段的第一步,验证的目的主要是为了确保class文件转换成的二进制文件流中包含的信息符合当前虚拟机的要求。并且不会危害到虚拟机的安全。
    验证阶段主要完成4个阶段的验证工作:文件格式检验、元数据校验、字节码校验、符号引用校验。

    准备
    准备阶段,是正式为类的变量分配内存空间并设置类变量初始值的阶段。这些变量所使用内存都将在方法区中分配。需要注意的是:这个阶段今次进行内存分配的进包含类变量,而不包含实例变量。实例变量将在对象实例化时随着对象一起分配到java堆中。并且这里说的初始值“通常情况”下是数据类型的零值,比如:

    public static int value=123;
    

    在value准备阶段过后的初始值为0,而不是123.value值在初始化的时候才会被赋值成123.因为把value赋值为123的putstatic指令在初始化后才执行。

    解析
    解析阶段是虚拟机将常量池内的符号引用替换成直接引用的过程。在这里插入图片描述
    初始化
    初始化阶段,执行类构造器()方法。会进行类变量的赋值和静态语句块(static{}快)的执行。


    未完待续,持续更新

    欢迎大家关注个人公众号
    分享各种学习资料,包含java,linux,大数据等。资料包含视频文档以及源码,仅供学习交流和分享,不涉及任何商业用途。同时分享本人及投递的优质技术博文。
    程序员小猪

    展开全文

空空如也

1 2 3 4 5 ... 20
收藏数 6,222
精华内容 2,488
关键字:

虚拟机类加载机制