注:本文是个人对java虚拟机规范提到的知识的一点总结。

在Java中,类必须经过jvm使用类装载器(class loader)装载(load)之后才能使用。以主程序(Class

A)为例,当jvm调用程序的main方法时,在没有装载A.class文件时,这是不可能的事情。

装载class文件是程序执行的第一步,这跟linux下的程序执行器(execve)装载目标文件的原理是一样的,jvm充当execve的角色,读取

class文件的二进制数据,转换成jvm内部能够识别的数据结构。在这个过程中生成了一个A类关联的Class对象,该Class对象记录了A类相关的

数据。

一个类真正能使用要经过装载、连接、初始化三个步骤。连接又可以分为“验证”、”准备“、”解析

“三个步骤。总体说来,由于class文件本身记录了很多数据结构(常量池、字段信息、方法信息、引用信息等),必须要转换成内部形式,这个过程就通过装

载来实现,但是,class文件自身并没有完成链接,这跟C的目标文件有很大差别——其实也就是解析执行和编译执行的区别了,装载之后形成的内部结构还存

在很多符号引用,需要resolve引用,这就是连接过程,原理跟C的链接是一样——解决内部和外部符号引用。

在连接过程,jvm试图解析类A中出现的符号引用,比如A中定义了:

private B b=new B();

符号引用b是一个字段引用,B()是一个方法引用,并且B是定义在别的class文件的(一个类只能对应一个class文件),所以jvm试图解析

b,这个过程同时要对B进行装载(如果B并没有被当前装载器装载),装载过程一般是递归进行的,一直到达最高类层次(Object)。

关于JVM是如何装载、连接、初始化的,内容太多,详细的信息要参考Java虚拟机规范。

Java中(jdk 1.6版)有三种加载器,启动加载器→扩展加载器(ExtClassLoader)→用户程序加载器(AppClassLoader)。箭头左边的类是右边类的父类。其中启动类加载器对于我们是不可见的,用于加载java源码包的类以及jdk安装路径下的类(rt.jar

etc),而扩展类加载器用于加载ext目录下的类,用户类加载器则是加载普通的class文件。

Java给我们提供了使用自定义类装载器来装载程序的可能,这有利于程序的扩展。想想看applet

的运行,JDBC驱动的装载(典型的JDBC访问语句Class,forName()),我们在编译的时候能知道它们要装载什么类型的类吗?

以下仅通过一个示例来说明自定义类装载器的原理以及使用自定义装载实现动态类型转换:

package greeter;

public interface Greeter {

public

void sayHello();

}

我在包greeter下定义了一个接口Greeter。

然后我实现一个自定义类装载器GreeterClassLoader(如果是没有特殊目的的加载,直接继承ClassLoader就可以了,根本不用覆盖任何方法):

//注:该实现是稍微有点复杂的,JDK文档鼓励使用另一种方法,稍后提供这种方法并说明两者之间的差异。

public class GreeterClassLoader extends ClassLoader{

private String basePath;

//自定义装载作用的根目录,装载器将在这个目录下查找class文件

public

GreeterClassLoader(String path){

this.basePath=path;

}

//覆盖loadClass方法

@Override

protected

synchronized Class loadClass(String name, boolean resolve) throws

ClassNotFoundException {

Class result=null;

//看看这个类是不是已经加载过了,如果是直接返回缓存中的Class对象(放在JVM的堆中)

result=super.findLoadedClass(name);

if(result!=null){

System.out.println("class "+name+" has been loaded before.");

return result;

}

//上一步没找到,看看是不是系统类,委托给启动类装载器去装载

result=super.findSystemClass(name);

if(result!=null){

System.out.println("found by system classloader.");

return result;

}else{

System.out.println("system loader can not find it.");

}

//都找不到,直接读取源文件

byte classdata[]=null;

//do not try to load system class

if(name.startsWith("java")){

System.out.println("i encountered a system class:"+name);

throw new ClassNotFoundException();

}

classdata=this.getClassData(name);

if(classdata==null){

System.err.println("can't load "+name);

}

System.out.println(name);

//从字节码中解析出一个Class对象

result=defineClass(name, classdata, 0, classdata.length);

if(result==null){

System.out.println("Class format error.");

throw new ClassFormatError();

}

//是否需要解析

if(resolve){

this.resolveClass(result);

}

return result;

// return super.loadClass(name, resolve);

}

//从文件中读取class文件的二进制数据

private byte[] getClassData(String name){

byte[] retArr=null;

//read the byte data of the class file

name=name.replace('.', '/');

String path=this.basePath+"/"+name+".class";

System.out.println(path);

try {

FileInputStream fin = new FileInputStream(path);

BufferedInputStream bis=new BufferedInputStream(fin);

ByteArrayOutputStream baos=new ByteArrayOutputStream();

int c=bis.read();

while(c!=-1){

baos.write(c);

c=bis.read();

}

bis.close();

System.out.println("read finished.");

retArr=baos.toByteArray();

} catch (FileNotFoundException ex) {

ex.printStackTrace();

return null;

}catch(IOException ex){

ex.printStackTrace();

return null;

}

java的classloader引用实例_通过实例Java ClassLoader原理相关推荐

  1. java的3个初始化_通过实例解析Java类初始化和实例初始化

    一.背景: 存在类Father和类Son,其中类Son继承了Father类. 1.父类Father代码 2.子类Son代码 *初始化包括? 成员变量赋初值.代码块.构造器 注意方法是被调用的,有人调用 ...

  2. java虚引用作用_深入理解Java中的引用(二)——强软弱虚引用

    深入理解Java中的引用(二)--强软弱虚引用 在上一篇文章中介绍了Java的Reference类,本篇文章介绍他的四个子类:强引用.软引用.弱引用.虚引用. 强引用(StrongReference) ...

  3. java中的invoke方法_详解Java中Method的Invoke方法

    在写代码的时候,发现从父类class通过getDeclaredMethod获取的Method可以调用子类的对象,而子类改写了这个方法,从子类class通过getDeclaredMethod也能获取到M ...

  4. 深入java虚拟机 第四版_深入理解Java虚拟机-常用vm参数分析

    Java虚拟机深入理解系列全部文章更新中... https://blog.ouyangsihai.cn/shen-ru-li-jie-java-xu-ni-ji-java-nei-cun-qu-yu- ...

  5. java的四种引用类型_你知道Java的四种引用类型吗?

    以下文章来源于程序员柯南 ,作者薛勤 点击蓝字关注我们 点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大!01概述 在Java中提供了四个级别的引用: ...

  6. java带参数的构造方法_看了Java的Class的源码,我自闭了

    作者丨chenweicool 来源:https://www.cnblogs.com/chentang/p/13170081.html 1.class这个类是什么 Class的本质也是一个类,只不过它是 ...

  7. java中对象的生存期_深入理解Java虚拟机-判断对象是否存活算法与对象引用

    我们知道Java中的对象一般存放在堆中,但是总不能让这些对象一直占着内存空间,这些对象最终都会被回收并释放内存,那么我们如何判断对象已经成为垃圾呢?这篇文章会提出两种算法解决这个问题.另外,本文还要谈 ...

  8. java字符串常量存哪里_浅谈JAVA中字符串常量的储存位置

    在讲述这些之前我们需要一些预备知识: Java的内存结构我们可以通过两个方面去看待它. 从该角度看的话Java内存结构包含以下部分:该部分内容可以结合:JVM简介(更加详细深入的介绍) 1.栈区:由编 ...

  9. java 和c 多态比较_多态在 Java 和 C 编程语言中的实现比较

    2011 年 12 月 22 日发布 众所周知,多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定.C++ 和 Java 作为当前最为流行的两种 ...

  10. java 面试题合集_撩课-Java面试题合辑1-50题

    1.简述JDK.JRE.JVM? 一.JDK JDK(Java Development Kit) 是整个JAVA的核心, 包括了Java运行环境(Java Runtime Envirnment), 一 ...

最新文章

  1. C#调用非托管代码找不到入口点解决办法
  2. 多点优化损失函数地图全局描述
  3. easyui combotree的使用
  4. python代码大全下载-最全Python算法实现资源汇总!
  5. 【数字信号处理】数字信号处理简介 ( 抽样定理 | 多抽样率 )
  6. [Swift]LeetCode206. 反转链表 | Reverse Linked List
  7. Centos 6.4搭建svnadmin服务器
  8. [deviceone开发]-多种样式下拉菜单demo
  9. 《程序员修炼之道》读后感02
  10. Mongodb中 Documents文档说明
  11. uwp浏览器java源码_uwp开发:webview模拟安卓浏览器
  12. flv转mp4视频格式转码教程
  13. 2012服务器系统 3389,windows 2012r2如何修改默认的3389远程端口
  14. python写stm32_python开发stm32例程
  15. java 数字拆分_如何在java中分割数字?
  16. wish - 简单的窗口式(windowing) shell
  17. 删除域控中的一个服务器,删除 Active Directory 域服务
  18. 汇编语言的符号拓展指令CBW、CWD、CDQ、CWDE、CDQE
  19. ssm文达学院学生社团招募系统的设计与实现毕业设计源码211633
  20. 学校计算机班班通维护保养记录,班班通计算机教室管理制度..doc

热门文章

  1. tensorflow.python.framework.errors_impl.InvalidArgumentError: 2 root error(s) found.
  2. linux 脚本编程
  3. 保证计算机网络的稳定运行,厦门大学校园网管理保证网络稳定运行
  4. angular6 mysql_angular6之路由
  5. r语言ggplot2一夜多图_ggplot2简介
  6. flask与简单的form表单
  7. 12.多线程的实现方式、线程安全问题的产生与解决以及生产者与消费者问题
  8. java事件驱动模型_Spring事件驱动模型详解
  9. liunx上安装nacos
  10. 聊一聊-JAVA 泛型中的通配符 T,E,K,V,?