深入分析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应用程序,当程序在运行时,即会调用该程 ...
随机推荐
- OC中的那些String
/--------操作字符串--NSString(静态字符串)--------------------- NSString * a = @"a+b+c+a+b+d"; NSArra ...
- JSON例子异常分析
今天自己写了一个JSON的例子,可以一调用就出了问题,报下面这个异常: Java.lang.ClassNotFoundException: org.apache.commons.lang.except ...
- spring boot + gradle[草稿]
入门文档:https://github.com/qibaoguang/Spring-Boot-Reference-Guide 安装gradle 官方下载 https://gradle.org/grad ...
- Eclipse 的单步调试(转)
1.设置断点在程序里面放置一个断点,也就是双击需要放置断点的程序左边的栏目上.2.调试(1)点击"打开透视图"按钮,选择调试透视图,则打开调试透视图界面,然后先设置断点,按调试按钮 ...
- (地址)Spring Data Solr
http://docs.spring.io/spring-data/solr/docs/1.3.0.RELEASE/reference/html/
- ora-02292
select table_name from all_constraints where constraint_name = '约束的名称'
- Python基础学习-Python中最常见括号()、[]、{}的区别
Python中最常见括号的区别: 在Python语言中最常见的括号有三种,分别是:小括号().中括号[].花括号{}:其作用也不相同,分别用来代表不同的Python基本内置数据类型. Python中的 ...
- ibatis输入多个参数
ibatis输入多个参数 在ibatis中,会发现其输入参数只能有一个,于是当出现需要进行多个输入参数的时候,就要想点办法了,我看到的有以下两种比较好的方法能够解决这个问题1) 用String ...
- Java内存区域与内存溢出异常
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”. Java将内存控制的权利交给了Java虚拟机,一旦出现内存泄露和溢出问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会成 ...
- Intellij IDE 常用设置
1· 去除代码提示的Case sensitive(比如Sprite,键入sprite不进行任何提示) Editor->Code Completion->Case sensitive com ...