首先介绍下ClassLoader:

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

  1. 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
  1. 如何判断两个类相同
  • 类名称不同
这里就不需要介绍了,只要类名不同,那么类肯定也不同
  • 包名称不同
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的更多相关文章

  1. JVM学习十一:JVM之深入分析ClassLoader

    本章节准备写的是对类加载器ClassLoader的剖析,但因为前面已经对类加载器做过一些简单的分析和双亲委派机制的分析:因此本章节的侧重点在于实例演示和自定义加载器. 一.什么是ClassLoader ...

  2. 第六章 深入分析ClassLoader工作机制

    补充(非书中): Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件).类加载器负责读取Java字节代码,并转换成 java.lan ...

  3. JVM学习四:深入分析ClassLoader

    一.什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程 ...

  4. 深入分析Java Web技术内幕(修订版)

    阿里巴巴集团技术丛书 深入分析Java Web技术内幕(修订版)(阿里巴巴集团技术丛书.技术大牛范禹.玉伯.毕玄联合力荐!大型互联网公司开发应用实践!) 许令波 著   ISBN 978-7-121- ...

  5. 《深入分析Java Web技术内幕》读书笔记 - 第1章 深入Web请求过程

    第1章 深入Web请求过程 1 1.1 B/S网络架构概述 2 基于统一的应用层协议HTTP来交互数据. 1.2 如何发起一个请求 4 HTTP连接本质是建立Socket连接.请求实现方式:工具包如H ...

  6. JAVA Coder 的《深入分析Java Web 技术内幕》读书笔记

    本文基于<深入分析Java Web 技术内幕> <深入分析Java Web 技术内幕>,作者是 许令波,电子工业出版社.本文只是记录书本当中的精彩部分,作个人回顾和技术分享,请 ...

  7. Java - 收藏集 -

    Java - 收藏集 -   Java 基础思维导图,让 Java 不再难懂 - 工具资源 - 掘金思维导图的好处 最近看了一些文章的思维导图,发现思维导图真是个强大的工具.了解了思维导图的作用之后, ...

  8. <JVM中篇:字节码与类的加载篇>04-再谈类的加载器

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...

  9. 深入分析Java ClassLoader原理

    一.什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程 ...

随机推荐

  1. "undefined method `root' for nil:NilClass" error when using "pod install" 解决办法

    如果pod undate 的时候报错"undefined method `root' for nil:NilClass" error when using "pod in ...

  2. bash里面的一些符号说明

    $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行的命令的结束代码(返回值) $- 使用Set命令设定的Flag一览 $* 所有参 ...

  3. .NET 串口通信中断接收,包含0X1A(作为EOF)

    .NET串口通信中将`0X1A`当做EOF处理,.NET接收到EOF会触发一次接收中断,此时事件形参`SerialDataReceivedEventArgs`值为枚举 `Eof`,其他为`Chars` ...

  4. iar调试

    我们可以自己建立自己的工程了,但这一步只是开发中的第一小步.今天就来说说开发中举足轻重的另外一件事:调试. 其实调试本身也并不难,楼主总结,调试关键在于两件事,一是运行,二是观察,为了更好的实现这两者 ...

  5. linux------------Another app is currently holding the xtables lock. Perhaps you want to use the -w option?

    今天突然遇到这个么一个奇葩的问题,直接说问题的原因:原因是我们创建了一个计划任务,这个计划任务是一分钟执行一次,是iptables封ip的一个sh脚本.由于攻击我们的ip太多,已经达到了几千个,这个脚 ...

  6. Infinite V2 Release Note

    游戏地址 PLAY 玩法说明 - WASD 控制角色移动 - 按下J键 进入攻击模式(WASD 可以继续移动) 更新内容 - 完成角色锁定目标后边移动边攻击 开发心得 状态机的设计 最初的设计很乱, ...

  7. git 远程版本库,github提供服务原理,git自动更新发送邮件

    1.安装好Linux,安装好Git(192.168.1.239) 2.创建一个用户zph(让此用户提供git on server),密码设置为12345678 # useradd zph # pass ...

  8. win10 pro 1511 激活成功

    slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX slmgr /skms franklv.ddns.net slmgr /ato

  9. C#如何实现下载文件保存到本地上面去

    public void btnTemplate_Click(object sender, EventArgs e) { string strResult = string.Empty; string ...

  10. liunx 远程拷贝到本地

    此句在本地git bash 执行,就能拷贝远程的目录 scp -r  userName@remote:/var/www/views/log/*.* ~/Desktop