我正在学习加载java类的过程,遇到了一些困惑。
我知道在加载 java 类 时,current classLoader 不会直接加载 java 类,它会委托(delegate)给它的 parent classLoader(一个递归过程)直到它的父类无法加载这个类。
问题是:当前的classLoader是什么? Bootstrap?扩大?应用?
如何获取当前的classLoader?
我知道有一个 API:
xxx.Class.getClassLoader();
但我不确定返回值是否是currentClassLoader。我认为实际上应该是加载这个 java 类 的 classLoader。
为了更详细地描述我的问题,我将举一个例子。
我在博客中得到以下内容。
ThreadContextClassLoader is used to deal with java SPI, Interface is defined in java
core lib
and loaded by Bootstrap ClassLoader and third party implement these interface then the jar are loaded by AppClassLoader
Solution: traditional classLoader cant deal with this case,because it cant discovery the third party jar when we use the third party implement in core lib.
我能理解上面的大部分内容,但解决方案让我感到困惑:
例如,接口(interface) CoreA 和类 CoreB 在 java core lib
中,应该由 Bootstrap ClassLoader 加载,并且AImpl 是第三方对 A 的实现,应该由 AppClass 加载器 加载。
代码段如下:
public Interface CoreA{
void add();
}
public Interface AImpl implements CoreA{
void add(){};
}
public class B{
public void demo(){
a = new AImpl();
}
}
那么如果我们在main方法
中引用B
,那么我们将加载B
,因为类加载器 B
是Bootstrap那么关于AImpl
当前的Loader是Bootstrap所以找不到?
不知道是不是我猜的那样?
任何建议将不胜感激。
最佳答案
一般来说你是对的,是找不到的。让我向您展示以下示例。假设我们有 3 个类:A
, B
和 Main
像这样:
public class A {
public String a() {
return "a";
}
}
public class B {
public String b() {
return new A().a();
}
}
public class Main {
public static void main(String... args) {
System.out.println(new B().b());
}
}
然后我们将这些类打包到对应的 jar 中:a.jar
, b.jar
并放置 Main.class
进入工作目录。之后让我们测试以下场景:
1) 所有内容( A.class
, B.class
, Main.class
)都由 system classloader
加载并且工作正常:
$ java -cp .:a.jar:b.jar Main
a
2) B.class
由 system classloader
加载和 A.class
由 bootstrap classloader
加载一切仍然正常,因为 system classloader
代表正在加载到 bootstrap classloader
(仅仅因为 bootstrap classloader
可以加载它):
$ java -Xbootclasspath/a:a.jar -cp .:b.jar Main
a
3) A.class
由 system classloader
加载和 B.class
由 bootstrap classloader
加载(你的情况)。在这种情况下,在加载 B.class
期间当前类加载器是 bootstrap classloader
, 但找不到 B.class
失败了:
$ java -Xbootclasspath/a:b.jar -cp .:a.jar Main
Exception in thread "main" java.lang.NoClassDefFoundError: A
at B.b(B.java:4)
at Main.main(Main.java:4)
让我们更仔细地看一下最后一个例子。这里发生了什么:
尝试使用
public static main(String[] args)
查找类方法1.1。
system classloader
还没有加载它所以委托(delegate)给extension classloader
1.2。
extension classloader
还没有加载它所以委托(delegate)给bootstrap classloader
1.3。
bootstrap classloader
尚未加载并尝试加载,它无法加载并将控制权返回给extension classloader
1.4。
extension classloader
尝试加载,它无法加载并将控制权返回给system classloader
1.5。
system classloader
负载Main.class
Main.class
已处理,我们尝试加载B.class
使用当前类加载器system classloader
2.1。
system classloader
还没有加载它所以委托(delegate)给extension classloader
2.2。
extension classloader
还没有加载它所以委托(delegate)给bootstrap classloader
2.3。
bootstrap classloader
尚未加载并加载B.class
B.class
已处理,我们尝试加载A.class
使用当前类加载器bootstrap classloader
3.1。
bootstrap classloader
还没有加载它并尝试加载和 失败
希望对您有所帮助。
关于java - 我怎么知道java中当前的classLoader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41102617/