Java类装入器什么时候启动?

Java类装入器什么时候启动?,java,classloader,Java,Classloader,有1000万篇关于Java类加载器是什么,以及如何/*为什么*编写自己的类加载器的文章和文档……但它们似乎都假设了一些我找不到简单答案的事情 我理解类加载器的工作:读取字节码并从中构造对象。不同的类加载器执行不同的操作,等等 但是,我从来没有在自己的代码中针对类加载器API编写过代码,也从来没有编写过自己的类加载器API,当类加载器的代码实际启动时,我在理解方面遇到了巨大的困难。 例如: public static void main(String[] args) { Fizz fizz

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

我理解类加载器的工作:读取字节码并从中构造对象。不同的类加载器执行不同的操作,等等

但是,我从来没有在自己的代码中针对类加载器API编写过代码,也从来没有编写过自己的类加载器API,当
类加载器的代码实际启动时,我在理解方面遇到了巨大的困难。

例如:

public static void main(String[] args) {
    Fizz fizz = new Fizz();
    fuzz.buzz();
}
这里,我们有一个
Fizz
对象。在实例化
Fizz
之前,我们需要一个类加载器来启动并将
Fizz.class
加载到它的缓存中这是在何时何地发生的它没有显式地出现在我的代码中,所以它必须隐式地出现在JRE


与这个问题相切的是,如果我编写自己的类加载器,比如说,
WidgetClassLoader
,并希望将其配置为加载所有应用程序的类,或者只加载我的
Fizz.class
,那么我如何将这个
WidgetClassLoader
绑定到我的应用程序中,以便它知道使用哪个类加载器?我的代码需要显式地调用这个类加载器,还是像第一个示例那样是隐式的?提前谢谢

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

当然,java仅在您首先将类加载器设置为默认类加载器(通过调用
Thread.currentThread().setContextClassLoader()
)或手动加载类(通过调用
loadClass()
)时才使用类加载器


我不确定什么时候调用类加载器。我认为它是在启动程序(在所有声明为
import
的类上)或在第一次使用类(变量声明或构造函数调用)时调用的。

您的问题并不像您现在想的那么简单

您的嘶嘶声示例: 什么时候有汽水?这是在中定义的。它没有定义何时加载Fizz,但它保证了可视行为。对于“when”部分,如果找不到Fizz,将从访问Fizz的第一条语句(Fizz-Fizz=new-Fizz())引发异常。我很确定它将是新的Fizz(),特别是在本例中,因为表达式的右侧首先被求值。如果你是这样写的:

Fizz fizz = null;
fizz = new Fizz();
在这种情况下,Fizz-Fizz=null已经抛出异常,因为它是对Fizz类的第一次访问

谁装汽水?当必须加载类时,使用“属于”需要该类的代码的类加载器来获取该类。在Fizz示例中,这将是用main方法加载类的类加载器。当然,如果类加载器不能自己加载Fizz,那么类加载器可以选择委托给其父类加载器


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

类的实际创建发生在
defineClass
中。该类是使用来自多个源中的任何一个的字节数组创建的

进入
定义类
(受
保护
)的正常路径是通过
findClass
(当然,它也受
保护
)。因此,通常的入口点是
loadClass
->
findClass
->
defineClass
。但对于特殊情况,还有其他途径


(整个过程非常复杂,代表了随着保护变得更加复杂和访问模式更加多样化而添加层的历史。)

如果您对类加载器以及它们的工作时间和工作方式感兴趣,您也可以查看—在我看来,这对您来说将是一本非常有趣的书。OSGi是一个Java框架,它提供模块化、清晰的代码分离和生命周期管理,目前非常流行(例如Eclipse本身就是基于OSGi的)


OSGi大量使用类加载器,并且有一个非常好的解释,说明了类加载在规范中何时以及如何发生。基本上,每个包都有一个单独的包类加载器(这就是模块的调用方式)这些类加载器负责处理依赖关系,并从另一个包中获取正确的类。

当然,它在JRE中。阅读本文,谷歌定制类加载器配置:@duffymo-请看我在安德烈回答下的评论-我有同样的问题要问你!我不认为有必要编写自己的类加载器。在我编写Java的整个过程中,一次也没有。这是从1997年的1.0开始的。是什么让你认为你需要它?我已经为一个用例编写了我自己的类加载器-我们有一个报告应用程序,我们交给我们的员工/分包商,这样他们就可以通过互联网进行报告。显然,我们希望能够更新它,并允许runni