JAVA基础_类加载器
什么是类加载器
- 类加载器是Java语言在1.0版本就引入的。最初是为了满足JavaApplet需要。现在类加载器在Web容器和OSGI中得到了广泛的应用,一般来说,Java应用的开发人员不需要直接同类加载器进行交互。Java虚拟机默认的行为就已经足够满足大多数情况的需求了。不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时候在ClassNotFoundException和NoClassDefFoundError等异常上。
- 顾名思义,类加载器是用来加载Java类到Java虚拟机中。一般来说,Java虚拟机使用Java类的方式如下:Java源程序(.java文件)在经过Java编译器编译之后会被转换成Java字节码代码(.class文件)。类加载器负责读取Java字节代码,并转换成java.lang.Class类的一个实例。每个这样的实例用来表示一个Java类。通过此实例的newInstance()方法就可以创建出该类的一个对象。实际的情况可能更复杂,比如Java字节码可能是通过工具动态生成的,也可能是通过网络下载的。基本上所有的类加载器都是java.lang.ClassLoader类的一个实例。
ClassLoader类介绍
java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java类,即Java.lang.Class类的一个实例,除此之外,ClassLoader还负责加载Java应用所需要的资源,如图像文件和配置文件。为了完成加载类这个职责,ClassLoader提供了一系列的方法。
表1:ClassLoader中与加载类相关的方法
|
|||||||||||||||
在表1中给出的方法,表示类名称的name参数的值是类的二进制名称。需要注意的是内部类的表示,如:com.exampe.Husband$Wife和com.example.OutClass$InnerClass等表示形式。
类加载器的树状组织结构
Java中的类加载器大致可以分为两类,一类是系统提供的,另外一类是Java应用开发人员自己编写的。系统提供的主要有以下三种:
- 引导类加载器(bootstrap class loader):它用来加载Java的核心库,是用原生代码来实现的,并不集成自java.lang.ClassLoader。加载核心库JAVA_HOME/jre/lib/rt.jar或sun.boot.class.path下的内容
- 扩展类加载器(extensions class loader):它用来加载Java的扩展库。Java虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载Java类。加载扩展库JAVA_HOME/jre/ext/*.jar或java.ext.dirs路径下的内容
- 系统类加载器(system class loader):他根据Java应用的类路径(CLASSPATH)来加载Java类。一般来说,Java应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader();来获取它。根据java应用的类路径(classpath,java.class.path)路径加载
除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。
图1.类加载器树状结构示意图

类加载器的树状组织结构代码清单:ClassLoaderTree .java
代码清单1:
public class ClassLoaderTree {
public static void main(String[] args) {
ClassLoader classLoader = ClassLoaderTree.class.getClassLoader();
while (classLoader != null) {
System.out.println("classLoader = " + classLoader);
// 找到其父加载器
classLoader = classLoader.getParent();
}
System.out.println("classLoader = " + classLoader);
}
}
输出结果1:
这也正好验证了类加载器的父子关系。每个Java类都维护一个指向定义它的类加载器的引用。通过getClassLoader()方法就可以获取到此引用。代码清单1通过递归调用getParent()方法来输出全部的父类加载器。在输出结果1中第一个输出的是ClassLoaderTree类的类加载器,即系统类加载器,是sun.misc.Launcher$AppClassLoader的实例,第二个输出的是扩展类加载器,是sun.misc.Launcher$ExtClassLoader的实例。在Java虚拟机中,引导类加载器是null,由启动时默认加载。
测试ExtClassLoader
- 导出至可执行jar包


然后直接Finish就可以了。
测试代码清单1的执行结果
输出结果2:

我们可以看到,少了一个系统类加载器,这是为什么呢?这就和类加载器的机制问题有关了,就是代理模式,下面就将开始类加载器的代理模式的笔记记录。
类加载器的代理模式
- 代理模式
- 交给其他加载器来加载指定的类
- 双亲委托机制
- 在某个特定的类加载器在接到加载类的请求时,自己本身先不去执行加载任务,而是将加载任务委托给其父类加载器,一次追溯,知道最高等级的父类加载器,如果父类加载器可以完成加载任务就成功返回,如果无法完成加载任务,就下放给下一级的子类,依次类推。如果所有的加载器都找不到的时候,就会抛出异常了,一般是ClassNotFoundException或NoClassDefException
- 双亲委托机制是为了保证Java核心类的类型安全,比如你重写一个Objectl类了,但是Java的类加载机制将会是你的Object类无法生效。
- 双亲委托机制是代理模式的一种
- 并非所有的类加载器都采用双亲委托机制
- tomcat服务器类加载器也使用代理模式,不同点在于它是首先尝试去加载某个类,如果找不到再代理给父类加载器。
Java虚拟机如何判定两个Java类是相同的
- 类的全限定类名是否相同
- 加载此类的类加载器是否一样
满足上述条件,才会认为类是相同的。即便是同样的字节码文件,被不同的类加载器加载,也会被认为是不同的Java类。
代码清单2:测试判定Java类是否相同的类:Sample.java
public class Sample {
private Sample instance;
public void setSample(Object instance) {
this.instance = (Sample) instance;
}
}
代码清单3:测试代码
JAVA基础_类加载器的更多相关文章
- 黑马程序员:Java基础总结----类加载器
黑马程序员:Java基础总结 类加载器 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个 ...
- Java基础之类加载器
Java类加载器是用户程序和JVM虚拟机之间的桥梁,在Java程序中起了至关重要的作用,理解它有利于我们写出更优雅的程序.本文首先介绍了Java虚拟机加载程序的过程,简述了Java类加载器的加载方式( ...
- Java基础加强-类加载器
/*类加载器*/ 把.class文件从硬盘上加载出来,将类的字节码(二进制)加载到内存中 /*类加载器及其委托机制*/ Java虚拟机中可以安装多个类加载器(可以自己编写),系统默认三个主要类加载器, ...
- java基础之—类加载器
要了解类加载器先要了解类的加载 一.类的加载(类的加载概述) 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 1.加载 就是指将clas ...
- java 基础之--类加载器的过程
先来段代码,大家瞧瞧运行pritln的结果是什么?(认真想一想哦
- Java中的类加载器
转载:http://blog.csdn.net/zhangjg_blog/article/details/16102131 从java的动态性到类加载机制 我们知道,Java是一种动态语言.那么怎 ...
- Java中的类加载器--Class loader
学习一下Java中的类加载器,这个是比较底层的东西,好好学习.理解一下. 一.类加载器的介绍 1.类加载器:就是加载类的工具,在java程序中用到一个类,java虚拟机首先要把这个类的字节码加载到内 ...
- 黑马程序员——【Java高新技术】——类加载器
---------- android培训.java培训.期待与您交流! ---------- 一.概述 (一)类加载器(class loader) 用来动态加载Java类的工具,它本身也是Java类. ...
- Java中的类加载器以及Tomcat的类加载机制
在加载阶段,虚拟机需要完成以下三件事情: 1.通过一个类的全限定名来获取其定义的二进制字节流. 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构. 3.在Java堆中生成一个代表这个类 ...
随机推荐
- Servlet - Servlet相关
1. 概念 Servlet是指任何实现了Servlet接口的类, Servlet运行于支持Java的应用服务器中, Servlet可以响应任何类型的请求, 但大多数情况下, Servlet只用来扩展基 ...
- thinkphp读取配置
无论何种配置文件,定义了配置文件之后,都统一使用系统提供的C方法(可以借助Config单词来帮助记忆)来读取已有的配置. 获取已经设置的参数值:C('参数名称') 例如, $model = C('UR ...
- 数位dp——牛客多校H
/* x[1,A] y[1,B] x^y<C 或 x&y>C 把ABC拆成二进制后按位进行数位dp dp[pos][s1][s2][f1][f2] 表示从高到低第pos位,条件一状 ...
- MetalLB自建私有Kubernetes的LoadBalancer负载均衡类型服务
简介 在私有网络上运行 Kubernetes,和御三家相比,对 LoadBalancer 类型的服务的支持应该是众多表面差异中最醒目的一个了.类型为 LoadBalancer 的服务在 Kuberne ...
- NX二次开发-UFUN读取表格注释内容UF_TABNOT_ask_cell_text
NX11+VS2013 #include <uf.h> #include <uf_ui.h> #include <uf_tabnot.h> #include < ...
- Devstack — screen 调试工具的使用
目录 目录 为什么要使用 screen 工具 启动 screen screen 的切换常用 退出和重新连接 screen Restart Openstack Services screen 指令选项总 ...
- [转]C# 将类的内容写成JSON格式的字符串
将类的内容写入到JSON格式的字符串中 本例中建立了Person类,赋值后将类中内容写入到字符串中 运行本代码需要添加引用动态库Newtonsoft.Json 程序代码: using System; ...
- 《转》python基础下
转自http://www.cnblogs.com/BeginMan/archive/2013/04/12/3016323.html 一.数字 在看<Python 核心编程>的时候,我就有点 ...
- C++之常量
常量 **作用**:用于记录程序中不可更改的数据 C++定义常量两种方式 1. **\#define** 宏常量: #define 常量名 常量值 * ==通常在文件上方定义==,表示一个常量 2. ...
- mysql保存当前时间精确到秒
用mybatis在mysql中保存字段精确到秒须要两个步骤. 1.如今mysql中将时间字段改为datetime 比如:alter table tablename add pay_date da ...
