为什么第一次调用 loadClass 方法时这个引用是 AppClassLoader 而不是 MyClassLoader
why this reference is AppClassLoader rather than MyClassLoader when invoke loadClass method at the first time
我通过扩展 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
中loadClass方法的代码段
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 也就是说 this 引用是 sun.misc.Launcher$AppClassLoader 而不是com.classLoader.MyClassLoader@xxxxxx.
我通过互联网和博客搜索 define own classLoader 告诉
it will set AppClassLoader
as parent of MyClassLoader
in default constructor.
我通过
查看
System.out.println(myClassLoader.getParent());
找到 MyClassLoader 的父级确实是 AppClassLoader 它是如何实现的,我的默认构造函数什么都不做,这是在 其父class的构造方法 ClassLoader?我阅读了它的父构造函数,但仍然无法弄清楚。
无论如何,这似乎无法解释为什么 this 是 AppClassLoader 而不是 MyClassLoader我们首先调用 loadClass 方法。
我想这是因为 *MyClassLoader 的 classLoader 是 AppClassLoader
但这只是我没有要点的直觉。
万事如意。
嗯,都记录在案了:
ClassLoader()
constructor:
Creates a new class loader using the ClassLoader
returned by the method getSystemClassLoader()
as the parent class loader.
loadClass(String)
:
Loads the class with the specified binary name. … Invoking this method is equivalent to invoking loadClass(name, false)
.
loadClass(String,boolean-)
:
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
- Invoke
findLoadedClass(String)
to check if the class has already been loaded.
- Invoke the
loadClass
method on the parent class loader. If the parent is null
the class loader built-in to the virtual machine is used, instead.
- Invoke the
findClass(String)
method to find the class.
If the class was found using the above steps, and the resolve
flag is true, this method will then invoke the resolveClass(Class)
method on the resulting Class
object.
Subclasses of ClassLoader
are encouraged to override findClass(String)
, rather than this method.
这个在class documentation of ClassLoader
中也有提到:
The ClassLoader
class uses a delegation model to search for classes and resources. Each instance of ClassLoader
has an associated parent class loader. When requested to find a class or resource, a ClassLoader
instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader
instance.
这个逻辑确保干净的范围,即父范围的 class 不引用子范围的 class,并且 class 之间没有冲突具有相同限定名称的 es,但由不同的 class 加载器定义。这样的 classes 可能仍然存在于不同的范围内,但不存在于嵌套范围内。但是 class 加载器并没有强制遵循这个规则。 Java2.
引入了委派模型
我通过扩展 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 也就是说 this 引用是 sun.misc.Launcher$AppClassLoader 而不是com.classLoader.MyClassLoader@xxxxxx.
我通过互联网和博客搜索 define own classLoader 告诉
it will set
AppClassLoader
as parent ofMyClassLoader
in default constructor.
我通过
查看System.out.println(myClassLoader.getParent());
找到 MyClassLoader 的父级确实是 AppClassLoader 它是如何实现的,我的默认构造函数什么都不做,这是在 其父class的构造方法 ClassLoader?我阅读了它的父构造函数,但仍然无法弄清楚。
无论如何,这似乎无法解释为什么 this 是 AppClassLoader 而不是 MyClassLoader我们首先调用 loadClass 方法。
我想这是因为 *MyClassLoader 的 classLoader 是 AppClassLoader
但这只是我没有要点的直觉。
万事如意。
嗯,都记录在案了:
ClassLoader()
constructor:
Creates a new class loader using the
ClassLoader
returned by the methodgetSystemClassLoader()
as the parent class loader.
loadClass(String)
:
Loads the class with the specified binary name. … Invoking this method is equivalent to invoking
loadClass(name, false)
.
loadClass(String,boolean-)
:
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
- Invoke
findLoadedClass(String)
to check if the class has already been loaded.- Invoke the
loadClass
method on the parent class loader. If the parent isnull
the class loader built-in to the virtual machine is used, instead.- Invoke the
findClass(String)
method to find the class.If the class was found using the above steps, and the
resolve
flag is true, this method will then invoke theresolveClass(Class)
method on the resultingClass
object.Subclasses of
ClassLoader
are encouraged to overridefindClass(String)
, rather than this method.
这个在class documentation of ClassLoader
中也有提到:
The
ClassLoader
class uses a delegation model to search for classes and resources. Each instance ofClassLoader
has an associated parent class loader. When requested to find a class or resource, aClassLoader
instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of aClassLoader
instance.
这个逻辑确保干净的范围,即父范围的 class 不引用子范围的 class,并且 class 之间没有冲突具有相同限定名称的 es,但由不同的 class 加载器定义。这样的 classes 可能仍然存在于不同的范围内,但不存在于嵌套范围内。但是 class 加载器并没有强制遵循这个规则。 Java2.
引入了委派模型