类加载

在Java代码中,类型的加载、连接与初始化过程都是在程序运行期间完成的。

类型可以是Class,Interface, 枚举等。

Java虚拟机与程序的生命周期

在如下几种情况下,Java虚拟机将结束生命周期

1)执行了System.exit() 方法

2)程序正常执行结束

3)程序在执行过程中遇到了异常或者错误而异常终止。

4) 由于操作系统出现错误导致Java虚拟机进程终止。

1.JVM运行流程,JVM基本结构

2、类加载器双亲委派模型

3、ClassLoader源码解析

4、从源码分析实现自定义类加载器

一、JVM运行流程,JVM基本结构

JVM基本结构

类加载器,运行时数据区,执行引擎,本地接口

Class Files -> ClassLoader -> 运行时数据区 -> 执行引擎 -> 本地方法库

类的装载:

加载,连接(验证,准备,解析),初始化,使用,卸载

初始化: 执行类的构造器<clinit>,为类的静态变量赋初始值

构造器:

  1、static变量

2、staitc{} 语句

构造方法: 实例化的对象

二、类加载器双亲委派模型

1、为什么使用双亲委派模型

避免重复加载

2、JDK已有的类加载器

BootStrap ClassLoader JVM自己的类加载器,启动加载器。(C++) 主要加载rt.jar

Extension ClassLoader extends ClassLoader 扩展类加载器  加载%Java_home%lib/ext/*.jar

APP ClassLoader extends ClassLoader 应用加载器  -> Classpath

打印Class Loader

打印parent ClassLoader

null为启动类加载器。

三、ClassLoader源码解析

ClassLoader所在的路径

1、创建关于ClassLoader的Demo

  1. public class MyTest15 {
  2. public static void main(String[] args) {
  3. String[] strings = new String[2];
  4. System.out.println(strings.getClass());
  5. System.out.println(strings.getClass().getClassLoader()); //启动类加载器
  6. System.out.println("--------------------");
  7.  
  8. MyTest15[] myTest15s = new MyTest15[2];
  9. System.out.println(myTest15s.getClass().getClassLoader()); //AppClassLoader
  10.  
  11. System.out.println("--------------------");
  12.  
  13. int[] ints = new int[2];
  14. System.out.println(ints.getClass().getClassLoader()); //原生类型没有classLoader
  15.  
  16. }
  17. }

  打印结果:

  1. class [Ljava.lang.String;
  2. null
  3. --------------------
  4. sun.misc.Launcher$AppClassLoader@18b4aac2
  5. --------------------
  6. null

  

2、定位到loadClass方法

loadClass(name,false)方法

  1. protected Class<?> loadClass(String name, boolean resolve)
  2. throws ClassNotFoundException
  3. {
  4. synchronized (getClassLoadingLock(name)) {
  5. // First, check if the class has already been loaded
  6. Class c = findLoadedClass(name);
  7. if (c == null) {
  8. long t0 = System.nanoTime();
  9. try {
  10. if (parent != null) {
  11. c = parent.loadClass(name, false);
  12. } else {
  13. c = findBootstrapClassOrNull(name);
  14. }
  15. } catch (ClassNotFoundException e) {
  16. // ClassNotFoundException thrown if class not found
  17. // from the non-null parent class loader
  18. }
  19.  
  20. if (c == null) {
  21. // If still not found, then invoke findClass in order
  22. // to find the class.
  23. long t1 = System.nanoTime();
  24. c = findClass(name);
  25.  
  26. // this is the defining class loader; record the stats
  27. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  28. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  29. sun.misc.PerfCounter.getFindClasses().increment();
  30. }
  31. }
  32. if (resolve) {
  33. resolveClass(c);
  34. }
  35. return c;
  36. }
  37. }

 3、双亲委派模型

如果parent不为空,则调用parent的loadClass方法。

findClass类的目的是自定义的ClassLoader

四、自定义类加载器 extends ClassLoader  -> 完成自定义加载路径

1) 创建Demo.java文件,路径为D:/tmp/Demo.java

然后编译成class文件

javac Demo.java

2) 创建自定义类加载器

  1. package com.classloader;
  2.  
  3. import java.io.ByteArrayOutputStream;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.InputStream;
  7.  
  8. public class MyClassLoader extends ClassLoader {
  9.  
  10. private String path; //加载的路径
  11. private String name; //类加载器名称
  12.  
  13. public MyClassLoader(String name, String path){
  14. super(); //让系统类加载器成为该类的父加载器
  15. this.name = name;
  16. this.path = path;
  17. }
  18.  
  19. public MyClassLoader(ClassLoader parent, String name, String path){
  20. super(parent); //显示指定父加载器
  21. this.name = name;
  22. this.path = path;
  23. }
  24.  
  25. /**
  26. * 加载自定义的类,通过自定义的ClassLoader
  27. */
  28. @Override
  29. protected Class<?> findClass(String name) throws ClassNotFoundException {
  30. byte[] data = readClassFileToByteArray(name);
  31. return this.defineClass(name, data,0, data.length);
  32. }
  33.  
  34. /**
  35. * 获取.class文件的字节数组
  36. * com.classLoader.Demo ->
  37. * D:/temp/com/classLoader/Demo.class
  38. * @return
  39. */
  40. private byte[] readClassFileToByteArray(String name) {
  41. InputStream is = null;
  42. byte[] returnData = null;
  43.  
  44. name = name.replaceAll("\\.","/");
  45. String filePath = this.path + name + ".class";
  46. File file = new File(filePath);
  47.  
  48. ByteArrayOutputStream os = new ByteArrayOutputStream();
  49. try{
  50. is = new FileInputStream(file);
  51. int tmp = 0;
  52. while ((tmp = is.read()) != -1){
  53. os.write(tmp);
  54. }
  55. returnData = os.toByteArray();
  56. }catch (Exception e){
  57. e.printStackTrace();
  58. }finally {
  59. try {
  60. if(is != null){
  61. is.close();
  62. }
  63.  
  64. if(os != null){
  65. os.close();
  66. }
  67.  
  68. }catch (Exception e2){
  69.  
  70. }
  71. }
  72.  
  73. return returnData;
  74.  
  75. }
  76.  
  77. @Override
  78. public String toString() {
  79. return this.name;
  80. }
  81. }

  

 

 

3、使用自定义类加载器

  1. public class TestDemo {
  2.  
  3. public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  4. MyClassLoader loader = new MyClassLoader("MyClassLoadName1", "D:/tmp/");
  5. Class<?> c = loader.loadClass("Demo");
  6. c.newInstance();
  7. }
  8. }

  运行结果

Demo, MyClassLoadName1

4、测试父加载器

1)、工程里的Demo.java增加测试方法

2)、修改D盘下的Demo.java

增加包名

  1. package com.classloader;
  2.  
  3. public class Demo {
  4.  
  5. public Demo(){
  6. System.out.println("Demo, " + this.getClass().getClassLoader());
  7. }
  8.  
  9. }

  路径为,并且重新生成class文件

3) 测试文件

  1. public class TestDemo {
  2.  
  3. public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  4. MyClassLoader loader = new MyClassLoader("MyClassLoadName1", "D:/tmp/");
  5. Class<?> c = loader.loadClass("com.classloader.Demo");
  6. c.newInstance();
  7. }
  8. }

  运行结果:

说明使用的是父类加载器,加载的是工程里的那个Demo.class文件。

修改如下:

传入null,说明父加载器为启动加载器。

显示结果:

Demo, MyClassLoadNameChild

JVM 类加载器ClassLoader源码学习笔记的更多相关文章

  1. 第五章 类加载器ClassLoader源码解析

    说明:了解ClassLoader前,先了解 第四章 类加载机制 1.ClassLoader作用 类加载流程的"加载"阶段是由类加载器完成的. 2.类加载器结构 结构:Bootstr ...

  2. 类加载器ClassLoader源码解析

    1.ClassLoader作用 类加载流程的"加载"阶段是由类加载器完成的. 2.类加载器结构 结构:BootstrapClassLoader(祖父)-->ExtClassL ...

  3. JUC源码学习笔记4——原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法

    JUC源码学习笔记4--原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法 volatile的原理和内存屏障参考<Java并发编程的艺术> 原子类源码基于JDK8 ...

  4. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  5. Qt Creator 源码学习笔记04,多插件实现原理分析

    阅读本文大概需要 8 分钟 插件听上去很高大上,实际上就是一个个动态库,动态库在不同平台下后缀名不一样,比如在 Windows下以.dll结尾,Linux 下以.so结尾 开发插件其实就是开发一个动态 ...

  6. async-validator 源码学习笔记(五):Schema

    系列文章: 1.async-validator 源码学习(一):文档翻译 2.async-validator 源码学习笔记(二):目录结构 3.async-validator 源码学习笔记(三):ru ...

  7. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  8. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  9. Underscore.js 源码学习笔记(下)

    上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...

随机推荐

  1. Vue.js源码中大量采用的ES6新特性介绍:模块、let、const

    1 关于ES6      ECMAScript6(以下简称ES6)是JavaScript语言的最新一代标准,发布于2015年6月,因为ECMA委员会决定从ES6起每年更新一次标准,因此ES6被改名为E ...

  2. 数据库类型对应Java语言类型表

    下表列出了基本 SQL Server.JDBC 和 Java 编程语言数据类型之间的默认映射: SQL Server 类型 JDBC 类型 (java.sql.Types) Java 语言类型 big ...

  3. 2013.6.22 - OpenNE第二天

    果然看中文材料就比较顺利,才半个小时就看完了一篇非常简单的综述<命名实体识别研究进展综述>(孙镇.王惠临).这个是2010年的文章,其实就是一个 科普文章,简述了国内外NER这块的历史如何 ...

  4. 登录-redis

    session的问题 目前session直接是js变量,放在nodejs进程内存中 1.进程内存有限,访问量过大,内存暴增怎么办? 2.正式线上运行是多进程,进程之间内存无法共享 为何session适 ...

  5. mysql安装好需要启动和停止服务

    启动mysql: mysql.server start 停止服务:mysql.server stop

  6. 小程序缓存Storage的基本用法

    wx.setStorageSync('key', 'hello world') 然后在小程序调试器里面的Storage里面就能看到设置的值.在小程序里面,如果用户不主动清除缓存,这个缓存是一直在的. ...

  7. 局部敏感哈希算法(Locality Sensitive Hashing)

    from:https://www.cnblogs.com/maybe2030/p/4953039.html 阅读目录 1. 基本思想 2. 局部敏感哈希LSH 3. 文档相似度计算 局部敏感哈希(Lo ...

  8. Kotlin星投影与泛型约束详解

    星投影(star projection): 继续来学习Kotlin泛型相关的东东,星投影(star projection),这是个啥东东呢?下面先来说一下概念: 1.对于Star<out T&g ...

  9. 洛谷 P2401 不等数列 题解

    每日一题 day25 打卡 Analysis dp[i][j]=dp[i-1][j-1]*(i-j)+dp[i-1][j]*(j+1); 其中i和j是表示前i个数中有j个小于号,j<=i-1 要 ...

  10. TPCH 22条SQL语句分析

    使用TPC-H进行性能测试,需要有很多工作配合才能获得较高性能,如建立索引,表数据的合理分布(使用表空间和聚簇技术)等.本文从查询优化技术的角度,对TPC-H的22条查询语句和主流数据库执行每条语句对 ...