- 浏览: 620300 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
kongqinglong:
我艹,不好使,大骗子
基于Eclipse的FindBugs中文插件发布了 -
worket123:
误人子弟,不会就不要乱发
基于Eclipse的FindBugs中文插件发布了 -
accphc:
策略工厂实现Spring的ApplicationContext ...
Spring与策略模式 -
老凯和他的Java:
我也一直不漏的看完了,感触颇深,还是要多花花时间陪陪父母
纪念一位伟大的女性 -
IT_jingying:
认真的看完了,每一位母亲都是伟大的,她为自己的子女,家庭付出的 ...
纪念一位伟大的女性
返回0表示编译成功,字符串数组as则是我们用javac命令编译时的参数,以空格划分。例如:
javac -classpath c:"foo"bar.jar;. -d c:" c:"Some.java
则字符串数组as为{"-classpath","c:""foo""bar.jar;.","-d","c:""","c:""Some.java"},如果带有PrintWriter参数,则会把编译信息出到这个指定的printWriter中。默认的输出是System.err。
其中 Main是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,编译器在解析这个java源文件时所发现的它所依赖和引用的所有Class也将由system classloader载入,如果system classloader不能载入某个Class时,编译器将抛出一个“cannot resolve symbol”错误。
所以首先编译就通不过,也就是编译器无法编译一个引用了不在CLASSPATH中的未知Class的java源文件,而由于拼写错误或者没有把所需类库放到CLASSPATH中,大家一定经常看到这个“cannot resolve symbol”这个编译错误吧!
其次,就是我们把这个Class放到编译路径中,成功的进行了编译,然后在运行的时候不把它放入到CLASSPATH中而利用我们自己的 classloader来动态载入这个Class,这时候也会出现“java.lang.NoClassDefFoundError”的违例,为什么呢?
我们再来分析一下,首先调用这个造型语句的可执行的Class一定是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,当我们进行造型的时候,JVM也会使用system classloader来尝试载入这个Class来对实例进行造型,自然在system classloader寻找不到这个Class时就会抛出“java.lang.NoClassDefFoundError”的违例。
OK,现在让我们来总结一下,java文件的编译和Class的载入执行,都是使用Launcher初始化的system classloader作为类载入器的,我们无法动态的改变system classloader,更无法让JVM使用我们自己的classloader来替换system classloader,根据全盘负责原则,就限制了编译和运行时,我们无法直接显式的使用一个system classloader寻找不到的Class,即我们只能使用Java核心类库,扩展类库和CLASSPATH中的类库中的Class。
还不死心!再尝试一下这种情况,我们把这个Class也放入到CLASSPATH中,让system classloader能够识别和载入。然后我们通过自己的classloader来从指定的class文件中载入这个Class(不能够委托 parent载入,因为这样会被system classloader从CLASSPATH中将其载入),然后实例化一个Object,并造型成这个Class,这样JVM也识别这个Class(因为 system classloader能够定位和载入这个Class从CLASSPATH中),载入的也不是CLASSPATH中的这个Class,而是从 CLASSPATH外动态载入的,这样总行了吧!十分不幸的是,这时会出现“java.lang.ClassCastException”违例。
为什么呢?我们也来分析一下,不错,我们虽然从CLASSPATH外使用我们自己的classloader动态载入了这个Class,但将它的实例造型的时候是JVM会使用system classloader来再次载入这个Class,并尝试将使用我们的自己的classloader载入的Class的一个实例造型为system classloader载入的这个Class(另外的一个)。大家发现什么问题了吗?也就是我们尝试将从一个classloader载入的Class的一个实例造型为另外一个classloader载入的Class,虽然这两个Class的名字一样,甚至是从同一个class文件中载入。但不幸的是JVM 却认为这个两个Class是不同的,即JVM认为不同的classloader载入的相同的名字的Class(即使是从同一个class文件中载入的)是不同的!这样做的原因我想大概也是主要出于安全性考虑,这样就保证所有的核心Java类都是system classloader载入的,我们无法用自己的classloader载入的相同名字的Class的实例来替换它们的实例。
看到这里,聪明的读者一定想到了该如何动态载入我们的Class,实例化,造型并调用了吧!
那就是利用面向对象的基本特性之一的多形性。我们把我们动态载入的Class的实例造型成它的一个system classloader所能识别的父类就行了!这是为什么呢?我们还是要再来分析一次。当我们用我们自己的classloader来动态载入这我们只要把这个Class的时候,发现它有一个父类Class,在载入它之前JVM先会载入这个父类Class,这个父类Class是system classloader所能识别的,根据委托机制,它将由system classloader载入,然后我们的classloader再载入这个Class,创建一个实例,造型为这个父类Class,注意了,造型成这个父类 Class的时候(也就是上溯)是面向对象的java语言所允许的并且JVM也支持的,JVM就使用system classloader再次载入这个父类Class,然后将此实例造型为这个父类Class。大家可以从这个过程发现这个父类Class都是由 system classloader载入的,也就是同一个class loader载入的同一个Class,所以造型的时候不会出现任何异常。而根据多形性,调用这个父类的方法时,真正执行的是这个Class(非父类 Class)的覆盖了父类方法的方法。这些方法中也可以引用system classloader不能识别的Class,因为根据全盘负责原则,只要载入这个Class的classloader即我们自己定义的 classloader能够定位和载入这些Class就行了。
这样我们就可以事先定义好一组接口或者基类并放入CLASSPATH中,然后在执行的时候动态的载入实现或者继承了这些接口或基类的子类。还不明白吗?让我们来想一想Servlet吧,web application server能够载入任何继承了Servlet的Class并正确的执行它们,不管它实际的Class是什么,就是都把它们实例化成为一个Servlet Class,然后执行Servlet的init,doPost,doGet和destroy等方法的,而不管这个Servlet是从web- inf/lib和web-inf/classes下由system classloader的子classloader(即定制的classloader)动态载入。说了这么多希望大家都明白了。在applet,ejb等容器中,都是采用了这种机制.
对于以上各种情况,希望大家实际编写一些example来实验一下。
最后我再说点别的,classloader虽然称为类加载器,但并不意味着只能用来加载Class,我们还可以利用它也获得图片,音频文件等资源的URL,当然,这些资源必须在CLASSPATH中的jar类库中或目录下。我们来看API的doc中关于ClassLoader的两个寻找资源和Class的方法描述吧:
public URL getResource(String name)
用指定的名字来查找资源,一个资源是一些能够被class代码访问的在某种程度上依赖于代码位置的数据(图片,音频,文本等等)。
一个资源的名字是以'/'号分隔确定资源的路径名的。
这个方法将先请求parent classloader搜索资源,如果没有parent,则会在内置在虚拟机中的classloader(即bootstrap classloader)的路径中搜索。如果失败,这个方法将调用findResource(String)来寻找资源。
public static URL getSystemResource(String name)
从用来载入类的搜索路径中查找一个指定名字的资源。这个方法使用system class loader来定位资源。即相当于ClassLoader.getSystemClassLoader().getResource(name)。
例如:
System.out.println(ClassLoader.getSystemResource("java/lang/String.class"));
的结果为:
jar:file:/C:/j2sdk1.4.1_01/jre/lib/rt.jar!/java/lang/String.class
表明String.class文件在rt.jar的java/lang目录中。
因此我们可以将图片等资源随同Class一同打包到jar类库中(当然,也可单独打包这些资源)并添加它们到class loader的搜索路径中,我们就可以无需关心这些资源的具体位置,让class loader来帮我们寻找了!
以上是转自bea论坛的一篇文章,作者不清楚,估计是bea内部的大牛。是值得俺们顶礼膜拜的神一般的存在 XD
最后 附上自己的几点理解
bootstrap classloader ------- 对应jvm中某c++写的dll类
Extenson ClassLoader ---------对应内部类ExtClassLoader
System ClassLoader ---------对应内部类AppClassLoader
Custom ClassLoader ----------对应任何URLClassLoader的子类(你也可以继承SecureClassLoader或者更加nb一点 直接继承ClassLoader,这样的话你也是神一般的存在了 XD)
以上四种classloder按照从上到下的顺序,依次为下一个的parent
这个第一概念
第二个概念是几个有关的classloader的类
抽象类 ClassLoader
|
SecureClassLoader
|
URLClassloader
| |
sun的ExtClassLoader sun的AppClassLoader
以上的类之间是继承关系,与第一个概念说的parent是两回事情,需要小心。
第三个概念是Thread的ContextClassLoader
其实从Context的名称就可以看出来,这只是一个用以存储任何classloader引用的临时存储空间,与classloader的层次没有任何关系。
第四 就是如何实现自己的classloader了,本来是要翻译另外一篇文章Find a way out of the ClassLoader maze
不过今天时间都花在《小夫妻天天恶战》这篇神文上了 XD 强烈推荐任何和俺一样期望彪悍人生的朋友都去看看
翻译明天补上,浪费时间是可耻的 XD
匿鸟,晚上还有朋友推荐的 《lie with me》(与我同眠)要看。XD
javac -classpath c:"foo"bar.jar;. -d c:" c:"Some.java
则字符串数组as为{"-classpath","c:""foo""bar.jar;.","-d","c:""","c:""Some.java"},如果带有PrintWriter参数,则会把编译信息出到这个指定的printWriter中。默认的输出是System.err。
其中 Main是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,编译器在解析这个java源文件时所发现的它所依赖和引用的所有Class也将由system classloader载入,如果system classloader不能载入某个Class时,编译器将抛出一个“cannot resolve symbol”错误。
所以首先编译就通不过,也就是编译器无法编译一个引用了不在CLASSPATH中的未知Class的java源文件,而由于拼写错误或者没有把所需类库放到CLASSPATH中,大家一定经常看到这个“cannot resolve symbol”这个编译错误吧!
其次,就是我们把这个Class放到编译路径中,成功的进行了编译,然后在运行的时候不把它放入到CLASSPATH中而利用我们自己的 classloader来动态载入这个Class,这时候也会出现“java.lang.NoClassDefFoundError”的违例,为什么呢?
我们再来分析一下,首先调用这个造型语句的可执行的Class一定是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,当我们进行造型的时候,JVM也会使用system classloader来尝试载入这个Class来对实例进行造型,自然在system classloader寻找不到这个Class时就会抛出“java.lang.NoClassDefFoundError”的违例。
OK,现在让我们来总结一下,java文件的编译和Class的载入执行,都是使用Launcher初始化的system classloader作为类载入器的,我们无法动态的改变system classloader,更无法让JVM使用我们自己的classloader来替换system classloader,根据全盘负责原则,就限制了编译和运行时,我们无法直接显式的使用一个system classloader寻找不到的Class,即我们只能使用Java核心类库,扩展类库和CLASSPATH中的类库中的Class。
还不死心!再尝试一下这种情况,我们把这个Class也放入到CLASSPATH中,让system classloader能够识别和载入。然后我们通过自己的classloader来从指定的class文件中载入这个Class(不能够委托 parent载入,因为这样会被system classloader从CLASSPATH中将其载入),然后实例化一个Object,并造型成这个Class,这样JVM也识别这个Class(因为 system classloader能够定位和载入这个Class从CLASSPATH中),载入的也不是CLASSPATH中的这个Class,而是从 CLASSPATH外动态载入的,这样总行了吧!十分不幸的是,这时会出现“java.lang.ClassCastException”违例。
为什么呢?我们也来分析一下,不错,我们虽然从CLASSPATH外使用我们自己的classloader动态载入了这个Class,但将它的实例造型的时候是JVM会使用system classloader来再次载入这个Class,并尝试将使用我们的自己的classloader载入的Class的一个实例造型为system classloader载入的这个Class(另外的一个)。大家发现什么问题了吗?也就是我们尝试将从一个classloader载入的Class的一个实例造型为另外一个classloader载入的Class,虽然这两个Class的名字一样,甚至是从同一个class文件中载入。但不幸的是JVM 却认为这个两个Class是不同的,即JVM认为不同的classloader载入的相同的名字的Class(即使是从同一个class文件中载入的)是不同的!这样做的原因我想大概也是主要出于安全性考虑,这样就保证所有的核心Java类都是system classloader载入的,我们无法用自己的classloader载入的相同名字的Class的实例来替换它们的实例。
看到这里,聪明的读者一定想到了该如何动态载入我们的Class,实例化,造型并调用了吧!
那就是利用面向对象的基本特性之一的多形性。我们把我们动态载入的Class的实例造型成它的一个system classloader所能识别的父类就行了!这是为什么呢?我们还是要再来分析一次。当我们用我们自己的classloader来动态载入这我们只要把这个Class的时候,发现它有一个父类Class,在载入它之前JVM先会载入这个父类Class,这个父类Class是system classloader所能识别的,根据委托机制,它将由system classloader载入,然后我们的classloader再载入这个Class,创建一个实例,造型为这个父类Class,注意了,造型成这个父类 Class的时候(也就是上溯)是面向对象的java语言所允许的并且JVM也支持的,JVM就使用system classloader再次载入这个父类Class,然后将此实例造型为这个父类Class。大家可以从这个过程发现这个父类Class都是由 system classloader载入的,也就是同一个class loader载入的同一个Class,所以造型的时候不会出现任何异常。而根据多形性,调用这个父类的方法时,真正执行的是这个Class(非父类 Class)的覆盖了父类方法的方法。这些方法中也可以引用system classloader不能识别的Class,因为根据全盘负责原则,只要载入这个Class的classloader即我们自己定义的 classloader能够定位和载入这些Class就行了。
这样我们就可以事先定义好一组接口或者基类并放入CLASSPATH中,然后在执行的时候动态的载入实现或者继承了这些接口或基类的子类。还不明白吗?让我们来想一想Servlet吧,web application server能够载入任何继承了Servlet的Class并正确的执行它们,不管它实际的Class是什么,就是都把它们实例化成为一个Servlet Class,然后执行Servlet的init,doPost,doGet和destroy等方法的,而不管这个Servlet是从web- inf/lib和web-inf/classes下由system classloader的子classloader(即定制的classloader)动态载入。说了这么多希望大家都明白了。在applet,ejb等容器中,都是采用了这种机制.
对于以上各种情况,希望大家实际编写一些example来实验一下。
最后我再说点别的,classloader虽然称为类加载器,但并不意味着只能用来加载Class,我们还可以利用它也获得图片,音频文件等资源的URL,当然,这些资源必须在CLASSPATH中的jar类库中或目录下。我们来看API的doc中关于ClassLoader的两个寻找资源和Class的方法描述吧:
public URL getResource(String name)
用指定的名字来查找资源,一个资源是一些能够被class代码访问的在某种程度上依赖于代码位置的数据(图片,音频,文本等等)。
一个资源的名字是以'/'号分隔确定资源的路径名的。
这个方法将先请求parent classloader搜索资源,如果没有parent,则会在内置在虚拟机中的classloader(即bootstrap classloader)的路径中搜索。如果失败,这个方法将调用findResource(String)来寻找资源。
public static URL getSystemResource(String name)
从用来载入类的搜索路径中查找一个指定名字的资源。这个方法使用system class loader来定位资源。即相当于ClassLoader.getSystemClassLoader().getResource(name)。
例如:
System.out.println(ClassLoader.getSystemResource("java/lang/String.class"));
的结果为:
jar:file:/C:/j2sdk1.4.1_01/jre/lib/rt.jar!/java/lang/String.class
表明String.class文件在rt.jar的java/lang目录中。
因此我们可以将图片等资源随同Class一同打包到jar类库中(当然,也可单独打包这些资源)并添加它们到class loader的搜索路径中,我们就可以无需关心这些资源的具体位置,让class loader来帮我们寻找了!
以上是转自bea论坛的一篇文章,作者不清楚,估计是bea内部的大牛。是值得俺们顶礼膜拜的神一般的存在 XD
最后 附上自己的几点理解
bootstrap classloader ------- 对应jvm中某c++写的dll类
Extenson ClassLoader ---------对应内部类ExtClassLoader
System ClassLoader ---------对应内部类AppClassLoader
Custom ClassLoader ----------对应任何URLClassLoader的子类(你也可以继承SecureClassLoader或者更加nb一点 直接继承ClassLoader,这样的话你也是神一般的存在了 XD)
以上四种classloder按照从上到下的顺序,依次为下一个的parent
这个第一概念
第二个概念是几个有关的classloader的类
抽象类 ClassLoader
|
SecureClassLoader
|
URLClassloader
| |
sun的ExtClassLoader sun的AppClassLoader
以上的类之间是继承关系,与第一个概念说的parent是两回事情,需要小心。
第三个概念是Thread的ContextClassLoader
其实从Context的名称就可以看出来,这只是一个用以存储任何classloader引用的临时存储空间,与classloader的层次没有任何关系。
第四 就是如何实现自己的classloader了,本来是要翻译另外一篇文章Find a way out of the ClassLoader maze
不过今天时间都花在《小夫妻天天恶战》这篇神文上了 XD 强烈推荐任何和俺一样期望彪悍人生的朋友都去看看
翻译明天补上,浪费时间是可耻的 XD
匿鸟,晚上还有朋友推荐的 《lie with me》(与我同眠)要看。XD
发表评论
-
大型跨境电商JVM调优经历
2018-02-23 14:01 10212前提:某大型跨境电商业务发展非常快,线上机器扩容也很频繁, ... -
Spring与策略模式
2014-02-09 18:15 43448... -
以NIO通信例子结合Jconsole解释JVM内存分配机制
2012-03-22 22:11 3801JAVA的内存分配机制,在很多地方都已经解析很多次了, ... -
推荐一个Eclipse的UML插件:AmaterasUML
2010-11-19 15:21 11136介绍介绍Eclipse的UML插件:AmaterasUML ... -
Java的比较
2010-11-18 22:13 1583一、== 适用于基本对象值的比较,其他对象是比较引用 ... -
classloader相关基础知识
2010-11-18 22:10 1223JVM jvm是jre里头一个动态 ... -
JAVA并发之Exchanger
2010-10-20 14:40 6337JDK1.5中有一个Exchanger类,可以用来完成线程 ... -
一道JAVA面试题
2010-10-18 22:01 2137题目:一列整型数组,从第一个开始,累加后续两个数字,得到 ... -
JAVA内存模型
2010-07-07 20:36 2278一、Java把内存划分成 ... -
JAVA动态代理解析
2010-06-11 09:25 1366众所周知,JDK的动态代理模式必须实现接口。 以下面的源码为 ... -
一次失败的JAVA性能优化经历
2010-05-26 17:44 1547在一次性能优化中,作为方案的主要参与者,我做了如下分析: ... -
双重检查锁定及单例模式,线程安全
2010-04-11 19:39 1984自己以前认识的单例模式很简单: 方式一: publ ... -
JAVA监控多个线程状态的一种实现
2010-03-19 21:33 6020场景:需要启动多线程处理事情,而在所有事情做完之后,需要修 ... -
Java在Linux下不能处理图形的解决办法
2010-02-08 20:09 2881Java在图形处理时调用了本地的图形处理库。在利用Java作 ... -
高性能JAVA代码的若干个习惯
2010-02-06 19:47 2767创建对象: 1.避免在循 ... -
JAVA read readLine逐行读取文件的问题
2009-10-30 10:08 44420在一次读取文件的写法中,逐行 int c; ... -
ClassLoader载入层次
2009-09-18 22:21 2811Class.forName(classname)默认 ... -
ArrayList对象引用的问题
2009-09-18 10:27 3363老问题了,之所以贴出来是给大家看看,希望不要出现类似的错误: ...
相关推荐
本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载机制遵循“双亲委派模型”(Delegation Model)。当一个类被加载时,它首先会尝试由当前...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。本示例"ClassLoader小例子"将深入探讨这个概念,并通过一个具体的程序来演示其工作原理。下面我们...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。了解和掌握ClassLoader的工作原理以及如何自定义ClassLoader对于深入理解Java应用程序的运行机制非常有帮助。以下是对...
Java ClassLoader是Java运行时系统的关键但经常被忽视的组件,负责在运行时查找和加载类文件。通过创建自定义ClassLoader,你可以定制JVM,使类文件的引入方式完全重新定义,这提供了很多实用和有趣的可能。这篇教程...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...
3. **在Java堆中生成一个代表这个类的`java.lang.Class`对象**,作为方法区这些数据的访问入口。 #### 三、Java中类加载器的几种方法 1. **`loadClass`**: 遵循双亲委托机制,尝试加载指定类。此方法先检查是否...
ClassLoader是JVM中的一个重要组件,它的主要任务是加载类的二进制数据,转换为Class对象,并供Java应用程序使用。本文将深入浅出地探讨JVM ClassLoader的工作原理和相关知识点。 首先,ClassLoader可以分为三种...
1. **加载**:加载是ClassLoader工作的起点,它从文件系统或网络中找到类的二进制数据,然后创建一个对应的Class对象。这个过程可以通过自定义ClassLoader来实现,比如从数据库中加载类。 2. **验证**:验证是确保...
### Java ClassLoader (类加载器)详解 #### 一、教程提示 如果你正在查看这份文档,在线版中你可以点击下面的任何主题直接跳转到相应的部分。 1. **教程提示** 2. **介绍** 3. **类加载器结构** 4. **编译类加载...
在Java中,Classloader是加载类的关键组件,它负责查找、加载和初始化字节码文件。自定义Classloader允许开发者根据特定需求定制类的加载逻辑,例如加密类文件、隔离不同版本的库或者动态加载代码。本文将深入探讨...
总的来说,ClassLoader运行机制是一个涉及多层委托、缓存管理、类隔离的重要概念。理解并能灵活运用这些知识对于开发和调试Java应用程序,特别是部署在容器如WebLogic上的应用,是至关重要的。在编写自己的...
自定义ClassLoader则允许我们插入这个流程,按照自己的规则去查找和加载类。 在自定义ClassLoader时,主要需要覆写两个关键方法:`findClass()` 和 `loadClass()`。`loadClass()` 方法通常用于委托父类加载器加载类...
Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...
ClassLoader的层次结构通常包括Bootstrap ClassLoader(启动类加载器)、Extension ClassLoader(扩展类加载器)和AppClassLoader(应用程序类加载器)。Bootstrap ClassLoader负责加载JRE核心库,如rt.jar;...
Java的类加载过程遵循双亲委托模型,即一个类加载请求会先委托给父ClassLoader,只有当父类加载器无法完成加载时,才会由当前类加载器进行加载。 ClassLoader的工作流程可以分为三个主要步骤: 1. **查找**:当...
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中执行。这篇测试主要探讨了ClassLoader的工作原理及其在实际应用中的使用。通过阅读给出的博文链接,我们可以深入理解...
开源项目"classloader-playground"为我们提供了一个学习和实验Java类加载器的绝佳平台。 首先,我们来理解一下什么是类加载器。在Java中,类加载的过程包括加载、验证、准备、解析和初始化五个阶段。类加载器主要...
在Java编程语言中,类加载器(ClassLoader)是一个至关重要的组件,负责将类的字节码从磁盘、网络或其他数据源加载到JVM(Java虚拟机)中,然后将其转换为运行时的类对象。这个过程是Java程序动态加载和运行的基础。...