码迷,mamicode.com
首页 > 其他好文 > 详细

类加载

时间:2018-08-20 17:19:01      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:size   print   阶段   载器   替换   自己   系统变量   trap   常量   

java类加载机制:

前引:类加载是java程序运行的第一步,研究类加载有助于理解jvm执行过程.

? 类加载机制可以让程序能动态的控制类加载的过程,比如热部署等(在应用运行的时候升级软件,无需重新启动的方式 )

jvm类加载分为五个部分:加载,验证,准备,解析,初始化

  1. 加载:加载主要是将 .class文件的字节流读取到jvm中.在这个过程jvm需要完成三件事:

    1. 通过类的全限定名获取该类的二进制字节流;

    2. 将字节流所代表的静态存储结构转化为方法区中的运行时数据结构

    3. 在内存中创建了一个该类的java.lang.Class文件,作为这个类在方法区中数据的访问入口;


       

  2. 验证:验证是连接的第一步,目的是保证加载进来的字节流符合jvm规范;完成以下行为

    1. 文件格式验证;

    2. 元数据验证,判断是否符号java语法

    3. 字节码验证,确保逻辑正确;

    4. 符号引用验证,确保下一步能正常执行.

  3. 准备:连接阶段的第二步,为静态变量在方法区分配内存.并设置默认值.

  4. 解析:连接阶段第三步,是虚拟机将常量池中的符号引用替换为直接引用的过程.


     

  5. 初始化:类加载的最后一步.先static,再构造器。则按照static在方法内的顺序 ,先初始化父类再初始化子类.顺序为 父类静态——》子类静态——》父类非静态代码块——》父类构造方法——》子类非静态代码块——》子类构造方法。

     

    jvm初始化步骤:

    • 假如这个类还没有加载和连接,则程序会先加载并连接该类.加入该类的直接父类还没有被初始化,则先初始化其直接父类

    • 如果该类有初始化语句,则依次执行初始化语句

 

结束生命周期

•在如下几种情况下,Java虚拟机将结束生命周期

– 执行了System.exit()方法

– 程序正常执行结束

– 程序在执行过程中遇到了异常或错误而异常终止

– 由于操作系统出现错误而导致Java虚拟机进程终止

 

什么时候对类初始化:

1.遇到new,getstatic,putstatic,invokestatic这4条字节码指令时,假如类还没进行初始化,则马上对其进行初始化工作。其实就是3种情况:用new实例化一个类时、读取或者设置类的静态字段时(不包括被final修饰的静态字段,因为他们已经被塞进常量池了)、以及执行静态方法的时候。

2.使用java.lang.reflect.*的方法对类进行反射调用的时候,如果类还没有进行过初始化,马上对其进行。

3.初始化一个类的时候,如果他的父亲还没有被初始化,则先去初始化其父亲。

4.当jvm启动时,用户需要指定一个要执行的主类(包含static void main(String[] args)的那个类),则jvm会先去初始化这个类。5.Class.forName(StringclassName);来加载类的时候,也会执行初始化动作。注意:ClassLoader的loadClass(String className);方法只会加载并编译某类,并不会对其执行初始化。

类加载器

实现的功能:加载阶段获取类的二进制字节流的时候

jvm提供了三种类加载器:

  1. 启动类加载器(Bootstrap Loader):最顶层的类加载器, JAVA_HOME\lib 目录中的 rt.jar,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引用的。

  2. 扩展类加载器(Extention Loader):负责加载 JAVA_HOME\lib\ext 目录中类库. 或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器

  3. 应用程序加载器(Application Loader):也叫做系统类加载器,可以通过getSystemClassLoader()获取负责加载用户路径(classpath)上的类库。如果没有自定义类加载器,一般这个就是默认的类加载器。

类加载方式:

 

1 /*
2 *1.命令行启动程序时,由jvm初始化加载
3 *2.通过Class.forName()动态加载
4 *3.通过ClassLoader.LoadClass()动态加载
5 */

类加载器之间的层次关系:


双亲委派模式规定除了启动类加载器,其他加载器都要有父类加载器,他们的关系是组合关系


工作过程:

当一个类需要加载的时候,他自己不会加载这个类,而是向上委派请求,委托父类加载器来加载类,如果启动类加载器都不能加载这个类时,子加载器才会自己加载.


 


jvm类加载机制


  1. 全盘负责:当一个类加载器负责加载某个类的时候,这个类所依赖和引用的Class也会由该类加载器负责加载.除非显示使用另外的类加载器.

  2. 父类委托:先让父类加载该类,只有在父类不能加载该类时才会尝试 从自己的类路径加载该类

  3. 缓存机制:他会保证所有的已经加载过的Class文件会被缓存,当程序需要使用某个Class文件时就会从缓存区读取,只有缓存区没有的时候才会去读取该类对应的二进制数据,并将其转化成Class对象,并存入缓存区.所以改了class文件后就要重启jvm


双亲委派模型

双亲委派模型的代码实现集中在java.lang.ClassLoader的loadClass()方法当中。


1)首先检查类是否被加载,没有则调用父类加载器的loadClass()方法;


? 2)若父类加载器为空,则默认使用启动类加载器作为父加载器;


3)若父类加载失败,抛出ClassNotFoundException 异常后,再调用自己的findClass() 方法。


意义:1.系统类防止内存中出现多份同样的字节码


2.保证java程序安全稳定运行.


面试题:

 1 public class Test {
 2 public static void main(String[] args) {
 3     SingleTon singleTon = SingleTon.getInstance();
 4     System.out.println("count1=" + singleTon.count1);
 5     //类初始化的顺序为,先加载 static,再构造器。
 6     System.out.println("count2=" + singleTon.count2);
 7 }
 8 }
 9 
10 class SingleTon{
11     private static SingleTon singleton=new SingleTon();
12     public  static  int count1;
13     public  static int count2;
14     
15     private SingleTon(){
16         count1++;
17         count2++;
18     }
19     
20     public  static SingleTon getInstance(){
21         return singleton;
22     }
23 }

 

这是一个单例模式,通过classLoader机制避免多线程同步问题,

多个线程同时调用getInstance方法,如果不存在SingleTon实例对象,则会触发类的初始化。已经存在类初始化,则直接会去调用。

 

 

 

 

 

 

 

 

 




 

类加载

标签:size   print   阶段   载器   替换   自己   系统变量   trap   常量   

原文地址:https://www.cnblogs.com/52haiyan/p/9506527.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!