深入分析ClassLoader
首先介绍下ClassLoader:
ClassLoader顾名思义就是类加载器,负责将Class加载到JVM中,事实上ClassLoader除了能将Class加载到JVM中之外,还有一个重要的作用就是审查每个类应该有谁加载,ClassLoader是一个父优先的等级加载机制。ClassLoader除了上述两个作用外还有一个任务就是将Class字节码重新解析成JVM统一要求的对象格式-----------由此本文可以划分成三点
ClassLoader类结构分析
1. ClassLoader常用的方法

1,defineClass():用来将byte字节流解析成JVM能够识别的Class对象
2,findClass():用来子类扩展的方法,目的是为了寻找类
3,loadClass():加载类,这里就可以动态加载了,程序运行的时候加载
4,resolveClass():这个方法是用来链接这个类
JDK给我们提供了可以扩展的,也就是我们可以自定义的类加载器URLCLassLoader,比较方便2. ClassLoader的等级加载机制

1,BootStrap ClassLoader:
这是一个引导类加载器,首先声明一下虽说在类的结构中可以看到这个类,但是这个类只有Class文件,据了解这个类是通过C++编写的,这也就是ExtClassLoader的父类为空的原因。引导类负责加载JDK的jre下的类库,例如rt.jar
2,ExtClassLoader:
这是一个扩展类加载器,加载bin目录下的ext文件夹下的jar包,不多说
3,AppClassLoader:
这个类加载器就是我们自定义的类,例如我们的这个方法getSystemClassLoader()作为父加载器,这个加载器也就是AppClassLoader。
4,加载类过程总结:
看了很多资料都是什么双亲委托加载机制,具体我也不是很清楚,可以我太low,但是我个人的理解就是,当加载一个类的时候:首先检查这个类是否已经被自己加载过,如果已经加载过,就拒绝本次加载,如果没有加载过,就会抛给他的父类,然后父类在检查是否加载,然后在抛给父类,直到全部检查完都没有发现这个类被加载,那么就有意思了,因为每一个类加载器都有自己的加载范围,然后开始判断,父类不加载类,那么就开始向下寻找这个类的加载器,然后这个类被加载,也就是先向上检查是否加载,其次向下看是否可以加载!--------------------这里有一个讲解,来帮助理解,如果我们自己写了一个java.lang.String,那么类加载器就先去加载jdk下的java.lang.String.遇到我们自己定义的类就不会加载了,这也就是java.lang.Object首先被加载,父类加载会防止我们破坏干扰jre的正常运行,导致类结构被破坏
这里是类关系的代码
public class ClassA {
}
public class ClassB {
}
public class ClassTest {
public static void main(String[] args) {
//演示 我們的類加載器
System.out.println("ClassTest-------------ClassLoader:"+ClassTest.class.getClassLoader());
System.out.println("ClassTest.Parent------ClassLoader:"+ClassTest.class.getClassLoader().getParent());
System.out.println("ClassTest.GrandFather-ClassLoader:"+ClassTest.class.getClassLoader().getParent().getParent());
//用户自定义的类加载 都是通过AppClassLoader加载
System.out.println(ClassA.class.getClassLoader());
System.out.println(ClassB.class.getClassLoader());
//结论就是----------当两个类名称不同,那么这两个类就不相同
}
}
打印结果
ClassTest-------------ClassLoader:sun.misc.Launcher$AppClassLoader@73d16e93
ClassTest.Parent------ClassLoader:sun.misc.Launcher$ExtClassLoader@15db9742
ClassTest.GrandFather-ClassLoader:null
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$AppClassLoader@73d16e93
- 如何判断两个类相同
- 类名称不同
这里就不需要介绍了,只要类名不同,那么类肯定也不同
- 包名称不同
package me.classloader.classpackage;
public class String {
}
package me.classloader.classpackage;
import org.junit.Test;
public class ClassTest {
@Test
public void classTest(){
//这里是 BootStrap ClassLoader-------因此返回Null
System.out.println(java.lang.String.class+"------classLoader:"+java.lang.String.class.getClassLoader());
//这里 我们自定义的类 被AppClassLoader 加载
System.out.println(String.class+"--------ClassLoader:"+String.class.getClassLoader());
//很明显这两个类是不同的
}
}
这里可以得到我们的包名可以引起 两个类不是同一个类,并且,这里JVM就近调用一个类先调用的同包下的类
- 类加载器不同
package me.classloader.classloader;
public class Demo {
private Demo demo;
public void setDemo(Demo demo) {
this.demo = demo;
}
}
package me.classloader.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//自己写的ClassLoader
public class MyClassLoader extends ClassLoader {
private String classPath;// 类路径
public MyClassLoader() {
}
public MyClassLoader(String classPath) {
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classDate = getDate(name);
if (classDate == null) {
throw new ClassNotFoundException();
} else {
return defineClass(name, classDate, 0, classDate.length);
}
}
// 将 class 文件转化成字节流
//className是类名称---权限定名
private byte[] getDate(String className) {
// 将XX.XX.java --------->XX/XX/java.class
String path = classPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class";
try {
InputStream is = new FileInputStream(path);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int num = 0;
while ((num = is.read(buffer)) != -1) {
stream.write(buffer, 0, num);
}
return stream.toByteArray();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
package me.classloader.classloader;
public class ClassTest {
public static void main(String[] args) throws Exception{
String classPath ="E:\\javaprogram\\java-exercise\\classload\\bin";
String className = "me.classloader.classloader.Demo";
ClassLoader appClassLoader = ClassTest.class.getClassLoader();
MyClassLoader myClassLoader = new MyClassLoader(classPath);
Class demo1 = appClassLoader.loadClass(className);
System.out.println(demo1.newInstance().getClass().getClassLoader());
Class demo2 = myClassLoader.findClass(className);
System.out.println(demo2.newInstance().getClass().getClassLoader());
System.out.println(demo1.newInstance().getClass() ==demo2.newInstance().getClass());
}
}
测试结果
sun.misc.Launcher$AppClassLoader@73d16e93
me.classloader.classloader.MyClassLoader@6d06d69c
false
通过上面的代码,我们也知道了如何写一个类加载器,其实查看findClass()是ClassLoader提供的一个模板方法!
总结:类加载器也是一个比较深的东西,例如servlet中jsp使用了热部署!其实就是类加载器的应用,可能动态代理也用到了类加载器,因为实际工作加载的是我们代理的类
深入分析ClassLoader的更多相关文章
- JVM学习十一:JVM之深入分析ClassLoader
本章节准备写的是对类加载器ClassLoader的剖析,但因为前面已经对类加载器做过一些简单的分析和双亲委派机制的分析:因此本章节的侧重点在于实例演示和自定义加载器. 一.什么是ClassLoader ...
- 第六章 深入分析ClassLoader工作机制
补充(非书中): Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件).类加载器负责读取Java字节代码,并转换成 java.lan ...
- JVM学习四:深入分析ClassLoader
一.什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程 ...
- 深入分析Java Web技术内幕(修订版)
阿里巴巴集团技术丛书 深入分析Java Web技术内幕(修订版)(阿里巴巴集团技术丛书.技术大牛范禹.玉伯.毕玄联合力荐!大型互联网公司开发应用实践!) 许令波 著 ISBN 978-7-121- ...
- 《深入分析Java Web技术内幕》读书笔记 - 第1章 深入Web请求过程
第1章 深入Web请求过程 1 1.1 B/S网络架构概述 2 基于统一的应用层协议HTTP来交互数据. 1.2 如何发起一个请求 4 HTTP连接本质是建立Socket连接.请求实现方式:工具包如H ...
- JAVA Coder 的《深入分析Java Web 技术内幕》读书笔记
本文基于<深入分析Java Web 技术内幕> <深入分析Java Web 技术内幕>,作者是 许令波,电子工业出版社.本文只是记录书本当中的精彩部分,作个人回顾和技术分享,请 ...
- Java - 收藏集 -
Java - 收藏集 - Java 基础思维导图,让 Java 不再难懂 - 工具资源 - 掘金思维导图的好处 最近看了一些文章的思维导图,发现思维导图真是个强大的工具.了解了思维导图的作用之后, ...
- <JVM中篇:字节码与类的加载篇>04-再谈类的加载器
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- 深入分析Java ClassLoader原理
一.什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程 ...
随机推荐
- xcode国际化工具genstrings体验总结
genstrings是苹果推出的一个用于自动从代码的nslocalizedstring等提取生成国际化字符串的工具: xcode的国际化文件方案一直以来都不太智能,我记得很久以前.strings文件库 ...
- App Extension
一.扩展概述 扩展(Extension)是iOS 8中引入的一个非常重要的新特性.扩展让app之间的数据交互成为可能.用户可以在app中使用其他应用提供的功能,而无需离开当前的应用. 在iOS 8系统 ...
- Android下百度地图开发(一):基础地图展示
最终效果如: 这个需要详细说下,准备工作较为繁琐. 第一步:去百度申请一个开发者账号,新建一个android应用,会让你输入开发者SHA1,目前我只拿到开发版SHA1,发布版那里也填的是这个. 获取方 ...
- java 使用map返回多个对象组装
Object json=JSONObject.fromObject("{}"); List<Object> list = new ArrayList<Object ...
- Altium Designer 生成Gerber文件
- iOS蓝牙开发CoreBluetooth快速入门
在iOS开发中,实现蓝牙通信有两种方式,一种是使用传统的GameKit.framework,另一种就是使用在iOS 5中加入的CoreBluetooth.framework. 利用CoreBlueto ...
- C++学习笔记 宏 const 内联 枚举
宏, const变量, 内联, 枚举 宏 宏定义: 宏即宏替换,在C语言源程序中允许用一个标识符来表示一个字符串,称为宏,关键字 define,在所有使用到宏的地方都只是直接的替换而不做任何类型检查 ...
- varnish4.1 配置文件default.vcl
varnish4.1 配置文件default.vcl # This .x VCL file vcl 4.0; backend default { .host = "127.0.0.1&quo ...
- iOS10 - 访问系统通讯录新方法
所需框架 #import <ContactsUI/ContactsUI.h> 遵循代理 CNContactPickerDelegate 调用通讯录 如果在iOS10的机器上调用以前的ABP ...
- git pull 冲突解决
这个意思是说更新下来的内容和本地修改的内容有冲突,先提交你的改变或者先将本地修改暂时存储起来. 处理的方式非常简单,主要是使用git stash命令进行处理,分成以下几个步骤进行处理. 1.先将本地修 ...