繁体   English   中英

Java类加载器何时参与?

[英]When do Java class loaders engage?

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

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

但是从来没有在我自己的代码中对类加载器API进行编码,而且从不必编写自己的代码,我很难理解ClassLoader自己的代码实际触发的时间。

例如:

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

在这里,我们有一个Fizz对象。 在可以实例化Fizz之前,我们需要一个类加载器来启动并将Fizz.class加载到其缓存中。 这种情况何时何地发生?!?! 它没有明确地出现在我的代码中所以它必须隐含在JRE中的某个地方......?

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

你的问题并不像你现在想象的那么简单。

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

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

在这种情况下,Fizz fizz = null将抛出异常,因为它是第一次访问Fizz类。

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

如何让JVM使用我的 ClassLoader? 有两种方式,明确或隐含。 明确地说:您可以通过调用其方法通过您自己的类加载器加载类。 Implcitly:当你从已经从类加载器加载的类中执行代码(意思是方法或初始化器)并且需要在进程中解析类引用时,你的类加载器将被自动使用,因为它是加载代码的类加载器第一名。

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

当然,如果你首先将它设置为默认类加载器(通过调用Thread.currentThread().setContextClassLoader() )或者手动加载类(通过调用loadClass() ),java只使用你的类加载器。

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

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

获取defineClassprotected )的正常路径是通过findClass (当然,它也protected )。 所以通常的入口点是loadClass - > findClass - > defineClass 但特殊情况还有其他途径。

(整个过程非常复杂,并且代表了添加层的历史,因为保护变得更加复杂,访问模式也变得更加多样化。)

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM