Java 类装入器何时参与?

2022-09-03 02:44:16

有1000万篇文章和文档是关于Java类加载器是什么以及如何/*为什么*编写自己的...但他们似乎都在假设一些我找不到简单答案的事情!

我理解类装入器的工作:读取字节码并从中构造一个对象。不同的类加载器以不同的方式执行此操作,等等。

但是,由于我从来不需要在自己的代码中针对类加载器 API 进行编码,也不必编写自己的代码,因此我很难理解 ClassLoader 自己的代码何时实际触发。

例如:

public static void main(String[] args) {
    Fizz fizz = new Fizz();
    fuzz.buzz();
}

在这里,我们有一个对象。在实例化 之前,我们需要一个类装入器来启动并加载到其缓存中。这种情况在何时何地发生?!?!它在我的代码中没有显式显示,所以它必须隐式地存在于JRE中的某个地方...?FizzFizzFizz.class

与这个问题相关的是,如果我编写自己的类加载器,例如,并希望将其配置为加载我应用程序的所有类,或者只是我的类,我如何将其“绑定”到我的应用程序中,以便它知道要使用哪个类加载器?我的代码是否需要显式调用此类加载器,还是像第一个示例一样是隐式的?提前致谢!WidgetClassLoaderFizz.classWidgetClassLoader


答案 1

你的问题并不像你现在想象的那么微不足道。

您的 Fizz 示例:何时加载 Fizz?这在JLS(第5.4章:链接)中定义。它没有定义Fizz何时加载,但它保证了可见的行为。对于“何时”部分,如果找不到Fizz,将从访问Fizz的第一个语句中引发异常(Fizz fizz = new Fizz())。我很确定在这种情况下,它将是新的Fizz(),因为首先评估表达式的右侧。如果你这样写:

Fizz fizz = null;
fizz = new Fizz();

在这种情况下,Fizz fizz = null 已经抛出 Exception,因为它是对 Fizz 类的第一次访问。

谁加载嘶嘶声?当必须装入类时,“属于”需要该类的代码的类装入器用于获取该类。在 Fizz 示例中,这将是使用 main 方法加载类的类装入器。当然,如果类装入器无法自行装入 Fizz,则它可以选择委托给其父类装入器。

如何让 JVM 使用我的类加载器?有两种方式,显式或隐式。显式地:您可以通过调用类的方法通过自己的类装入器来装入该类。Implcitly:当您从已经从类装入器装入的类执行代码(即方法或初始值设定项)并且需要在进程中解析类引用时,将自动使用类装入器,因为它是首先装入代码的类装入器。


答案 2

Java 有一个缺省的类装入器。这将在默认类路径中查找类声明。如果您编写自己的类装入器,则可以(并且应该)设置父类装入器。如果没有其他人,这将是默认设置。如果不这样做,你的类装入器将无法找到java API类。如果java寻找一个类,它不会开始寻找你的自定义类装入器,而是用父类装入器。如果这个有一个父级,它从那里开始,依此类推。仅当找不到某个类时,才会使用下一个子类装入器重试。同样,只要有孩子,这种情况就会继续下去。如果链中的任何加载器都找不到该类,则抛出 a。ClassNotFoundException

当然,Java只有在您首先将其设置为缺省类装入器(通过调用)或手动装入类(通过调用)时才使用类装入器。Thread.currentThread().setContextClassLoader()loadClass()

我不确定何时调用类装入器。我认为它是在启动programm(在所有声明为的类上)或首次使用类(变量声明或构造函数调用)时调用的。import


推荐