我们正常遇到这样的情况,自定义一个jar文件中包含一个class【类】文件。我们想重写这个类的话直接在工程中包名及类名一致就可行。
但是对于某些类文件例如String等一些类,在我们的工程中直接重写这些类,是调用不了的。这是什么原因呢?
这和java的类的加载机制有关,那到底java是怎么加载类文件?这个问题也是下文将阐述的问题。
首选要提到的是ClassLoader,那什么是ClassLoader?
ClassLoader负责将相应的类文件(即class文件)装载到内存中。jvm中存在多种类型的ClassLoader,主要分为4类:
(1)BootStrap[启动类加载器] 是最顶层的类加载器,它是由C++编写而成,并且已经内嵌到JVM中了,主要用来读取Java的核心类库JRE/lib/rt.jar、resources.jar、charsets.jar
等
(2)Extension ClassLoader[扩展类加载器] 是用来读取Java的扩展类库,读取JRE/lib/ext/*.jar
(3)App ClassLoader[应用类加载器] 是用来读取当前应用下CLASSPATH指定的所有jar包或目录的类文件【是用户自定义类装载器的缺省父装载器】。
(4)Custom ClassLoader[用户自定义类加载器] 是用户自定义编写的,它用来读取指定类文件
不同的类装载器,只能加载相应范围的类,哪怕是同包下的类,只要他们不属于同一类装载器,都是相互隔绝的。这对一些有安全隐患的类起到了安全隔离的作用。使它不能冒充系统类来破坏程序正常运作。
这些ClassLoader组成了jvm的ClassLoader的体系结构,如下图所示为。
从图中我们可以看出,当加载一个类的时候,是先检查是当前加载器是否已经加载该类,如已加载则返回。否则委托给它的父加载器检查是否已经加载,一直检查到BootStrap【启动类加载器】,如果还是没有发现该类被加载,则BootStrap【启动类加载器】尝试加载该类,加载成功则返回,如没有加载到则将委托还给子装载器,子类加载器继续加载,一直装载到最底层的ClassLoader【可能为App ClassLoader或者Custom ClassLoader,甚至可能为Extension ClassLoader】,如果没有装载到相应的类则抛出ClassNotFoundException。整个模型也称作双亲委派模型。
总结来说
双亲委派方式的类加载,指的是优先从顶层启动类加载器开始,自顶向下的方式加载类的模型
(参见图示)。
可能有点迷糊,我们结合一个实际的源码来说明该模型。
java中的Launcher类【在sun.misc包下】,它包含两个内部类AppClassLoader、ExtClassLoader,java通过这两个类完成对应用及扩展类文件的加载,它们继承URLClassLoader类,而URLClassLoader类继SecureClassLoader类,SecureClassLoader继承抽象类ClassLoader。
它们的类图关系如下
虽然AppClassLoader、ExtClassLoader都是继承于URLClassLoader,但是AppClassLoader的父加载器为ExtClassLoader【这里就不多讲了,可以看看源码就知道了】。而对于AppClassLoader、ExtClassLoader类中并未覆盖抽象类ClassLoader的loadClass方法。ClassLoader的loadClass的方法如下
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 首选查看类是否已经被加载
Class c = findLoadedClass(name);
//没有被加载
if (c == null) {
try {
//如果父加载器不为空,父加载器查看该类是否被加载
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果父加载器不存在调用BootStrap查看是否已被加载
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
//如果顶级装载器BootStrap未发现已加载该类,增尝试加载该类
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
而findBootstrapClass0方法如下
private Class findBootstrapClass0(String name)
throws ClassNotFoundException
{
check();
if (!checkName(name))
throw new ClassNotFoundException(name);
return findBootstrapClass(name);
}
private native Class findBootstrapClass(String name)
throws ClassNotFoundException;
它是一个本地接口的方法时C++写的。
从源码中可以看出ClassLoader总是现从下往上查看类是否已被加载,然后从上往下尝试加载类。
一般自定类加载器时loadClass是不重写,而自定义加载器重写的是findClass。从源码中我们可以看出,所有加载器的顶级加载器为BootStrap【即父加载器不存时】,同时注意到的时出于安全等因素考虑,
BootStrap不会加载
lib
存在的陌生类或jar
,
开发者通过将要加载的非
JDK
自身的类放置到此目录下期待启动类加载器加载是不可能的,其他类加载器无这样的限制
。
示例代码如下
public class classLoaderTest {
public static void main( String args[] ){
classLoaderTest t = new classLoaderTest();
System.out.print( t.getClass() );
System.out.println( t.getClass().getClassLoader() ) ;
System.out.println( t.getClass().getClassLoader().getParent() ) ;
System.out.println( t.getClass().getClassLoader().getParent().getParent() ) ;
}
}
类加载器查看如下
class classLoaderTest
sun.misc.Launcher$AppClassLoader@82ba41
sun.misc.Launcher$ExtClassLoader@923e30
null
第二行的结果表示 classLoaderTest 的类的加载器为 AppClassLoader
第三行的结果表示 AppClassLoader的父加载器为 ExtClassLoader
第四行的结果null表示 ExtClassLoader 的父加载器为 BootStrap
整个的加载流程如下自定类classLoaderTest,创建该类对象时,先是AppClassLoader检查是否已经加载该类,AppClassLoader并未加载该类,AppClassLoader委托给ExtClassLoader,而ExtClassLoader也未发现已经装载该类ExtClassLoader将委托交给BootStrap,BootStrap也未发现。这时BootStrap将尝试加载classLoaderTest,BootStrap未加载到,将委托交还给ExtClassLoader,ExtClassLoader未加载到,将委托交还给AppClassLoader,AppClassLoader加载到该类,并创建classLoaderTest。
这里我们回到问题为什么对于String等类,在应用重写,为什么不能覆盖系统的String类型。
从双亲委派模型
中我们可以知道,String对象存在rt.jar中它是由BootStrap负责加载,这样我们在应用中重写该类的时候无法加载自定义的String类【且是永远加载不到】,只能加载系统的String,这里也是java沙箱模型的第一保障。
备注:
用java –verbose:class ClassLoaderTest
可以查看具体的类运行的时候类加载过程
图及部分类容参考
http://www.cnblogs.com/ChrisWang/archive/2009/11/17/Inside-JVM-4-ClassLoader-Knowledge-Sharing.html
- 大小: 313.8 KB
- 大小: 16.4 KB
分享到:
相关推荐
深入jvm 内核-原理,诊断于优化视频教程.算是比较基础的
深入JVM内核—原理、诊断与优化视频教程 深入JVM内核—原理、诊断与优化视频教程
JAVA应用JVM原理及参数调优深入讲解视频.4 JAVA应用JVM原理及参数调优深入讲解视频.5 JAVA应用JVM原理及参数调优深入讲解视频.6 JAVA应用JVM原理及参数调优深入讲解视频.7 JAVA应用JVM原理及参数调优深入讲解视频.8 ...
深入JVM内核—原理、诊断与优化视频教程 深入JVM内核—原理、诊断与优化视频教程
深入JVM内核—原理、诊断与优化视频教程———目前,Java是更为流行的编程语言之一,它的基础平台就是JVM。除了Java,如JRuby、Scala、Clojure等语言也运.
1、java虚拟机的基本介绍。 2、字节码的执行 3、常用的jvm参数配置 4、算法和种类 5、gc参数配置 6、类加载器 7、性能监控工具 8、jvm堆栈分析
【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!
jvm的基本原理,以及体系结构,对于java的实现有所帮助
在本课程中个,将详细介绍JVM的基本原理、组成以及工作方式,并配合实际案例,介绍相关的调优技巧。 课程大纲: 第一课 初识JVM JVM分类 Java语言规范 JVM规范 介绍JVM的基本知识和发展历史,并介绍了Java语言...
深入JVM内核—原理、诊断与优化视频教程
2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...
JVM ClassLoader简析.压缩包中文档和示例代码
讲解JVM的ClassLoader子系统原理.
JVM内存结构-JVM体系结构 程序计数器 虚拟机栈 本地方法栈 堆 方法区
JVM与Java体系结构
深入解析jvm深入解析jvm深入解析jvm深入解析jvm深入解析jvm深入解析jvm
JVM体系结构与GC调优相关介绍,包含JVM体系结构、常用GC算法、内存管理、垃圾回收器、虚拟机调优、相关监控工具等
2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...
详细介绍了jvm生命周期和体系结构及垃圾回收机制