JVM学习笔记4:类的加载、连接、初始化。

10 篇文章 0 订阅

一:加载、连接、初始化

  1. 加载:查找并加载类文件的二进制数据
          类的加载要完成:
          (1)通过类的全限定名来获取该类的二进制字节流
          (2)把二进制字节流转化为方法区的运行时数据结构   
          (3)在堆上创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
          类加载的最终产物就是在堆中的class对象;Class对象封装了类在方法区内的数据
    结构,并向外提供了访问方法区内数据结构的接口。
     
  2. 连接:就是将已经读入内存的类的二进制数据合并到JVM运行时环境中去
     (1)验证:确保被加载类的正确性
     (2)准备:为类的 静态变量 分配内存,并初始化它们
     (3)解析:把常量池中的符号引用转换成直接引用
  3. 初始化:为类的静态变量赋初始值。

二:类加载器(ClassLoader)
 

  1. 类加载器分为:

    Java虚拟机自带的加载器:
          启动类加载器(Bootstrap) c++
          扩展类加载器(Extension) java
          应用程序类加载器(System) java,也叫系统类加载器
    用户自定义的加载器:
          Java.lang.ClassLoader的子类,用户可以定制类的加载方式
     
  2. 类加载器的结构:

各个类加载器的职责:
      a.启动类加载器(Bootstrap classloader):负责将<JAVA_HOME>/lib,或者-Xbootclasspath参数指定的路径中的,且
是虚拟机识别的类库加载到内存中(按照名字识别,比如rt.jar,对于不能识别的文件不予装载)。Java程序不能直接引用启动类加载器,直接设置classLoader为null,默认就使用启动类加载器

      b.扩展类加载器(Extension classloader):负责加载<JRE_HOME>/lib/ext,或者java.ext.dirs系统变量所指定路径中
的所有类库
      c.应用程序类加载器(App calssloader):负责加载classpath路径中的所有类库。可由getSystemClassLoader()
方法获取,因此也称为系统加载器。


注: 类加载器并不需要等到某个类 “首次主动使用”的时候才加载它,Jvm规范允许类加载器
在预料到某个类将要被使用的时候就预先加载它
。如果在加载的时候.class文件缺失,会在该类首次主动使用时报告LinkageError错误,如果一直没有被使用,那就不会报错。
 

三:双亲委派模型

        JVM中的ClassLoader通常采用双亲委派模型,要求除了启动类加载器外,其余的类加载器都应该有自己的父类加载器。这里的父子关系是组合而不是继承。
    其工作过程:

  1. 一个类加载器收到类加载的请求,它自己先不去加载这个类,而是委派给父类加载器
  2. 父类加载器又可以委派给它的父类加载器,直到启动类加载器

如果父类加载器反馈它不能完成加载请求,比如在它的搜索路径下找不到这个类,那么子的类加载器才自己来加载

双亲委派说明:

  1.   双亲委派模型对于保证Java程序的稳定运作很重要
  2. 实现双亲委派的代码在java.lang.ClassLoader的loadClass()方法中,如果自定义类加载器的话,推荐覆盖实现findClass()方法
  3. 如果有一个类加载器能加载某个类,称为 定义类加载器, 所有能成功返回该类的Class的类加载器 都被称为 初始类加载器
  4. 如果没有指定父加载器,默认就是启动加载器
  5. 每个类加载器都有自己的命名空间,命名空间由该加载器及其所有父加载器所加载的类构成,不同的命名空间,可以出现 类的全路径名 相同的情况
  6. 运行时包由同一个类加载器的类构成,决定两个类是否属于同一个运行时包,不仅要看全路径名是否一样,还要看定义类加载器是否相同。只有属于同一个运行时包的类才能实现相互包内可见。

破坏双亲委派模型:

  1. 双亲模型有个问题:父加载器无法向下识别子加载器加载的资源。
  2. 为了解决这个问题,引入了线程上下文类加载器,可以通过Thread的setContextClassLoader()进行设置
  3. 另外一种典型情况就是实现热替换,比如OSGI的模块化热部署,它的类加载器就不再是严格按照双亲委派模型,很多可能就在平级的类加载器中执行了。
     

四:类的初始化

    1.初始化

          为类的静态变量赋初始值,或者说是执行类构造器<clinit>方法的过程。

        1:如果类还没有加载和连接,就先加载和连接
        2:如果类存在父类,且父类没有初始化,就先初始化父类
        3:如果类中存在初始化语句,就依次执行这些初始化语句
       4:如果是接口的话:
            初始化一个类的时候,并不会先初始化它实现的接口
            初始化一个接口时,并不会初始化它的父接口
        只有当程序首次使用接口里面的变量或者是调用接口方法的时候,才会导致接口初始化
      5:调用Classloader类的loadClass方法来装载一个类,并不会初始化这个类,不是对类的主动使用


2.类的初始化时机

        1:创建类实例
        2:访问某个类或接口的静态变量
        3:调用类的静态方法
        4:反射某个类
        5:初始化某个类的子类,而父类还没有初始化
        6:JVM启动的时候运行的主类
 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值