(可怕的标题,我知道)
解释这一点的最好方法是,我需要加载一些将在运行时从 URLClassLoader 加载的类,因为这些类引用了系统类加载器已经加载的类的实例并且它们无法重新加载,因为的一些其他问题。
此外,我愿意更改我的代码,以便可以使用 System ClassLoader 从类路径中的 jar 加载类,但我无法做到这一点。
(可怕的标题,我知道)
解释这一点的最好方法是,我需要加载一些将在运行时从 URLClassLoader 加载的类,因为这些类引用了系统类加载器已经加载的类的实例并且它们无法重新加载,因为的一些其他问题。
此外,我愿意更改我的代码,以便可以使用 System ClassLoader 从类路径中的 jar 加载类,但我无法做到这一点。
不。每个类加载器都将引导类加载器作为祖先,尝试加载已经在类加载器中定义的类只会导致使用祖先的版本。这是为了防止java.lang.Object
和其他内在函数被重新定义。
该类
ClassLoader
使用委托模型来搜索类和资源。每个实例ClassLoader
都有一个关联的父类加载器。当请求查找类或资源时,ClassLoader
实例将在尝试查找类或资源本身之前将对该类或资源的搜索委托给其父类加载器。虚拟机的内置类加载器,称为“引导类加载器”,它本身没有父级,但可以作为ClassLoader
实例的父级。
您可能能够定义一个自定义类加载器,该类加载器在defineClass
不被调用的情况下公开findClass
并避免发生在 中的委托findClass
,但我不会依赖于defineClass(className, bytes)
在所有 JVM 上按预期工作(如果parent.findClass(className)
存在)。
是的,您可以定义另一个类加载器并加载该类。
根据规格
“在运行时,一个类或接口不仅仅由它的名称决定,而是由一对:它的完全限定名称和它的定义类加载器。每个这样的类或接口都属于一个运行时包。一个类的运行时包或接口由类或接口的包名和定义类加载器决定。 "
是的。但是你需要稍微小心,因为默认的父类加载器是系统类加载器,而不是引导类加载器。我建议使用java.net.URLClassLoader.newInstance(myURLs, null)
. 如果您想成为闪存,请从系统类加载器中获取父类加载器,这将包括扩展类。
(注意,术语有点扭曲,因为它可以追溯到 Java2 之前,当时类路径包含现在的引导类路径(安装程序很痛苦)。所以系统类不由系统类加载器加载。)