- 浏览: 420842 次
- 性别:
- 来自: 济南
文章分类
最新评论
-
pmh905001:
写的很详尽,感谢!
解析jvm.dll和java.exe -
Bll:
插得真深啊,我的是(eclipse_j2ee_juno):F: ...
在eclipse里jsp编译后的java和class文件的位置 -
heming_way:
谢谢,对我很有用,解答了我对多值依赖的疑问
关于多值依赖--范式! -
JavaStudy2011:
java语言解析xml文件 -
vrussell:
Thanks man, it helps me a lot!
获得IEditorPart和IDocument
类装载器是Java程序运行时不可缺少的一部分,它的任务是把由Java源程序编译成的class文件读入到内存中,确切的说是装入到JVM的内存中,应为JVM是一台抽象的计算机,它有着自己的CPU,内存等. 在class文件中包含了一个类的各种信息,当执行java XXX命令运行一个以XXX为初始类的Java程序时,类装载器会把XXX的class文件装载到内存,然后根据该class文件中包含的信息在方法区中生成一个JVM的内部数据结构,该数据结构里的内容是XXX类的类型信息,大家知道每个类都会对应一个Class对象,该对象就是JVM根据这个类型信息在堆区中创建的,这个对象含有一个指向方法区中对应类型信息的指针,除此之外,该Class对象还包含一个指向类装载器的指针,根据这个Class对象就可以创建对象,可以访问装载本类的类装载器,还可以访问方法区中的数据(Java反射机制就是这样实现的).
一.Java中有四中类装载器:启动类装载器,扩展类装载器,类路径类装载器,自定义类装载器.下面将围绕着这三s种类装载器做一个详细的描述:
1.启动类装载器:也叫引导类装装载器,它是JVM内部的类装载器,用C++编写,作用是装载Java核心类库中的类,比如说一个Java虚拟机目录为D:\JDK1.5,则启动类装载器负责装载D:\JDK1.5\jre\lib\rt.jar,rt.jar为Java核心类库,比如我们常用到的java.lang包中的System类,由于启动类装载器是供JVM使用的,Java程序并不能直接使用,下面举个例子来说明:
class Test {
public static void main(String[] args) {
System.out.println(System.class.getClassLoader());
}
}
上述程序打印出装载System类的类装载器,而打印出的却是null,说明了启动类装载器不能直接调用.
2.扩展类装载器:它负责装载Java的扩展类,比如说一个Java虚拟机目录为D:\JDK1.5,则它负责加载D:\JDK1.5\jre\lib\ext下的类库中的类,假如ext目录下有个jar包,包里有个Test类,包名为org.test,则可以用org.test.Test.class.getClassLoader()方法打印出该类加载器,可以看到结果为sun.misc.Launcher$ExtClassLoader,说明Test类由扩展类装载器装载,可以根据需要把自己写的类打成jar包放到ext目录下.
3.类路径类装载器:也可以叫系统类装载器,它负责装载当前classpath下的类,也就是当我们要运行一个Java程序时初始类的包所在的目录,比如在D:\test下有个Test.class,它是程序的初始类,当执行Java Test命令时D:\test就是classpath. 一般classpath下的类都是我们自定义的类,同样Test.getClassLoader()方法得到的结果是sun.misc.Launcher$AppClassLoader,说明Test类由类路径类装载器加载.
4.自定义类装载器:Java允许用户可以自定义类装载器来装载类,下面举个例子,使用URLClassLoader,从网络上装载一个类:
首先自己创建一个Java Web工程,Web根目录为WebRoot(WEB-INF的上一级目录),在WebRoot下创建一个包名为org.test.TestImpl的类,即TestImpl.class文件在WebRoot目录的org/test目录下,我们在定义一个接口,名为Test,接口有个test()方法,让Test实现它的test()方法,为了测试方便,把Test接口放在classes目录下:
Test类代码如下:
package org.test.TestImpl;
public class TestImpl implements Test{
public void add(){
System.out.println("TestImpl#add()");
}
}
在classes目录下写个测试类TestLoader :
public class TestLoader {
public static void main(String[] args) throws Exception{
URL url = new URL("http://localhost:8080/WebRoot/");
URLClassLoader loader = new URLClassLoader(new URL[]{url});
Class clazz = loader.loadClass("org.test.TestImpl");
Test t = (Test) clazz.newInstance();
t.add();
}
}
URLClassLoader从http://localhost:8080/WebRoot/下加载TestImpl,要执行TestLoader类,要把Web项目部署到Tomcat中,启动Tomcat后(上述的端口可以自己修改,tomcat的内容这里就不再敖述),执行TestLoader,可以看到程序打印出TestImpl#add(),说明加载成功. 我们可以在TestLoader的main方法中添加System.out.println(loader),结果答应出java.net.URLClassLoader,说明URLClassLoader为自定义类装载器.
二.由于除启动类装载器之外的所有类装载器都是由Java实现的,这些类加载器也是Java类,也需要用相应的类加载器来装载,那么各种类加载器分别是用什么加载器来加载呢?下面描述一下这个问题,请看如下代码,其中WebRequest是httpunit的包,我把它放到了ext目录下,用来测试扩展类装载器:
public class Test{
public static void main(String[] args) throws Exception{
ClassLoader loader0 = Thread.currentThread().getContextClassLoader();
URLClassLoader loader1 = new URLClassLoader(new URL[]{});
System.out.println(loader0);
System.out.println(loader0.getClass().getClassLoader());
System.out.println("======================");
System.out.println(loader1);
System.out.println(loader1.getClass().getClassLoader());
System.out.println("======================");
System.out.println(WebRequest.class.getClassLoader());
System.out.println(WebRequest.class.getClassLoader().getClass().getClassLoader());
}
}
上述代码中分别把装载类路径类装载器(系统类装载器)loader0,自定义类装载器loader1,扩展类装载器WebRequest.class.getClassLoader()这三个类装载器的类装载器打印出来,结果为:
sun.misc.Launcher$AppClassLoader@187c6c7
null
======================
java.net.URLClassLoader@7d772e
null
======================
sun.misc.Launcher$ExtClassLoader@10b62c9
null
从结果中看出,类路径类装载器,自定义类装载器,扩展类装载器都是由启动类装载器装载的.
三.一个类中如果引用了其他类,如果被引用的类不是Java核心类,不是Java扩展类,也不是从网络加载的类, 而在classpath下,则装载被引用类的类装载器是装载第一个的类装载器,如下代码说明这个问题:
public class Test{
public static void main(String[] args) throws Exception{
Test0 t0 = new Test0();
Test1 t1 = new Test1();
System.out.println(t0.getClass().getClassLoader());
System.out.println(t1.getClass().getClassLoader());
System.out.println(Thread.currentThread().getContextClassLoader());
}
}
Test0和Test1都在classpath下,最后得到当前线程的类装载器(装载Test的类装载器),打印结果为:
sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$AppClassLoader@187c6c7
从中看出得到的类装载器实例的hash码是相同的,说明都是用同一个类加载器加载的,也就是装载Test的类装载器.
四.除启动类装载器之外的任何类装载器有且仅有一个父加载器,扩展类装载器的父装载器为启动类装载器,类路径类装载器的父装载器为扩展类装载器,自定义类装载器的父装载器为类路径类装载器.如下代码说明:
public class Test{
public static void main(String[] args) throws Exception{
URLClassLoader loader0 = new URLClassLoader(new URL[]{});
System.out.println(loader0.getParent());
System.out.println(loader0.getParent().getParent());
System.out.println(loader0.getParent().getParent().getParent());
}
}
打印结果为:
sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$ExtClassLoader@10b62c9
null
正好说明了上述的结论.
五.Java类装载器的委派机制:除启动类装载器外的任何类装载器都有一个默认的委派类装载器,比如:当一个自定义类装载器loader0试图去装载网络上的一个类时,它不会自己先去加载,而是先将加载任务委托给它的类路径类装载器,类路径类装载器又会将任务委托给扩展类装载器,扩展类装载器又会将任务委托给启动类装载器,由于在核心类库中找不到要加载的类,所以它告诉扩展类装载器没有加载到相应的类,这是扩展类装载器试图去加载,也没有找到,然后类路径类装载器在classpath也没找到.于是,loader0自己从网络上加载该类.从上面的描述中可以看出,启动类装载器优先去加载类.这样做的好处就是提高了安全性. 设想一下,如果有个恶意类,它的全限定名和Java核心类库中某个类相同,如java.lang.Integer,如果你的Java程序中使用了Integer这个类,如果没有这种委派机制的话,类路径类装载器会加载这个恶意类并执行,假如这个恶意Integer类中使用JNI来调用操作系统的API,那么后果可想而知. 不过通过委派机制的话,启动类装载器先去找java.lang.Integer,找到了之后,直接返回给类路径类装载器,这样类路径类装载器就没有机会去加载那个恶意的java.lang.Integer,这样就避免了一些安全问题.
上述写的可能不太直观,下面用代码说明:
假如我自己定义一个java.lang.Integer尝试去调用它:
package java.lang;
public class Integer {
public static void destroy(){
System.out.println("start destroy...");
}
}
测试类如下:
public class Test{
public static void main(String[] args) throws Exception{
Integer.destroy();
}
}
执行测试类并没有看到所期望的"start destroy...",而是一个异常:Exception in thread "main" java.lang.NoSuchMethodError: java.lang.Integer.destroy()V;这正好说明了启动类装载器已经装载了Integer并返回,程序中的Integer是Java核心类库中的类,当试图去调用destroy()方法时,由于Java核心类java.lang.Integer没有destroy()方法,所以报NoSuchMethodError.
先写到这里了...
一.Java中有四中类装载器:启动类装载器,扩展类装载器,类路径类装载器,自定义类装载器.下面将围绕着这三s种类装载器做一个详细的描述:
1.启动类装载器:也叫引导类装装载器,它是JVM内部的类装载器,用C++编写,作用是装载Java核心类库中的类,比如说一个Java虚拟机目录为D:\JDK1.5,则启动类装载器负责装载D:\JDK1.5\jre\lib\rt.jar,rt.jar为Java核心类库,比如我们常用到的java.lang包中的System类,由于启动类装载器是供JVM使用的,Java程序并不能直接使用,下面举个例子来说明:
class Test {
public static void main(String[] args) {
System.out.println(System.class.getClassLoader());
}
}
上述程序打印出装载System类的类装载器,而打印出的却是null,说明了启动类装载器不能直接调用.
2.扩展类装载器:它负责装载Java的扩展类,比如说一个Java虚拟机目录为D:\JDK1.5,则它负责加载D:\JDK1.5\jre\lib\ext下的类库中的类,假如ext目录下有个jar包,包里有个Test类,包名为org.test,则可以用org.test.Test.class.getClassLoader()方法打印出该类加载器,可以看到结果为sun.misc.Launcher$ExtClassLoader,说明Test类由扩展类装载器装载,可以根据需要把自己写的类打成jar包放到ext目录下.
3.类路径类装载器:也可以叫系统类装载器,它负责装载当前classpath下的类,也就是当我们要运行一个Java程序时初始类的包所在的目录,比如在D:\test下有个Test.class,它是程序的初始类,当执行Java Test命令时D:\test就是classpath. 一般classpath下的类都是我们自定义的类,同样Test.getClassLoader()方法得到的结果是sun.misc.Launcher$AppClassLoader,说明Test类由类路径类装载器加载.
4.自定义类装载器:Java允许用户可以自定义类装载器来装载类,下面举个例子,使用URLClassLoader,从网络上装载一个类:
首先自己创建一个Java Web工程,Web根目录为WebRoot(WEB-INF的上一级目录),在WebRoot下创建一个包名为org.test.TestImpl的类,即TestImpl.class文件在WebRoot目录的org/test目录下,我们在定义一个接口,名为Test,接口有个test()方法,让Test实现它的test()方法,为了测试方便,把Test接口放在classes目录下:
Test类代码如下:
package org.test.TestImpl;
public class TestImpl implements Test{
public void add(){
System.out.println("TestImpl#add()");
}
}
在classes目录下写个测试类TestLoader :
public class TestLoader {
public static void main(String[] args) throws Exception{
URL url = new URL("http://localhost:8080/WebRoot/");
URLClassLoader loader = new URLClassLoader(new URL[]{url});
Class clazz = loader.loadClass("org.test.TestImpl");
Test t = (Test) clazz.newInstance();
t.add();
}
}
URLClassLoader从http://localhost:8080/WebRoot/下加载TestImpl,要执行TestLoader类,要把Web项目部署到Tomcat中,启动Tomcat后(上述的端口可以自己修改,tomcat的内容这里就不再敖述),执行TestLoader,可以看到程序打印出TestImpl#add(),说明加载成功. 我们可以在TestLoader的main方法中添加System.out.println(loader),结果答应出java.net.URLClassLoader,说明URLClassLoader为自定义类装载器.
二.由于除启动类装载器之外的所有类装载器都是由Java实现的,这些类加载器也是Java类,也需要用相应的类加载器来装载,那么各种类加载器分别是用什么加载器来加载呢?下面描述一下这个问题,请看如下代码,其中WebRequest是httpunit的包,我把它放到了ext目录下,用来测试扩展类装载器:
public class Test{
public static void main(String[] args) throws Exception{
ClassLoader loader0 = Thread.currentThread().getContextClassLoader();
URLClassLoader loader1 = new URLClassLoader(new URL[]{});
System.out.println(loader0);
System.out.println(loader0.getClass().getClassLoader());
System.out.println("======================");
System.out.println(loader1);
System.out.println(loader1.getClass().getClassLoader());
System.out.println("======================");
System.out.println(WebRequest.class.getClassLoader());
System.out.println(WebRequest.class.getClassLoader().getClass().getClassLoader());
}
}
上述代码中分别把装载类路径类装载器(系统类装载器)loader0,自定义类装载器loader1,扩展类装载器WebRequest.class.getClassLoader()这三个类装载器的类装载器打印出来,结果为:
sun.misc.Launcher$AppClassLoader@187c6c7
null
======================
java.net.URLClassLoader@7d772e
null
======================
sun.misc.Launcher$ExtClassLoader@10b62c9
null
从结果中看出,类路径类装载器,自定义类装载器,扩展类装载器都是由启动类装载器装载的.
三.一个类中如果引用了其他类,如果被引用的类不是Java核心类,不是Java扩展类,也不是从网络加载的类, 而在classpath下,则装载被引用类的类装载器是装载第一个的类装载器,如下代码说明这个问题:
public class Test{
public static void main(String[] args) throws Exception{
Test0 t0 = new Test0();
Test1 t1 = new Test1();
System.out.println(t0.getClass().getClassLoader());
System.out.println(t1.getClass().getClassLoader());
System.out.println(Thread.currentThread().getContextClassLoader());
}
}
Test0和Test1都在classpath下,最后得到当前线程的类装载器(装载Test的类装载器),打印结果为:
sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$AppClassLoader@187c6c7
从中看出得到的类装载器实例的hash码是相同的,说明都是用同一个类加载器加载的,也就是装载Test的类装载器.
四.除启动类装载器之外的任何类装载器有且仅有一个父加载器,扩展类装载器的父装载器为启动类装载器,类路径类装载器的父装载器为扩展类装载器,自定义类装载器的父装载器为类路径类装载器.如下代码说明:
public class Test{
public static void main(String[] args) throws Exception{
URLClassLoader loader0 = new URLClassLoader(new URL[]{});
System.out.println(loader0.getParent());
System.out.println(loader0.getParent().getParent());
System.out.println(loader0.getParent().getParent().getParent());
}
}
打印结果为:
sun.misc.Launcher$AppClassLoader@187c6c7
sun.misc.Launcher$ExtClassLoader@10b62c9
null
正好说明了上述的结论.
五.Java类装载器的委派机制:除启动类装载器外的任何类装载器都有一个默认的委派类装载器,比如:当一个自定义类装载器loader0试图去装载网络上的一个类时,它不会自己先去加载,而是先将加载任务委托给它的类路径类装载器,类路径类装载器又会将任务委托给扩展类装载器,扩展类装载器又会将任务委托给启动类装载器,由于在核心类库中找不到要加载的类,所以它告诉扩展类装载器没有加载到相应的类,这是扩展类装载器试图去加载,也没有找到,然后类路径类装载器在classpath也没找到.于是,loader0自己从网络上加载该类.从上面的描述中可以看出,启动类装载器优先去加载类.这样做的好处就是提高了安全性. 设想一下,如果有个恶意类,它的全限定名和Java核心类库中某个类相同,如java.lang.Integer,如果你的Java程序中使用了Integer这个类,如果没有这种委派机制的话,类路径类装载器会加载这个恶意类并执行,假如这个恶意Integer类中使用JNI来调用操作系统的API,那么后果可想而知. 不过通过委派机制的话,启动类装载器先去找java.lang.Integer,找到了之后,直接返回给类路径类装载器,这样类路径类装载器就没有机会去加载那个恶意的java.lang.Integer,这样就避免了一些安全问题.
上述写的可能不太直观,下面用代码说明:
假如我自己定义一个java.lang.Integer尝试去调用它:
package java.lang;
public class Integer {
public static void destroy(){
System.out.println("start destroy...");
}
}
测试类如下:
public class Test{
public static void main(String[] args) throws Exception{
Integer.destroy();
}
}
执行测试类并没有看到所期望的"start destroy...",而是一个异常:Exception in thread "main" java.lang.NoSuchMethodError: java.lang.Integer.destroy()V;这正好说明了启动类装载器已经装载了Integer并返回,程序中的Integer是Java核心类库中的类,当试图去调用destroy()方法时,由于Java核心类java.lang.Integer没有destroy()方法,所以报NoSuchMethodError.
先写到这里了...
发表评论
-
关于无法delete文件
2011-09-26 17:12 1428File f=new File(targetDir+&qu ... -
正则表达式匹配替换网址
2011-08-30 13:10 3445有这么一个需求, 网页里所有的src="/web/ ... -
汉字编码
2011-07-29 11:08 942一、汉字编码的种类 汉字编码中现在主要用到的有三类, ... -
符编码笔记:ASCII,Unicode和UTF-8
2011-07-29 10:37 937阮一峰 日期: 2007年10月28日 1. ASCII码 ... -
Class.getResource
2011-07-21 13:19 1025用JAVA获取文件,听似简单,但对于很多像我这样的新人来说, ... -
学习内部类的总结
2010-10-24 11:23 941public class TestInnerStatic ... -
Classloader加载类的问题探讨
2010-09-06 14:28 1015首先在C:\Program Files\Java\jdk1.6 ... -
学习spring IOC AOP
2010-09-03 11:28 2448一.什么是控制反转模式? 不创建对象,但是描述创建它们的方 ... -
有符号类型转为无符号类型
2010-09-01 17:29 1453int toUnsigned(short s) { ... -
学习 utf-8总结
2010-08-15 16:45 851在ultraEditor中查看字符 “中国”的utf-8格式的 ... -
unicode
2010-08-15 16:02 1345Unicode是国际组织制定 ... -
关于集合的remove
2010-06-01 13:15 1118public class collectionsTest ... -
字符和整型的各种表示方法
2010-05-28 15:52 1428一个字符 的表示 '\u12ab'这种表示方法表示unico ... -
一个程序中String==String两种输入
2010-05-28 10:56 965今天帮别人写个程序 无意中发现的!! private v ... -
js中的if和Java中的if
2010-05-21 14:20 1574if(-323) { alert("if&q ... -
float和double精度
2010-05-19 10:55 2474float与double的范围和精度 1 范围 float和 ... -
子类重写父类的方法中有10种要求
2010-05-11 12:25 2301昨天发了一个帖子 parent.class ... -
the static method cannot hide instance method from object
2010-05-10 22:17 1278public class CloneInit implem ... -
proctected属性和方法的包依赖性
2010-05-08 20:34 1137这个说法是为理解自己造的 package testpro ... -
system.in.read
2010-04-28 10:34 1279关于字符的获得getBytes一直搞不明白!! 也就得过且过 ...
相关推荐
类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念
### Java深度历险(2)--深入类装载器 #### 前言 在现代软件开发领域,特别是使用Java这样的高级编程语言时,“动态性”是一个非常重要的概念。它指的是程序能够在运行时根据需要加载、卸载或替换部分代码的能力。这...
这个模型可以用层次结构来表示,例如,系统类装载器(AppClassLoader)的父类是扩展类装载器(ExtClassLoader),扩展类装载器的父类是启动类装载器(Bootstrap ClassLoader)。在示例代码`LoaderSample1`中,我们...
《JVM类装载器原理详解》 Java的JVM(Java Virtual Machine)类装载器是Java运行时系统的重要组成部分,负责在程序运行期间查找并加载类的二进制数据。理解类装载器的工作原理对于优化Java应用性能和实现动态加载类...
### 利用类装载器动态加载类并启动类 #### 概述 本文将详细介绍如何通过自定义类装载器来动态加载并启动类的过程,同时介绍一个简单的位移加密算法和非运算加密算法,以及如何使用这些算法进行文件的加密与解密。此...
在Java虚拟机(JVM)中,类装载器(ClassLoader)是至关重要的组成部分,它负责查找和加载Java类到JVM内存中。本教程聚焦于深入理解JVM内核,特别是类装载器的原理、诊断与优化。在这个第六部分中,我们将探讨以下几...
【浅析J2EE应用服务器的JAVA类装载器】 Java类装载器机制是Java语言灵活性的关键组成部分,尤其在J2EE应用服务器中扮演着重要角色。理解这一机制有助于开发者更好地部署和管理应用程序,解决可能出现的部署问题。 ...
Java的类装载器分为三个基本层次:启动类装载器(Bootstrap ClassLoader)、扩展类装载器(Extension ClassLoader)和应用程序类装载器(Application ClassLoader)。它们共同协作,根据类的全限定名(包括包名和...
Android基于类装载器插件架构的实现主要涉及到Android系统中类的动态加载与插件化架构的设计。在Android开发中,由于APK包的独立性和Android系统对安全性的严格限制,传统的插件化技术在动态加载外部模块时面临着...
类装载器ClassLoader1
所有JVM都内置了一个特殊的类装载器——根装载器(Bootstrap ClassLoader),它负责装载Java核心类库。当需要装载非设计时已知的类时,则需要使用用户自定义的类装载器。 #### 实例演示 以下是一个简单的示例,...
装载阶段涉及寻找并导入类或接口的二进制数据,通常由类装载器(ClassLoader)执行。链接阶段则包括校验、准备和解析,校验确保二进制数据的正确性,准备阶段为类的静态变量分配内存并初始化,解析则将符号引用转化...
这一过程涉及到了四个主要角色:类装载器(ClassLoader)、类的二进制表示、验证(Verification)、准备(Preparation)以及初始化(Initialization)。下面我们将逐一解析这些环节。 1. **类装载器**: 类装载器...
在实际开发中,类装载器的层次结构是关键,包括引导类装载器(Bootstrap ClassLoader)、扩展类装载器(Extension ClassLoader)和应用程序类装载器(Application ClassLoader),它们共同构成了双亲委派模型,保证...
在Java中,类装载器 把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化。其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的。各个步骤的主要工作如下: * ...
### WAS V7 理解类装载器 #### Java类装载器介绍 Java类装载器在Java编程语言中扮演着至关重要的角色。它们是Java虚拟机(JVM)的一部分,负责将Java类加载到运行时环境中。类装载器的正确配置对于确保应用程序能够...
在这个阶段,JVM会通过类装载器寻找并加载类的二进制数据。这通常是从类路径(Classpath)中获取的,例如`.class`文件。装载过程包括: - 二进制数据流生成:通过类路径查找指定类的`.class`文件,读取其二进制数据...