如何在 JVM 中多次加载 java.util.TimeZone

How to load java.util.TimeZone more then once in JVM

我创建自定义 class 加载器:

new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());

其中 urls 是 new Url("java.util.TimeZone")

之后我按名称加载 class :

Class<?> newTimeZoneClass = loader.loadClass("java.util.TimeZone");

newTimeZoneClass==TimeZone.classreturnstrue

我的 class 加载器从父加载器加载 class 的主要原因。 如何解决?

public URLClassLoader(URL[] urls, ClassLoader parent): Java 文档中所述

Constructs a new URLClassLoader for the given URLs. The URLs will be searched in the order specified for classes and resources after first searching in the specified parent class loader.

我假设您应该创建一个 CustomClassLoader ccl = new CustomClassLoader(); 或通过传递 AccessControlContext 对象使用另一个构造函数 - URLClassLoader(URL[] urls, ClassLoader parent, AccessControlContext acc)URLClassLoader(URL[] urls, AccessControlContext acc).

有一些关于创建新的 class 加载器的文章:

https://www.baeldung.com/java-classloaders

https://www.javaworld.com/article/2077260/learn-java-the-basics-of-java-

https://www.oodlestechnologies.com/blogs/Creating-Custom-Class-Loader-In-JAVA/class-loaders.html

你不能这样做。 Java 安全模型阻止任何 class 加载程序在 "java.*" 层次结构中创建 class。这是 JVM 本机代码中的 hard-coded,因此没有解决方法。

此外,标准 class 加载器遵循委托模型,要求父 class 加载器在尝试加载 class 之前加载,所以你总是得到相同的 class实例。应用程序容器使用特殊的 class 加载程序来反转此委托以用于特定于应用程序的 classes。

无论如何,有几种方法可以做到这一点。

首先,TimeZone是一个抽象class,实际实现通常是sun.util.calendar.ZoneInfo。由于这不在 "java.*" 层次结构中,您可以在 class 加载器中创建多个副本。

其次,您可以 sub-class TimeZone,并将所有方法委托给 JVM 提供的实例,同时添加您自己的功能。我用它在我的一些应用程序中使 TimeZone 实例成为单例。

第三,由于JDK是开源的,您可以将TimeZone及其sub-class的所有代码复制到您自己的应用程序中,然后您就可以拥有class 多个版本随你喜欢。

如果您想更改 TimeZone 中静态方法返回的 TimeZone 个实例,这些委托给 ZoneInfo,您将不得不使用反射来更改结果。如果您知道 Aspect-J 或同等学历,您也可以拦截呼叫。