Java 类装入器 [已关闭]

2022-09-01 17:58:20

任何人都可以给我指出一个好的资源或向我解释类加载器背后的概念吗?我在类装入器上找到了以下资源 http://www.onjava.com/lpt/a/5586 但仍然没有任何帮助。以下问题可能看起来很愚蠢,但试图回答它们总是让我感到困惑。

  • 为什么开发人员编写自定义类装入器,为什么不调用 Bootstrap 类装入器来调用您的自定义类?定义自定义类装入器的需要是什么?

  • 为什么类装载机有这么多种类?例如:Bootsrap,Comman,Catalina类加载器等,

    提前致谢。


答案 1

我发现了以下创建自定义类装入器的正当理由:

  1. 您希望从非常规源加载类(例如,一个类的字节码存储在数据库中,通过网络或由 pidgeons 作为 0 和 1s 携带 - MessengerPidgeonClassLoader)。对于这种情况,API 中已经有一些 ClassLoader 实现,例如 URLClassLoader

  2. 您需要定义不同的层次结构来加载类。ClassLoader 的默认实现首先将搜索委托给父级,然后尝试自己加载类。也许你想要一个不同的层次结构。这就是为什么OSGI和Eclipse有自己的ClassLoaders作为Manifest的原因。MF文件定义了所有类型的奇怪的层次结构路径(例如,伙伴类加载)。所有 Eclipse 类加载器都实现了 BundleClassLoader 接口,并有一些额外的代码来查找 Eclipse 插件中的资源。

  3. 您需要对字节码进行一些修改。也许字节码是加密的,你会动态地取消加密它(并不是说它有帮助,真的,但已经尝试过)。也许你想“修补”动态加载的类(A la JDO字节码增强功能)。

如果您需要从内存中卸载类,或者需要装入类,而不是在运行时更改其定义,则需要使用与系统类装入器不同的类装入器。例如,一个典型的情况是,应用程序从 XML 文件动态生成一个类,然后尝试重新加载此类。一旦类位于系统类装入器中,就无法卸载它并具有新的定义。


答案 2

类装入器的常见用途是隔离 JAR。如果你有一个使用插件的应用程序(EclipseMaven 2),那么你可能会遇到这种情况:插件X需要1.0版的jar A,而插件Y需要相同的jar,但版本2.0。但是,X 不能在 2.0 版中运行。

如果你有类装入器,你可以创建类的分区(想想由细桥连接的孤立岛;桥是类装入器)。这样,类加载器可以控制每个插件可以看到的内容。

当插件X实例化具有静态字段的类Foo时,这没有问题,并且不会与插件Y中的“相同”类混淆,因为每个类加载器实际上都会创建自己的类Foo实例。然后,内存中有两个类,其中是,但不是。这意味着 cl1 的实例与 cl2 的实例不兼容。这可能会导致奇怪的说,无法分配给 .cl1.getName().equals(cl2.getName())truecl1.equals(cl2)ClassCastExceptionsorg.project.Fooorg.project.Foo

就像偏远的岛屿一样,这两个类都不知道另一个类的存在。想想人类克隆,它们在不同的岛屿上出生和长大。从 VM 的角度来看,没有问题,因为 Class 类型的实例的处理方式与任何其他对象类似:可以有多个实例。你认为其中一些是“相同的”对 VM 并不重要。

此模式的另一个用途是,您可以摆脱以这种方式加载的类:只需确保没有人有指向从类装入器装入的类创建的任何对象的指针,然后也忘记类装入器。在下一次运行 GC 时,将从内存中删除由此类装入器装入的所有类。这样,您就可以“重新加载”应用程序,而无需重新启动整个 VM。


推荐