精彩的人生
好好工作,好好生活
BlogJava
首页
新随笔
联系
聚合
管理
147 Posts :: 0 Stories :: 220 Comments :: 0 Trackbacks
常用链接
我的随笔
我的评论
我的参与
最新评论
留言簿
(42)
给我留言
查看公开留言
查看私人留言
随笔分类
BIRT(1)
Eclipse(13)
EMF&GEF(6)
Google Code Jam(3)
Gossip(28)
Java(45)
Job(6)
Social Network(5)
Web(1)
Web Service(41)
我爱吃(2)
随笔档案
2008年9月 (1)
2008年8月 (1)
2008年3月 (1)
2008年2月 (1)
2008年1月 (1)
2007年12月 (1)
2007年11月 (2)
2007年10月 (1)
2007年7月 (1)
2007年3月 (1)
2006年10月 (9)
2006年9月 (18)
2006年8月 (4)
2006年7月 (6)
2006年6月 (3)
2006年5月 (11)
2006年4月 (27)
2006年3月 (25)
2006年2月 (6)
2006年1月 (1)
2005年12月 (20)
2005年11月 (6)
相册
my
收藏夹
GEF/EMF/Eclipse(1)
semantic web(4)
uddi(2)
配色方案(5)
Friends
Reload_cn
uiiang
八进制
老冒的SNS专栏
Web Site
Eclipse Org
Eclipse World
网谈
关注虹的新作,关注SNS
搜索
积分与排名
积分 - 188811
排名 - 65
最新评论
1. re: 正宗泡椒凤爪做法(zz)
谢谢楼主。明天我也准备做来试试。
--Angelo
2. re: 正宗泡椒凤爪做法(zz)
加点糖更爽。
--葛葛
3. re: 正宗泡椒凤爪做法(zz)[未登录]
配上图片太好了,简单明了,楼主好样的。
--ANN
4. re: 正宗泡椒凤爪做法(zz)[未登录]
配上图片,简单明了,楼主好样的,顶!
--ANN
5. re: 正宗泡椒凤爪做法(zz)[未登录]
太好了,我明天就去做,哈哈
--
阅读排行榜
1. 正宗泡椒凤爪做法(zz)(54600)
2. 转:Eclipse插件FatJar安装与使用(8181)
3. 2005.6.12 使用jsp上传文件(6739)
4. 将String转换成InputStream(5738)
5. 读Axis2用户帮助文档(5552)
6. 2005.6.12 图片处理(4012)
7. 简单的将String类型的xml转换为对象的代码(3960)
8. 探索:Eclipse+Spring+XFire+Resin开发Web service(1)(3733)
9. Eclipse的BPEL(3593)
10. 转:Java基础知识——Java入门与加深(3496)
评论排行榜
1. 正宗泡椒凤爪做法(zz)(85)
2. 2005.6.12 图片处理(15)
3. 读Axis2用户帮助文档(9)
4. 如何写好PPT(9)
5. 从扩展点中load class(8)
6. gef布局的一点感想(8)
7. 从插件/RCP中取得文件路径的方法(7)
8. 转:Eclipse插件FatJar安装与使用(6)
9. emf&gef之一example.my.gefpractice(6)
10. 简单的将String类型的xml转换为对象的代码(5)
初探Java类加载机制的奥秘(zz)
[文章信息]
作者:
cqfz
时间:
2005-02-15
出处:
天极网blog
责任编辑:
方舟
[文章导读]
在jdk1.2以后,类加载是通过委托来完成的,这意味着如果 ClassLoader 不能找到类……
一、在jdk1.2以后,类加载是通过委托来完成的,这意味着如果 ClassLoader 不能找到类,它会请求父代 ClassLoader 来执行此项任务,所有 ClassLoaders 的根是系统 ClassLoader,它会以缺省方式装入类 -- 即,从本地文件系统。今天我们就来探讨一下在jvm中这些机制是怎样运行的。让我们假设有一个class字节码文件(比如Hello.class文件),那么在应用程序中,他是如何被加载进来,并形成一个类对象的呢?我们这篇文章的目的就是为了解释这个问题。
在java.lang包里有个ClassLoader类,ClassLoader 的基本目标是对类的请求提供服务。当 JVM 需要使用类时,它根据名称向 ClassLoader 请求这个类,然后 ClassLoader 试图返回一个表示这个类的 Class 对象。通过覆盖对应于这个过程不同阶段的方法,可以创建定制的 ClassLoader。其中有个loadClass(String name, boolean resolve)方法,该方法为ClassLoader的入口点,在jdk1.2以后,loadClass方法将缺省调用findClass方法,详细内容可以参考API文档,我们编写的ClassLoader主要就是为了覆盖以上两个方法。回到我们刚才的问题,怎样读进字节码文件,并把它构成一个类对象呢?在ClassLoader里有个方法,Class defineClass(String name, byte[] b, int off, int len),答案就在这里了,我们根据把class字节码文件(如Hello.class)读进一个字节数组里,byte[] b,并把它转化为Class对象,而这些数据可以来源于文件,网络等,神奇吧:)
defineClass管理 JVM 的许多复杂、神秘和倚赖于实现的方面 -- 它把字节码分析成运行时数据结构、校验有效性等等。不必担心,您无需亲自编写它。事实上,即使您想要这么做也不能覆盖它,因为它已被标记成最终的。
其他一些方法:
findSystemClass方法:从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就使用 defineClass 将原始字节转换成 Class 对象,以将该文件转换成类。
findClass方法:jdk1.2以后loadClass 的缺省实现调用这个新方法。findClass 的用途包含您的 ClassLoader 的所有特殊代码,而无需要复制其它代码(例如,当专门的方法失败时,调用系统 ClassLoader)。
getSystemClassLoader: 如果覆盖 findClass 或 loadClass,getSystemClassLoader 使您能以实际 ClassLoader 对象来访问系统 ClassLoader(而不是固定的从 findSystemClass 调用它)。
getParent:为了将类请求委托给父代 ClassLoader,这个新方法允许 ClassLoader 获取它的父代 ClassLoader。当使用特殊方法,定制的 ClassLoader 不能找到类时,可以使用这种方法。
resolveClass: 可以不完全地(不带解析)装入类,也可以完全地(带解析)装入类。当编写我们自己的 loadClass 时,可以调用 resolveClass,这取决于 loadClass 的 resolve 参数的值。
findLoadedClass:充当一个缓存,当请求 loadClass 装入类时,它调用该方法来查看 ClassLoader 是否已装入这个类,这样可以避免重新装入已存在类所造成的麻烦。应首先调用该方法。
二、工作流程:
1)调用 findLoadedClass(String) 来查看是否存在已装入的类,如果没有,那么采用那种特殊的神奇方式来获取原始字节。
2)通过父类ClassLoader调用loadClass方法,如果父类ClassLoader是null,那么按缺省方式装入类,即系统ClassLoader。
3)调用findClass(String)去查找类并获取类;
4)如果loadClass 的 resolve 参数的值为true,那么调用 resolveClass 解析 Class 对象.
5)如果还没有类,返回 ClassNotFoundException。
6)否则,将类返回给调用程序。
三、一个实现了ClassLoader的例子:
/** */
/**
*CompilingClassLoader.java
*Copyright 2005-2-12
*/
import
java.io.
*
;
public
class
CompilingClassLoader
extends
ClassLoader
{
//
读取一个文件的内容
private
byte
[] getBytes(String filename)
throws
IOException
{
File file
=
new
File(filename);
long
len
=
file.length();
byte
[] raw
=
new
byte
[(
int
)len];
FileInputStream fin
=
new
FileInputStream(file);
int
r
=
fin.read(raw);
if
(r
!=
len)
throw
new
IOException(
"
Can't read all,
"
+
r
+
"
!=
"
+
len);
fin.close();
return
raw;
}
private
boolean
compile(String javaFile)
throws
IOException
{
System.out.println(
"
CCL:Compiling
"
+
javaFile
+
"
"
);
//
调用系统的javac命令
Process p
=
Runtime.getRuntime().exec(
"
javac
"
+
javaFile);
try
{
//
其他线程都等待这个线程完成
p.waitFor();
}
catch
(InterruptedException ie)
{
System.out.println(ie);
}
int
ret
=
p.exitValue();
return
ret
==
0
;
}
public
Class loadClass(String name,
boolean
resovle)
throws
ClassNotFoundException
{
Class clas
=
null
;
clas
=
findLoadedClass(name);
//
这里说明了包的表示
String fileStub
=
name.replace(
'
.
'
,
'
/
'
);
String javaFilename
=
fileStub
+
"
.java
"
;
String classFilename
=
fileStub
+
"
.class
"
;
File javaFile
=
new
File(javaFilename);
File classFile
=
new
File(classFilename);
//
如果存在class文件就不编译
if
(javaFile.exists()
&&
(
!
classFile.exists()
||
javaFile.lastModified()
>
classFile.lastModified()))
{
try
{
if
(
!
compile(javaFilename)
||!
classFile.exists())
{
throw
new
ClassNotFoundException(
"
ClassNotFoundExcetpion:
"
+
javaFilename);
}
}
catch
(IOException ie)
{
throw
new
ClassNotFoundException(ie.toString());
}
}
try
{
byte
[] raw
=
getBytes(classFilename);
//
通过读入数据来构造一个类结构,这是核心
clas
=
defineClass(name,raw,
0
,raw.length);
}
catch
(IOException ie)
{
//
}
if
(clas
==
null
)
{
clas
=
findSystemClass(name);
}
System.out.println(
"
findSystemClass:
"
+
clas);
if
(resovle
&&
clas
!=
null
)
{
resolveClass(clas);
}
if
(clas
==
null
)
{
throw
new
ClassNotFoundException(name);
}
return
clas;
}
}
测试该loader:
/** */
/**
*TestRun.java
*Copyright 2005-2-11
*/
import
java.lang.reflect.
*
;
public
class
TestRun
{
public
static
void
main(String[] args)
throws
Exception
{
String progClass
=
args[
0
];
String progArgs[]
=
new
String[args.length
-
1
];
System.arraycopy(args,
1
,progArgs,
0
,progArgs.length);
CompilingClassLoader ccl
=
new
CompilingClassLoader();
Class clas
=
ccl.loadClass(progClass);
//
返回一个class的type
Class[] mainArgType
=
{(
new
String[
0
]).getClass()}
;
Method main
=
clas.getMethod(
"
main
"
,mainArgType);
Object argsArray[]
=
{progArgs}
;
main.invoke(
null
,argsArray);
}
}
以上的核心内容已经编写完了,编译后,我们得到两个文件:
CompilingClassLoader.class,TestRun.class
四、编写一个例子,然后运行我们的ClassLoader
/** */
/**
*Hello.java
*/
public
class
Hello
{
public
static
void
main(String[] args)
{
if
(args.length
!=
1
)
{
System.err.println(
"
Error,exit!
"
);
System.exit(
1
);
}
String name
=
args[
0
];
System.out.println(
"
Hello,
"
+
name);
}
}
好了,运行java TestRun Hello 阿飞
.
.
.
Hello,阿飞
原文:
http://www.yesky.com/SoftChannel/72342371961929728/20050212/1911003.shtml
posted on 2006-10-23 16:19
hopeshared
阅读(1091)
评论(0)
编辑
收藏
所属分类:
Java
新用户注册
刷新评论列表
IT新闻:
·
Google Code 5岁啦!
·
PayPal宣布将与中国银联合作 剑指阿里巴巴
·
淘宝网全面下架曝光产品 惠普问题笔记本在内
·
控制力的较量,Android上的博弈
·
ATI显卡破译密码的速度是高端NVIDIA显卡的2倍
专题:
Android
iPad
jQuery
Chrome OS
博客园首页
IT新闻
知识库
学英语
Java程序员招聘
标题
姓名
主页
验证码
*
内容(请不要发表任何与政治相关的内容)
Remember Me?
登录
[使用Ctrl+Enter键可以直接提交]
每天10分钟,轻松学英语
推荐职位:
·
飞信服务器端高级.NET开发工程师(新媒传信)
·
.NET飞信官网开发工程师(新媒传信)
·
.NET技术开发总监(广州衣酷)
·
ASP.NET资深工程师 (盛大网络)
·
.NET初级程序员 (北京安人)
·
.NET中级程序员 (北京安人)
·
中高级.NET工程师(沪江网)
·
前端开发工程师(沪江网)
博客园首页随笔:
·
[下载]Internet Explorer 9 预览版
·
存储优化 -- 删除重复记录只保留单条
·
Expression Blend实例中文教程(2) - 界面快速入门
·
策略模式的扩展——策略枚举
·
微软一站式示例代码库 KB 文章 2010-3-16 更新列表
知识库:
·
面试时最难的25个问题
·
控制力的较量 Android上的博弈
·
应用程序商店与开发:警惕长尾失效
·
技术管理中常见的几个问题
·
伟大领导人的标志
网站导航:
博客园
IT新闻
个人主页
博客生活
IT博客网
C++博客
博客园社区
管理
相关文章:
一段关于callback的代码
当cmd里输入路径包含空格的时候
java类加载的表现形式(zz)
初探Java类加载机制的奥秘(zz)
Java类加载内幕(zz)
使用Jakarta Commons Pool处理对象池化(zz)
对象池(对象缓冲池)-高手进阶(zz)
简单的将String类型的xml转换为对象的代码
一段很好用的判断数据库中某张表是否存在的代码
转:Java Annotation 高级应用
Powered by:
BlogJava
Copyright © hopeshared