JVM类加载器

##类加载器 类加载器作用于类加载过程中加载环节,是将.class文件加载进入内存时所使用到的技术,下文介绍类加载器 

     ##类加载的机制 

      加载:1.取得类的二进制流,2.转为方法区数据结构,3.在Java堆中生成对应java.lang.Class对象 

      链接 1.验证:保证Class流的格式是正确的 一、文件格式的验证(是否以0xCAFEBABE开头)。二、元数据验证(是否 有父类,继承了final类?非抽象类实现了所有的抽象方法。三、字节码验证 (很复杂)。四、符号引用验证) 

  1. 准备:分配内存,并为类的静态变量设置默认初始值 (方法区中),注意:此时对象并未创建,且常量在该阶段 就完成赋值 

3.解析:符号引用替换为直接引用 1)、符号引用:Java中,一个java类将会编译成一个class文件。在编译时, java类并不知道所引用的类的实际地址,因此只能使用符号引用来代替。比如org.simple.People类引用了 org.simple.Language类,在编译时People类并不知道Language类的实际内存地址2)、直接引用:、实际 内存地址,指向了实际的内存如果有了直接引用,那引用的目标必定已经被加载入内存中了。 

初始化:执行类构造器 1、static变量 赋值语句 2、static{}语句 3、子类的调用前保证父类的被调用 4、是线程安全的

 ##判断什么时候需要进行初始化 有6种情况称之为主动使用,在主动使用的情况下,该类会被类加载器加入内存, 且进行初始化,除此以外都不会加载该类、创建类的实例 

– 访问某个类或接口的静态变量,或者对该静态 变量赋值 

– 调用类的静态方法 

– 反射(如Class.forName(“java.lang.String”) 

– 初始化一个类的子类 

– Java虚拟机启动时被标明为启动类的类(Java Test) 

##类加载器的介绍 BootStrap ClassLoader (启动ClassLoader,根类加载器) rt.jar java.lang Extension ClassLoader (扩展ClassLoader) ext包下的 内容 App ClassLoader (应用ClassLoader/系统ClassLoader) 开 发人员自己写的 Custom ClassLoader(自定义ClassLoader) 根类加载器并不是由Java代码写的,且sun公司也不提 供对根类加载器的任何操作,想要拿到这个一个加载器,返回的结果是null 除了根类加载器以外,其他的加载器都 是java代码写的,上一层是下一层的父容器 ,值得注意的是他们并不是一个继承关系,而是逻辑上的父子关系 启 动类加载器,由C++实现,没有父类。 拓展类加载器(ExtClassLoader),由Java语言实现,父类加载器为BootStrap 系统类加载器(AppClassLoader),由Java语言实现,父类加载器为ExtClassLoader 自定义类加载器,父类加载器 肯定为AppClassLoader。 

##双亲委派模式工作原理 原理:如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求 委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到 达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任 务,子加载器才会尝试自己去加载,这就是双亲委派模式, 

双亲机制的目的:防止对象的重复加载! 举例:每个类加载器都能加载对应不同文件的类,那么假如我们自己定义 了一个java.lang.Object包下的内容,那么首先这个类是我们自己写的,也存在我们的classpath路径下,会被app加 载器加载,但同样,JDK中的Object也会被加载,产生多个对象,造成混乱! 

接下来我们再来类加载器代码中怎么保证父类双亲委托机制 该方法加载指定名称(包括包名)的二进制类型,该方 法在JDK1.2之后不再建议用户重写但用户可以直接调用该方法,loadClass()方法是ClassLoader类自己实现的,该 方法中的逻辑就是双亲委派模式的实现 

```java protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { 

// 先从缓存查找该class对象, 找到就不用重新加载 

Class c = findLoadedClass(name); 

if (c == null) { 

long t0 = System.nanoTime(); 

try { 

// 如果找不到,则委托给父类加载器去加载 

if (parent != null) { 

c = parent.loadClass(name, false); 

} else { 

//如果没 有父类,则委托给启动加载器去加载 

c = findBootstrapClassOrNull(name); } } 

catch (ClassNotFoundException e) { } 

if (c == null) { long t1 = System.nanoTime(); 

// 如果都没有找到,则通过自定义实现的findClass去查找并加载 

           c = findClass(name); 

            sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } 

``` 而对应findClass是在CLassloader接口中用于给子类重写使用的源码中只是一个空实现 

```java protected Class findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }` ``` 

##双亲委派模型的破坏者 介绍:打破双亲委派机制有3种方式,双亲委 派的核心是由下向上委托,而所谓的打破,指的是在加载资源时需要从上往下寻找 1.类加载器是Jdk1.0以前出现的,而双亲委派原则是Jdk1.2出现的,为了兼容以前的程序 2.热部署,热部署会使得每个点都具有一个类加载器,从而使得类加载器形成一个网状结构,从而打破了双亲 委派机制 3.Java提供了很多服务提供者接口(Service Provider Interface,SPI)这些接口允许第三方为它们提供实 现,如常见的 SPI 有 JDBC、JNDI等,这些 SPI 的接口属于 Java 核心库,一般存在rt.jar包中,由Bootstrap类 加载器加载,而 SPI 的第三方实现代码则是作为Java应用所依赖的 jar 包被存放在classpath路径下,由于SPI 接口中的代码经常需要加载具体的第三方实现类并调用其相关方法,但SPI的核心接口类是由引导类加载器来 加载的,而Bootstrap类加载器无法直接加载SPI的实现类,同时由于双亲委派模式的存在,Bootstrap类加载 器也无法反向委托AppClassLoader加载器SPI的实现类。在这种情况下,我们就需要一种特殊的类加载器来加 载第三方的类库,使用线程类上下文类加载器其核心原理就是: 线程类上下文类加载器是调用 java.lang.Thread 包下的getContextClassLoader 和setContextClassLoader-->如果没有设置的话默认就是 appClassLoader

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值