类加载器以及双亲委派模式

类加载器以及双亲委派模式

类加载器ClassLoader

类的加载流程的"加载"阶段是由类加载器完成的。

 

JVM什么时候加载.class文件

 当执行new操作时候

 当执行Class.forName(“包路径 + 类名”)

 

分类

启动类加载器(Bootstrap ClassLoader)

C++编写;

为ExtClassLoader的父类,但是通过ExtClassLoader的getParent()获取到的是null;

主要加载:E:\Java\jdk1.6\jre\lib\*.jar(最重要的就是:rt.jar);

扩展类加载器(Extendsion ClassLoader)

java编写,位于sun.misc包下,该包在你导入源代码的时候是没有的,需要重新去下;

主要加载:E:\Java\jdk1.6\jre\lib\ext\*.jar(eg.dnsns.jar);

应用类加载器(Application ClassLoader)

java编写,位于sun.misc包下;系统默认的类加载器;

主要加载:负责加载用户类路径(CLASSPATH)下的类

自定义加载器

自己编写的类加载器,需要继承ClassLoader类或URLClassLoader,并至少重写其中的findClass(String name)方法,若想打破双亲委托机制,需要重写loadClass方法;

主要加载:自己指定路径的class文件。

 

Java类装载机制:全盘负责双亲委托机制

全盘负责:

当一个ClassLoder装载一个类时,该类所依赖及引用的类也由这个ClassLoder载入。

假设ClassLoaderA要加载class B,但是B引用了class C,那么ClassLoaderA先要加载C,再加载B。

双亲委派模式

含义:

类加载器收到类加载的请求时,会将该请求委托派给父类加载器去完成,蹭蹭递进,所有的请求被传递值顶层的启动类加载器中。只有父类加载器无法加载时,才会交给自类加载器去尝试加载。

流程

类的加载过程只有向上的双亲委托,没有向下的查询和加载。

假设A加载成功了,那么该类就会缓存在当前的类加载器实例对象C中,key是(A,C)(其中A是类的全类名,C是加载A的类加载器对象实例),value是对应的java.lang.Class对象

进行缓存的目的是为了同一个类不被加载两次

为什么要使用这种双亲委托模式呢?

假设自己编写了一个java.lang.Object类,编译后置于类路径下,此时在系统中就有两个Object类,一个是rt.jar的,一个是类路径下的,在类加载的过程中,当要按照全类名去加载Object类时,根据双亲委托,boot会加载rt.jar下的Object类,这是方法结束,即类路径下的Object类就没有加载了。这样保证了系统中类不混乱。

 

类的装载方式

由 new 关键字创建一个类的实例

程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。如:Dog dog = new Dog();

静态加载,使用的是当前类的加载器

通过反射加载类型,并创建对象实例

如:Class clazz = Class.forName(“Dog”); Object dog =clazz.newInstance();

动态加载,使用的是当前类的加载器

调用某个 ClassLoader 实例的 loadClass() 方法

如:Class clazz = cl.loadClass(“Dog”); Object dog =clazz.newInstance();

动态加载,使用的是用户自定义的类加载器对象。

 

Class

static Class<?>  :  Class.forName("com.wang.HelloWorld")

静态方法。

根据传入的类的全限定名,返回一个Class对象。

在将Class文件加载到内存的同时,会执行类的初始化,即HelloWorld的static{} 以及静态变量初始化.

 ClassLoader  :   getClassLoader()

返回该类的类加载器。

Bootstrap Loader是用C++语言写的,故java程序代码打印输出为null。

 

ClassLoader源码分析

c.loadClass("com.wang.HelloWorld")

非静态方法。

根据传入的类的全限定名,返回一个Class对象。

将Class文件加载到内存时,并不会执行类的初始化,在new时执行初始化。

 

findLoadedClass(name):

获取已经缓存的Class对象,不存在则返回null;

findBootstrapClassOrNull(name):

当父加载器为BootStrap ClassLoader时,查找jdk1.6\jre\lib\*.jar下是否存在Class对象

findClass(name):

自定义类加载器时需重写该方法。1.通过输入流读取Class文件为字符数组;2.引用defineClass方法,将二进制字节流转换为了java.lang.Class对象。

ClassNotFoundException

 

自定义类加载器的实现

目的:用于加载特定目录下的Class文件。

实现逻辑:

继承ClassLoader,重写Class<?> findClass(String name)方法(通过输入流读取class文件为字节数组,调用defineClass方法转化为Class<?>的实例)。

调用:

通过调用对应的loadClass(className),来加载对应的类。

注意:注意自定义的类加载器的父类加载器是否是系统默认的类加载器,即双亲委派模型。

 

使用场景:

核心类库对字节码文件加密,需自定义findClass解密;

资源隔离,如tomcat以及下的多个webApp应用

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值