类的加载机制以及双亲委托机制

一、类的加载

概述

1:当程序要使用某个类时,类未被加载到内存中,系统会通过三步实现类的初始化(加载-连接-初始化)

2:得到类加载器:Class#getClassLoader()

3:类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。
任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性。

1.加载

  1. 就是指将class文件读入内存(JVM方法区),并为之创建一个class对象(成员变量,成员方法,构造方法).
  2. 任何类被使用系统都会建立一个class对象.

2:连接

  1. 验证 是否有正确的内部结构,并和其他类协调一致
  2. 准备 负责为类的静态成员分配内存(静态是随着类的加载而加载),并设置默认初始化值
  3. 解析 将类的二进制数据中的符号引用替换为直接引用。

3:初始化

类加载(初始化)时机

  1. 创建类的实例
  2. 访问类的静态变量或者为静态变量赋值
  3. 调用类的静态方法
  4. 使用反射方法来强制创建某个类或接口对应的java.lang.Class对象
  5. 初始化某个类的子类
  6. 直接使用java.exe命令来运行某个主类

 类加载器的组成分类

  1. 类的加载机制:就是将class文件加载到内存中,并为之生成对应的class对象,
  2. 根类加载器>扩展类加载器>系统类加载器

根类加载器(引导类加载器) (Bootstrap classLoader)

1.负责Java核心类的加载,,作为虚拟机的一部分,比如system.string,在JDK的jre的lib目录下的rt.jar文件中
类的加载机制以及双亲委托机制_第1张图片

2:扩展类加载器(Extension classLoader)

2.负责jre的扩展目录下的jar包的加载,在JDK中jre的lib目录下的ext目录

类的加载机制以及双亲委托机制_第2张图片

3:系统类加载器 (system classLoader)
1.负责在jvm启动时加载来自Java命令的class文件,以及classpath环境变量所指定的jar包和类的路径,包含了所有jdk提供的类(rt-jar).包含开发人员写的类和第三方的jar包
2:加载classpath下的类
3:也叫Application ClassLoader ,sun.misc.Launcher$AppClassLoader, 它是System.getClassLoader()的返回值

4:类加载器的委托机制
类加载器的关系

1:系统类加载器的上层领导----------->扩展类加载器
2:扩展类加载器的上层领导----------->根类加载器

委托机制执行顺序

  1. 创建了一个对象 User user=new User();
  2. 系统类加载器发现了new User这个类
  • 系统会给自动的领导打电话,让扩展去自己的地盘去加载user类
  • 扩展会给自己的领导打电话,让根类加载器去自己的地盘去加载user类

1:根类加载器去jre下的rt.jar去寻找A类

  • 如果找到了,就进行加载,然后返回user对象的class对象给扩展类加载器,扩展类加载器将这个user.class文件返回给系统类加载器
  • 如果没找到

2:根类加载器返回给扩展一个null,扩展会在自己的地盘上寻找user类

  • 如果扩展类找到了user类,就进行加载,返回user对象的class文件给系统类加载器
  • 如果没找到

3:扩展类返回给系统类加载器一个null,系统去自己的地盘(应用程序) 加载A类

  • 如果找到了,加载,返回这个class文件,结束
  • 如果没找到,抛出classNotFoundException类为未找到异常
    类的加载机制以及双亲委托机制_第3张图片

5:双亲委派模型

概述

双亲委派模型的过程:如果一个类加载器收到了类加载的请求,首先不会自己去加载,而是把请求为派给自己的父类加载器去完成,每一个层次的类加载器都是如此。因此所有的加载请求最终都应该传送到顶层的启动类加载器中。只有当父类反馈自己无法完成这个加载请求时,子类加载器才会尝试自己完成

类的加载机制以及双亲委托机制_第4张图片

2:破坏双亲委派模型
1:三次大规模破坏该模型的情

  1. JDK 1.0->1.2 , loadClass() -> findClass()
  2. 模型缺陷:JNDI服务,SPI扩展类是由厂商自己实现,而启动类加载又不可能认识这些类。只好引入 线程上下文 类加载Thread Context ClassLoader. 该类加载器可以通过setContextClassLoader()设置,如果创建线程时未设置,将会从父线程继承。如果在应用的全局范围内都没有设置,那就默认是AppClassLoader.  有了这个,JNDI服务就可以去加载所需的SPI扩展代码,也就是父类加载器请求子类加载器去完成类加载的动作。这其实也就违背了双亲委派模型的一般性原则,但无可奈何。
  3. 程序动态性的追求: “热替换” , OSGI. JSR-291

2:开发自己的类加载器

类加载安全机制

  1. 类的加载会从根类加载器---扩展类加载器---系统类加载器一层一层的往下找,不会出现重复加载的情况
  2. 自己写一个类Java.lang.string,想去替换Java根类库

1是不会加载的,因为根类加载器中有Java.lang.string.是不会加载自己写的类的

6:类加载器与线程

  1. 每一个线程都有一个单独的类加载器和cpu寄存器(记录线程的工作状态)
  2. getContextClassLoader:获取当前线程的类加载器
    类的加载机制以及双亲委托机制_第5张图片

你可能感兴趣的:(Java)