当第一次使用 class 时,jvm 如何检查 class 是否已加载
How jvm checks a class is loaded or not when a class is used first time
问题
当 jvm 运行以下代码时
MyObject o=new MyObject() //first access MyObject
我们知道 jvm 将开始加载 class MyObject,但我想知道 jvm 是如何知道 MyObject 未加载的。
动机
我想知道,因为如果 jvm 运行这些代码
public class Main{
public static void main(){
ClassLoader myLoader = new ClassLoader(null) {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// omitted here
}
}
myLoader.loadClass("MyObject"); //#1
MyObject o=new MyObject() //#2
}
}
我们知道,如果没有#1,MyObject 将由 class Main 的 classloader 加载,但是如果有 #1,MyObject 的 class 将在 #2 加载,并且jvm 是如何做出判断的?
每个 ClassLoader
都保留一份 class 目前已加载的列表。
如果两个不同的 ClassLoader
加载同名的 class,运行时会将它们视为两个独立的不相关的 class。这很有用,因为它允许相同 class 的不同版本在运行时共存。例如,我们可以将不同团队开发的多个 Web 应用程序部署到同一个 JVM 中,每个应用程序都有自己的库,从而使各个应用程序的开发人员无需协调他们使用的库的版本。
在您的情况下,如果我们在 class Main
中执行 new MyObject()
,将询问加载 class Main
的 class 加载程序加载 class MyObject
。那就是系统 ClassLoader
,它对您的 myLoader
一无所知。因此,系统class加载器将再次加载classMyObject
。
您可以通过向 MyObject 添加静态初始值设定项来验证这一点:
class MyObject {
static {
System.out.println("class MyObject has been loaded");
}
}
问题
当 jvm 运行以下代码时
MyObject o=new MyObject() //first access MyObject
我们知道 jvm 将开始加载 class MyObject,但我想知道 jvm 是如何知道 MyObject 未加载的。
动机
我想知道,因为如果 jvm 运行这些代码
public class Main{
public static void main(){
ClassLoader myLoader = new ClassLoader(null) {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// omitted here
}
}
myLoader.loadClass("MyObject"); //#1
MyObject o=new MyObject() //#2
}
}
我们知道,如果没有#1,MyObject 将由 class Main 的 classloader 加载,但是如果有 #1,MyObject 的 class 将在 #2 加载,并且jvm 是如何做出判断的?
每个 ClassLoader
都保留一份 class 目前已加载的列表。
如果两个不同的 ClassLoader
加载同名的 class,运行时会将它们视为两个独立的不相关的 class。这很有用,因为它允许相同 class 的不同版本在运行时共存。例如,我们可以将不同团队开发的多个 Web 应用程序部署到同一个 JVM 中,每个应用程序都有自己的库,从而使各个应用程序的开发人员无需协调他们使用的库的版本。
在您的情况下,如果我们在 class Main
中执行 new MyObject()
,将询问加载 class Main
的 class 加载程序加载 class MyObject
。那就是系统 ClassLoader
,它对您的 myLoader
一无所知。因此,系统class加载器将再次加载classMyObject
。
您可以通过向 MyObject 添加静态初始值设定项来验证这一点:
class MyObject {
static {
System.out.println("class MyObject has been loaded");
}
}