Java的ClassLoader与Package机制介绍了ClassLoader的委派机制,它是把装载的任务传递给上级的装载器的,依次类推,直到启动类装载器(没有上级类装载器)。如果启动类装载器能够装载这个类,那么它会首先装载。如果不能,则往下传递。其实这引出一个运行时包的概念。不同装载器装载的类,即使包名相同也不能互相访问。这样保证了核心类库不被破坏。(by juxtapose)
本文将讲述如何扩展ClassLoader类实现一个自己的类装载器,每个Class对象都有一个引用指向装载他的ClassLoader,你可以通过public ClassLoader getClassLoader()方法得到它。为了创建自己的类装载器我们应该扩展ClassLoader类,这是一个抽象类。我们目的是从本地文件系统使用我们实现的类装载器装载一个类。我们创建一个FileClassLoader extends ClassLoader。我们需要覆盖ClassLoader中的
findClass(String name)方法,这个方法通过类的名字而得到一个Class对象。
1
public Class findClass(String name)
2

{
3
byte[] data = loadClassData(name);
4
return defineClass(name, data, 0, data.length);
5
}
6
我们还应该提供一个方法loadClassData(String name),通过类的名称返回class文件的字节数组。然后使用ClassLoader提供的defineClass()方法我们就可以返回Class对象了。
1
public byte[] loadClassData(String name)
2

{
3
FileInputStream fis = null;
4
byte[] data = null;
5
try
6

{
7
fis = new FileInputStream(new File(drive + name + fileType));
8
ByteArrayOutputStream baos = new ByteArrayOutputStream();
9
int ch = 0;
10
while ((ch = fis.read()) != -1)
11

{
12
baos.write(ch);
13
14
}
15
data = baos.toByteArray();
16
} catch (IOException e)
17

{
18
e.printStackTrace();
19
}
20
21
return data;
22
}
23
这里我们是从D盘装载一个类。
下面我们提供一个类public class MyApp{},类中没有定义任何方法和变量,下面我们编译MyApp.java得到MyApp.class,然后把文件放在D盘的根目录。为了证明MyApp.class是被我们定义的classloader装载的,我们在FileClassLoader的main()方法中打印出装载MyApp.class的类装载器的名称。
1
public static void main(String[] args) throws Exception
2

{
3
FileClassLoader loader = new FileClassLoader();
4
Class objClass = loader.loadClass("MyApp", true);
5
Object obj = objClass.newInstance();
6
System.out.println(objClass.getName());
7
System.out.println(objClass.getClassLoader());
8
9
10
}
11
编译FileClassLoader
javac FileClassLoader.java 然后运行java FileClassLoader 可以看到输出结果为
MyApp
FileClassLoader@1a5ab41
如果你把MyApp.class放入到你程序的所在目录会出现什么情况呢?读者自己实践一下吧!
结果为:MyApp
sun.misc.Launcher$AppClassLoader@92e78c
下面给出FileClassLoader的源代码。/*
1
* Created on 2005-7-27
2
3
*
4
5
* To change the template for this generated file go to
6
7
* Window>Preferences>Java>Code Generation>Code and Comments
8
9
*/
10
11
12
/** *//**
13
14
* @author liuxiang
15
16
*
17
18
* To change the template for this generated type comment go to
19
20
* Window>Preferences>Java>Code Generation>Code and Comments
21
22
*/
23
24
import java.io.ByteArrayOutputStream;
25
26
import java.io.File;
27
28
import java.io.FileInputStream;
29
30
import java.io.IOException;
31
32
public class FileClassLoader extends ClassLoader
33
34

{
35
36
public static final String drive = "d:/";
37
38
public static final String fileType = ".class";
39
40
41
public FileClassLoader()
{
42
43
super();
44
45
46
}
47
48
49
public FileClassLoader(ClassLoader arg0)
{
50
51
super(arg0);
52
53
}
54
55
56
public Class findClass(String name)
57
58

{
59
60
byte[] data = loadClassData(name);
61
62
/**//*
63
64
* Converts an array of bytes into an instance of class Class.
65
66
* Before the Class can be used it must be resolved.
67
68
*
69
70
* This method assigns a default ProtectionDomain to the newly
71
72
* defined class. The ProtectionDomain contains the set of
73
74
* permissions granted when a call to Policy.getPolicy().getPermissions()
75
76
* is made with a code source of null,null. The default domain
77
78
* is created on the first invocation of defineClass, and re-used
79
80
* on subsequent calls.
81
82
* To assign a specific ProtectionDomain to the class, use the
83
84
* defineClass method that takes a ProtectionDomain as one of
85
86
* its arguments.
87
88
*/
89
90
/**//*
91
92
* 该方法接受由原始字节组成的数组并把它转化成class对象
93
94
* 原始字节包含从文件系统或网络装入的data
95
96
* defineClass管理JVM中许多复杂、神秘和依赖于实现的方面————
97
98
* ————它把字节码分析成运行时数据结构、校验有效性等。
99
100
*/
101
102
return defineClass(name, data, 0, data.length);
103
104
}
105
106
107
/**//*
108
109
* 将对应的Class文件读为byte[]
110
111
*/
112
113
public byte[] loadClassData(String name)
114
115

{
116
117
FileInputStream fis = null;
118
119
byte[] data = null;
120
121
try
122
123

{
124
125
//装载d:根目录下面的.class文件到data中
126
127
fis = new FileInputStream(new File(drive + name + fileType));
128
129
ByteArrayOutputStream baos = new ByteArrayOutputStream();
130
131
int ch = 0;
132
133
while ((ch = fis.read()) != -1)
134
135

{
136
137
baos.write(ch);
138
139
140
}
141
142
data = baos.toByteArray();
143
144
} catch (IOException e)
145
146

{
147
148
e.printStackTrace();
149
150
}
151
152
153
return data;
154
155
}
156
157
158
public static void main(String[] args) throws Exception
159
160

{
161
162
FileClassLoader loader = new FileClassLoader();
163
164
//装载类MyApp
165
166
Class objClass = loader.loadClass("MyApp", true);
167
168
//生成MyApp的一个实例
169
170
Object obj = objClass.newInstance();
171
172
//获得类的名称
173
174
System.out.println(objClass.getName());
175
176
//获得类的装载器的名称
177
178
System.out.println(objClass.getClassLoader());
179
180
}
181
182
}
183
posted on 2007-06-26 14:27
冰封的爱 阅读(256)
评论(0) 编辑 收藏 所属分类:
技术