我通过扩展classLoader
并覆盖其 findClass 方法来编写myOwnClassLoader。并遇到一个有趣的问题:
以下是代码段:
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> findClass(String name) {
byte[] bt = loadClassData(name);
return defineClass(name, bt, 0, bt.length);
}
private byte[] loadClassData(String className) {
...
}
public static void main(String[] args) throws ClassNotFoundException{
MyClassLoader myClassLoader = new MyClassLoader();
//Class<?> clazz = myClassLoader.findClass("com.classLoader.BMW");
Class<?> clazz = myClassLoader.loadClass("com.classLoader.BMW");
System.out.println(clazz.getClassLoader());//////////////////
}
}
执行时
Class<?> clazz = myClassLoader.findClass("com.classLoader.BMW");
输出满足我的期望: 的输出:
com.classLoader.MyClassLoader@xxxxxx
执行时但
Class<?> clazz = myClassLoader.loadClass("com.classLoader.BMW");
输出超出了我的想法: 的输出:
sun.misc.Launcher$AppClassLoader@xxxx
期望输出
com.classLoader.MyClassLoader@xxxxxx
这是ClassLoader
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
.....
我调试它并找到我们在 第一次 时调用loadClass
时父母 sun.misc.Launcher$ExtClassLoader@6aa8ceb6 < / strong>也就是说此引用是 sun.misc.Launcher $ AppClassLoader 而不是 com.classLoader.MyClassLoader@xxxxxx 。
我通过互联网和博客搜索define own classLoader告诉
它会将
AppClassLoader
设置为默认构造函数中MyClassLoader
的父级。
我通过
检查System.out.println(myClassLoader.getParent());
找到 MyClassLoader的父确实是 AppClassLoader 它是如何实现这一点的,我的默认构造函数什么都不做,这是在构造函数方法中实现的它的父类 ClassLoader ?我读了它的父构造函数,仍然无法解决。
无论如何,当我们第一次调用 loadClass 时,似乎无法解释为什么这个是 AppClassLoader 而不是 MyClassLoader 方法。
我想这是因为* MyClassLoader的classLoader是AppClassLoader
,但这只是一种我没有根据的直觉。
。一切都将受到赞赏。
答案 0 :(得分:0)
嗯,这些都记录在案:
ClassLoader()
constructor:
使用方法
ClassLoader
返回的getSystemClassLoader()
作为父类加载器创建新的类加载器。
loadClass(String)
:
使用指定的二进制名称加载类。 ...调用此方法相当于调用
loadClass(name, false)
。
loadClass(String,boolean-)
:
使用指定的二进制名称加载类。此方法的默认实现按以下顺序搜索类:
- 调用
findLoadedClass(String)
以检查该类是否已加载。- 在父类加载器上调用
loadClass
方法。如果父级是null
,则使用内置于虚拟机的类加载器。- 调用
醇>findClass(String)
方法查找班级。如果使用上述步骤找到该类,并且
resolve
标志为true,则此方法将在生成的resolveClass(Class)
对象上调用Class
方法。鼓励
ClassLoader
的子类覆盖findClass(String)
,而不是此方法。
class documentation of ClassLoader
中也提到了这一点:
ClassLoader
类使用委派模型来搜索类和资源。ClassLoader
的每个实例都有一个关联的父类加载器。当请求查找类或资源时,ClassLoader
实例会在尝试查找类或资源本身之前将对类或资源的搜索委托给其父类加载器。虚拟机的内置类加载器(称为“引导类加载器”)本身不具有父级,但可以作为ClassLoader
实例的父级。
此逻辑确保干净的作用域,即父作用域的类不引用子作用域的类,并且同一限定名的类之间没有冲突,但是由不同的类加载器定义。此类可能仍存在于不同的范围中,但不存在于嵌套范围中。但类加载器并未强制遵循此规则。委托模型是用Java 2引入的。