深入理解和探究Java类加载机制----

1.java.lang.ClassLoader类介绍

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 java.lang.Class类的一个实例。

ClassLoader提供了一系列的方法,比较重要的方法如:

2.JVM中类加载器的树状层次结构

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。

引导类加载器(bootstrap class loader):

它用来加载 Java 的核心库(jre/lib/rt.jar),是用原生C++代码来实现的,并不继承自java.lang.ClassLoader。

加载扩展类和应用程序类加载器,并指定他们的父类加载器,在java中获取不到。

扩展类加载器(extensions class loader):

它用来加载 Java 的扩展库(jre/ext/*.jar)。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

系统类加载器(system class loader):

它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

自定义类加载器(custom class loader):

除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

以下测试代码可以证明此层次结构:

  1. public class testClassLoader {
  2. @Test
  3. public void test(){
  4. //application class loader
  5. System.out.println(ClassLoader.getSystemClassLoader());
  6. //extensions class loader
  7. System.out.println(ClassLoader.getSystemClassLoader().getParent());
  8. //bootstrap class loader
  9. System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
  10. }
  11. }

输出为:

可以看出ClassLoader类是由AppClassLoader加载的。他的父亲是ExtClassLoader,ExtClassLoader的父亲无法获取是因为它是用C++实现的。

3.双亲委派机制

  某个特定的类加载器在接到加载类的请求时,首先将加载任务委托交给父类加载器,父类加载器又将加载任务向上委托,直到最父类加载器,如果最父类加载器可以完成类加载任务,就成功返回,如果不行就向下传递委托任务,由其子类加载器进行加载。

双亲委派机制的好处:

  保证java核心库的安全性(例如:如果用户自己写了一个java.lang.String类就会因为双亲委派机制不能被加载,不会破坏原生的String类的加载)

代理模式

  与双亲委派机制相反,代理模式是先自己尝试加载,如果无法加载则向上传递。tomcat就是代理模式。

4.自定义类加载器

  1. public class MyClassLoader extends ClassLoader{
  2.  
  3. private String rootPath;
  4.  
  5. public MyClassLoader(String rootPath){
  6. this.rootPath = rootPath;
  7. }
  8.  
  9. @Override
  10. protected Class<?> findClass(String name) throws ClassNotFoundException {
  11. //check if the class have been loaded
  12. Class<?> c = findLoadedClass(name);
  13. if(c!=null){
  14. return c;
  15. }
  16. //load the class
  17. byte[] classData = getClassData(name);
  18. if(classData==null){
  19. throw new ClassNotFoundException();
  20. }
  21. else{
  22. c = defineClass(name,classData, 0, classData.length);
  23. return c;
  24. }
  25. }
  26.  
  27. private byte[] getClassData(String className){
  28. String path = rootPath+"/"+className.replace('.', '/')+".class";
  29.  
  30. InputStream is = null;
  31. ByteArrayOutputStream bos = null;
  32. try {
  33. is = new FileInputStream(path);
  34. bos = new ByteArrayOutputStream();
  35. byte[] buffer = new byte[1024];
  36. int temp = 0;
  37. while((temp = is.read(buffer))!=-1){
  38. bos.write(buffer,0,temp);
  39. }
  40. return bos.toByteArray();
  41. } catch (Exception e) {
  42. e.printStackTrace();
  43. }finally{
  44. try {
  45. is.close();
  46. bos.close();
  47. } catch (Exception e) {
  48. e.printStackTrace();
  49. }
  50. }
  51.  
  52. return null;
  53. }
  54.  
  55. }

测试自定义的类加载器

创建一个测试类HelloWorld

  1. package testOthers;
  2.  
  3. public class HelloWorld {
  4.  
  5. }

在D盘根目录创建一个testOthers文件夹,编译HelloWorld.java,将得到的class文件放到testOthers文件夹下。

利用如下代码进行测试

  1. public class testMyClassLoader {
  2. @Test
  3. public void test() throws Exception{
  4. MyClassLoader loader = new MyClassLoader("D:");
  5. Class<?> c = loader.loadClass("testOthers.HelloWorld");
  6. System.out.println(c.getClassLoader());
  7. }
  8. }

输出:

说明HelloWorld类是被我们的自定义类加载器MyClassLoader加载的

5.类加载过程详解

JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize)

1) 装载:

  查找并加载类的二进制数据;

2)链接:

  验证:确保被加载类信息符合JVM规范、没有安全方面的问题。

  准备:为类的静态变量分配内存,并将其初始化为默认值。

  解析:把虚拟机常量池中的符号引用转换为直接引用。

3)初始化:

  为类的静态变量赋予正确的初始值。

ps:解析部分需要说明一下,Java 中,虚拟机会为每个加载的类维护一个常量池【不同于字符串常量池,这个常量池只是该类的字面值(例如类名、方法名)和符号引用的有序集合。 而字符串常量池,是整个JVM共享的】这些符号(如int a = 5;中的a)就是符号引用,而解析过程就是把它转换成指向堆中的对象地址的相对地址。

类的初始化步骤:

1)如果这个类还没有被加载和链接,那先进行加载和链接

2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)

3)如果类中存在static标识的块,那就依次执行这些初始化语句。

深入理解和探究Java类加载机制的更多相关文章

  1. 理解Java类加载机制(译文)

    理解java类加载机制 你想写类加载器?或者你遇到了ClassCastException异常,或者你遇到了奇怪的LinkageError状态约束异常.应该仔细看看java类的加载处理了. 什么是类加载 ...

  2. Java类加载机制的理解

    算上大学,尽管接触Java已经有4年时间并对基本的API算得上熟练应用,但是依旧觉得自己对于Java的特性依然是一知半解.要成为优秀的Java开发人员,需要深入了解Java平台的工作方式,其中类加载机 ...

  3. 深入理解Java类加载机制,再也不用死记硬背了

    谈谈"会"的三个层次 在<说透分布式事务>中,我举例里说明了会与会的差别.对一门语言的学习,这里谈谈我理解的"会"的三个层次: 第一层:了解这门语言 ...

  4. Java类加载机制深度分析

    转自:http://my.oschina.net/xianggao/blog/70826 参考:http://www.ibm.com/developerworks/cn/java/j-lo-class ...

  5. 两道面试题,带你解析Java类加载机制

    文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...

  6. 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)

    本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...

  7. Java类加载机制与Tomcat类加载器架构

    Java类加载机制 类加载器 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这 ...

  8. 带你解析Java类加载机制

      目录 Java类加载机制的七个阶段 加载 验证 准备(重点) 解析 初始化(重点) 使用 卸载 实战分析 方法论 树义有话说 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如 ...

  9. 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制

    你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...

随机推荐

  1. gdb ../sysdeps/i386/elf/start.S: No such file or directory

    使用 gdb 调试的时候 输入 l 之后出现下列信息 (gdb) l 1 ../sysdeps/i386/elf/start.S: No such file or directory. in ../s ...

  2. Redis源代码分析(十七)--- multi事务操作

    redis作为一非关系型数据库,居然相同拥有与RDBMS的事务操作,不免让我认为比較吃惊.在redis就专门有文件就是运行事务的相关操作的.也能够让我们领略一下.在Redis的代码中是怎样实现事务操作 ...

  3. coreseek中文搜索

    coreseek的安装和使用 准备软件包 coreseek-3.2.14.tar.gz 其他汁源 coreseek中文索引-示例文件.zip sphinx配置文件详解.txt 1.安装组件 yum - ...

  4. JAVA中equals()与==的区别详解

    在进行判断操作时,常常会用到==或者equals()进行等价判断,那么两者究竟有什么区别呢,下面整理一下个人理解. 简单介绍: ==是一种引用相等性比较符,判断引用到堆上同一个对象的两个引用是相等的. ...

  5. HTML——input

    一个简单的HTML表单,包含两个文本输出框和一个提交按钮: <form action="form_action.asp" method="get"> ...

  6. ls bash: cannot create temp file for here-document: No space left on device

    出现这种问题,一般是磁盘空间满了,或者是inode满了 使用命令: df -h查询磁盘空间 df -i 查询inode占用 Filesystem Inodes IUsed IFree IUse% Mo ...

  7. BZOJ 1529 [POI2005]ska Piggy banks:并查集

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1529 题意: Byteazar有N个小猪存钱罐. 每个存钱罐只能用钥匙打开或者砸开. By ...

  8. POJ 2976 Dropping tests:01分数规划【二分】

    题目链接:http://poj.org/problem?id=2976 题意: 共有n场考试,每场考试你得的分数为a[i],总分为b[i]. 你可以任意去掉k场考试. 问你最大的 100.0 * ( ...

  9. RQNOJ 202 奥运火炬登珠峰:01背包

    题目链接:https://www.rqnoj.cn/problem/202 题意: 登珠峰需要携带a(L)O2和t(L)N2. 有n个气缸可供选择.其中第i个气缸能装下a[i](L)O2和t[i](L ...

  10. 常见的25个python面试问答

    常见的25个python面试问答 说到好用简洁的大数据技术,除了Hadoop.R等等,Python也是其中熠熠生辉的一员,因而广受企业和商家的青睐.求职季,不少应聘者在面试相关职业时都被要求掌握Pyt ...