Java程序员的必备知识-类加载机制详解
类加载器的概念
类加载器是一个用来加载类文件的类。
Java源代码通过javac编译器编译成类文件。然后JVM来执行类文件中的字节码来执行程序。类加载器负责加载文件系统、网络或其他来源的类文件。
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类的方式实现自己的类加载器,以满足一些特殊的需求。
Java类加载器基于三个机制:委托、可见性和单一性
委托机制
是指将加载一个类的请求交给父类加载器,如果这个父类加载器不能够找到或者加载这个类,那么再加载它。
可见性的原理
是子类的加载器可以看见所有的父类加载器加载的类,而父类加载器看不到子类加载器加载的类。
单一性原理
是指仅加载一个类一次,这是由委托机制确保子类加载器不会再次加载父类加载器加载过的类。
类加载过程详解
JVM将类加载过程分为三个步骤:
装载(Load),链接(Link)和初始化(Initialize)
1) 装载:
查找并加载类的二进制数据;
2)链接:
验证:确保被加载类信息符合JVM规范、没有安全方面的问题。
准备:为类的静态变量分配内存,并将其初始化为默认值。
解析:把虚拟机常量池中的符号引用转换为直接引用。
3)初始化:
为类的静态变量赋予正确的初始值。
解析部分解释
Java 中,虚拟机会为每个加载的类维护一个常量池【不同于字符串常量池,这个常量池只是该类的字面值(例如类名、方法名)和符号引用的有序集合。 而字符串常量池,是整个JVM共享的】这些符号(如int a = 5;中的a)就是符号引用,而解析过程就是把它转换成指向堆中的对象地址的相对地址。
类的初始化步骤:
1)如果这个类还没有被加载和链接,那先进行加载和链接
2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
3)如果类中存在static标识的块,那就依次执行这些初始化语句。
类加载器的工作原理
委托机制
当一个类加载和初始化的时候,类仅在有需要加载的时候被加载。假设你有一个应用需要的类叫作Abc.class,首先加载这个类的请求由Application类加载器委托给它的父类加载器Extension类加载器,然后再委托给Bootstrap类加载器。Bootstrap类加载器会先看看rt.jar中有没有这个类,因为并没有这个类,所以这个请求由回到Extension类加载器,它会查看jre/lib/ext目录下有没有这个类,如果这个类被Extension类加载器找到了,那么它将被加载,而Application类加载器不会加载这个类;而如果这个类没有被Extension类加载器找到,那么再由Application类加载器从classpath中寻找。记住classpath定义的是类文件的加载目录,而PATH是定义的是可执行程序如javac,java等的执行路径。
可见性机制
根据可见性机制,子类加载器可以看到父类加载器加载的类,而反之则不行。所以下面的例子中,当Abc.class已经被Application类加载器加载过了,然后如果想要使用Extension类加载器加载这个类,将会抛出java.lang.ClassNotFoundException异常。
单一性机制
根据这个机制,父加载器加载过的类不能被子加载器加载第二次。虽然重写违反委托和单一性机制的类加载器是可能的,但这样做并不可取。你写自己的类加载器的时候应该严格遵守这三条机制。
java.lang.ClassLoader类介绍
java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 java.lang.Class类的一个实例。
ClassLoader提供了一系列的方法,比较重要的方法如:
自定义类加载器
public class MyClassLoader extends ClassLoader{
private String rootPath;
public MyClassLoader(String rootPath){
this.rootPath = rootPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//check if the class have been loaded
Class<?> c = findLoadedClass(name);
if(c!=null){
return c;
}
//load the class
byte[] classData = getClassData(name);
if(classData==null){
throw new ClassNotFoundException();
}
else{
c = defineClass(name,classData, 0, classData.length);
return c;
}
}
private byte[] getClassData(String className){
String path = rootPath+"/"+className.replace('.', '/')+".class";
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
is = new FileInputStream(path);
bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int temp = 0;
while((temp = is.read(buffer))!=-1){
bos.write(buffer,0,temp);
}
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
is.close();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
测试自定义的类加载器
创建一个测试类HelloWorld
package testOthers;
public class HelloWorld {
}
在D盘根目录创建一个testOthers文件夹,编译HelloWorld.java,将得到的class文件放到testOthers文件夹下。
利用如下代码进行测试
public class testMyClassLoader {
@Test
public void test() throws Exception{
MyClassLoader loader = new MyClassLoader("D:");
Class<?> c = loader.loadClass("testOthers.HelloWorld");
System.out.println(c.getClassLoader());
}
}
说明HelloWorld类是被我们的自定义类加载器MyClassLoader加载的
参考:
http://www.importnew.com/6581.html
http://www.cnblogs.com/sunniest/p/4574080.html
Java程序员的必备知识-类加载机制详解的更多相关文章
- Java入门基础学习,成为一个Java程序员的必备知识
引言 众所周知,Java是一种面向对象的编程语言.您可以在Windows操作系统上编写Java源代码,而在Linux操作系统上运行编译后的字节码,而无需修改源代码. 数据类型 Java 有 2 种数据 ...
- JVM类加载机制详解(二)类加载器与双亲委派模型
在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...
- JVM类加载机制详解
引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...
- Java程序员面试必备:Volatile全方位解析
前言 volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启vlatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~ 1.volatile的 ...
- JVM类加载机制详解,建议看这一篇就够了,深入浅出总结的十分详细!
类加载机制 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类加载的时机 遇到new(比如n ...
- Python/Java程序员面试必备常用问题解析与答案
转自AI算法联盟,理解python技术问题,以及一些常见的java面试中经常遇到的问题,这些面试问题分为四类: 是什么(what) 如何做(how) 说区别/谈优势(difference) 实践操作( ...
- JAVA类加载机制详解
“代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是变成语言发展的一大步”,这句话出自<深入理解JAVA虚拟机>一书,后面关于jvm的系列文章主要都是参考这本书. JAV ...
- Java虚拟机:类加载机制详解
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 大家知道,我们的Java程序被编译器编译成class文件,在class文件中描述的各种信息,最终都需要加载到虚拟机内存才能运行和使用,那么 ...
- JVM 类加载机制详解
如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lan ...
随机推荐
- bzoj 4542: [Hnoi2016]大数
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345 小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
- solr6.6初探之配置篇
一.solr的简介 1) solr是企业级应用的全文检索项目,它是基于Apache Lucence搜索引擎开发出来的用于搜索的应用工程 2) solr最新版本6.6 下载地址:下载地址 二 启动与配置 ...
- Python中模块之copy的功能介绍
模块之copy的功能介绍 copy主要分两种: 1.浅拷贝 2.深拷贝 赋值: 在python中赋值算特殊的拷贝,其实赋值可以理解为同一个对象有两个名字,所以当其中一个发生变化,另一个也跟着会变化. ...
- Linux 下 HTTP连接超时
将项目部署到现场环境,HTTP请求莫名奇妙的连接超时,通过抓包定位了问题,是请求的IP被禁止掉.其中用到了抓包,将记录记录于此. tcpdump host 120.197.89.51 -i any - ...
- STM32 基于定时器的PWM发生器
脉冲宽度调制(PWM),是英文"Pulse Width Modulation" 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术.简单一点,就 ...
- Error:Cannot build Artifact :war exploded because it is included into a circular depency
找到项目的目录 查找artifacts文件夹 删掉不是你项目名称的那个 问题出现的原因是你该项目名字了 造成tomcat发布两个网页 发布两个网页不是什么大问题 但是这两玩意地址一样 争夺资源啊冲突之 ...
- 分布式锁的几种使用方式(redis、zookeeper、数据库)
Q:一个业务服务器,一个数据库,操作:查询用户当前余额,扣除当前余额的3%作为手续费 synchronized lock db lock Q:两个业务服务器,一个数据库,操作:查询用户当前余额,扣除当 ...
- Mobx使用详解
Mobx是一个功能强大,上手非常容易的状态管理工具.就连redux的作者也曾经向大家推荐过它,在不少情况下你的确可以使用Mobx来替代掉redux. 本教程旨在介绍其用法及概念,并重点介绍其与Reac ...
- iOS支付宝,微信,银联支付集成封装调用(下)
一.越来越多的app增加第三方的功能,可能app有不同的页面但调用相同的支付方式,例如界面如下: 这两个页面都会使用第三方支付支付:(微信,支付宝,银联)如果在每一个页面都直接调用第三方支付的接口全部 ...
- PyCharm 2018.1破解过程
一.下载 首先从官网下载 官网,如果开了酸酸乳的话无法下载,官网会自动断开连接.所以下载时请关闭酸酸乳 二.安装 选择安装路径 选择64位,创建关联.py文件 安装完后运行Pycharm 选择不导入开 ...