java.lang.Object java.lang.ClassLoader
public abstract class ClassLoader
类加载器是负责加载类的对象。ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。
每个 Class
对象都包含一个对定义它的 ClassLoader 的引用
。
数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建。数组类的类加载器由 Class.getClassLoader()
返回,该加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。
应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。
类加载器通常由安全管理器使用,用于指示安全域。
ClassLoader 类使用委托模型来搜索类和资源。每个 ClassLoader 实例都有一个相关的父类加载器。需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。虚拟机的内置类加载器(称为 "bootstrap class loader")本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。
通常情况下,Java 虚拟机以与平台有关的方式,从本地文件系统中加载类。例如,在 UNIX 系统中,虚拟机从 CLASSPATH 环境变量定义的目录中加载类。
然而,有些类可能并非源自一个文件;它们可能源自其他来源(如网络),也可能是由应用程序构造的。defineClass
方法将一个 byte 数组转换为 Class 类的实例。这种新定义的类的实例可以使用 Class.newInstance
来创建。
类加载器所创建对象的方法和构造方法可以引用其他类。为了确定引用的类,Java 虚拟机将调用最初创建该类的类加载器的 loadClass
方法。
例如,应用程序可以创建一个网络类加载器,从服务器中下载类文件。示例代码如下所示:
ClassLoader loader = new NetworkClassLoader(host, port); Object main = loader.loadClass("Main", true).newInstance(); . . .
网络类加载器子类必须定义方法 findClass
和 loadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法 defineClass
来创建类实例。示例实现如下:
class NetworkClassLoader extends ClassLoader { String host; int port; public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection . . . } }
按照《Java Language Specification》的定义,任何作为 String
类型参数传递给 ClassLoader 中方法的类名称都必须是一个二进制名称。
有效类名称的示例包括:
"java.lang.String" "javax.swing.JSpinner$DefaultEditor" "java.security.KeyStore$Builder$FileBuilder$1" "java.net.URLClassLoader$3$1"
resolveClass(Class)
构造方法摘要 | |
---|---|
protected |
ClassLoader() 使用方法 getSystemClassLoader() 返回的 ClassLoader 创建一个新的类加载器,将该加载器作为父类加载器。 |
protected |
ClassLoader(ClassLoader parent) 使用指定的、用于委托操作的父类加载器创建新的类加载器。 |
方法摘要 | |
---|---|
void |
clearAssertionStatus() 将此类加载器的默认断言状态设置为 false,并放弃与此类加载器关联的所有默认包或类断言状态设置。 |
protected Class<?> |
defineClass(byte[] b, int off, int len) 已过时。 由 defineClass(String, byte[], int, int) 取代 |
protected Class<?> |
defineClass(String name, byte[] b, int off, int len) 将一个 byte 数组转换为 Class 类的实例。 |
protected Class<?> |
defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) 使用可选的 ProtectionDomain 将一个 byte 数组转换为 Class 类的实例。 |
protected Class<?> |
defineClass(String name, ByteBuffer b, ProtectionDomain protectionDomain) 使用可选的 ProtectionDomain 将 ByteBuffer 转换为 Class 类的实例。 |
protected Package |
definePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) 根据 name 在此 ClassLoader 中定义包。 |
protected Class<?> |
findClass(String name) 使用指定的二进制名称查找类。 |
protected String |
findLibrary(String libname) 返回本机库的绝对路径名。 |
protected Class<?> |
findLoadedClass(String name) 如果 Java 虚拟机已将此加载器记录为具有给定二进制名称的某个类的启动加载器,则返回该二进制名称的类。 |
protected URL |
findResource(String name) 查找具有给定名称的资源。 |
protected Enumeration<URL> |
findResources(String name) 返回表示所有具有给定名称的资源的 URL 对象的枚举。 |
protected Class<?> |
findSystemClass(String name) 查找具有指定的二进制名称的类,必要时加载它。 |
protected Package |
getPackage(String name) 返回由此类加载器或其任何祖先所定义的 Package。 |
protected Package[] |
getPackages() 返回此类加载器及其祖先所定义的所有 Package。 |
ClassLoader |
getParent() 返回委托的父类加载器。 |
URL |
getResource(String name) 查找具有给定名称的资源。 |
InputStream |
getResourceAsStream(String name) 返回读取指定资源的输入流。 |
Enumeration<URL> |
getResources(String name) 查找所有给定名称的资源。 |
static ClassLoader |
getSystemClassLoader() 返回委托的系统类加载器。 |
static URL |
getSystemResource(String name) 从用来加载类的搜索路径中查找具有指定名称的资源。 |
static InputStream |
getSystemResourceAsStream(String name) 从用来加载类的搜索路径打开具有指定名称的资源,以读取该资源。 |
static Enumeration<URL> |
getSystemResources(String name) 从用来加载类的搜索路径中查找所有具有指定名称的资源。 |
Class<?> |
loadClass(String name) 使用指定的二进制名称来加载类。 |
protected Class<?> |
loadClass(String name, boolean resolve) 使用指定的二进制名称来加载类。 |
protected void |
resolveClass(Class<?> c) 链接指定的类。 |
void |
setClassAssertionStatus(String className, boolean enabled) 设置在此类加载器及其包含的嵌套类中指定的最高层类所需的断言状态。 |
void |
setDefaultAssertionStatus(boolean enabled) 设置此类加载器的默认断言状态。 |
void |
setPackageAssertionStatus(String packageName, boolean enabled) 为指定包设置默认断言状态。 |
protected void |
setSigners(Class<?> c, Object[] signers) 设置类的签署者。 |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
构造方法详细信息 |
---|
protected ClassLoader(ClassLoader parent)
如果存在安全管理器,则调用其 checkCreateClassLoader
方法。这可能导致安全性异常。
parent
- 父类加载器
SecurityException
- 如果存在安全管理器并且其
checkCreateClassLoader 方法不允许创建新的类加载器。
protected ClassLoader()
getSystemClassLoader()
返回的
ClassLoader 创建一个新的类加载器,将该加载器作为父类加载器。
如果存在安全管理器,则调用其 checkCreateClassLoader
方法。这可能导致安全性异常。
SecurityException
- 如果存在安全管理器并且其
checkCreateClassLoader 方法不允许创建新的类加载器。
方法详细信息 |
---|
public Class<?> loadClass(String name) throws ClassNotFoundException
loadClass(String, boolean)
方法相同的方式搜索类。Java 虚拟机调用它来分析类引用。调用此方法等效于调用
loadClass(name, false)
。
name
- 类的
二进制名称
ClassNotFoundException
- 如果没有找到类
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
调用 findLoadedClass(String)
来检查是否已经加载类。
在父类加载器上调用 loadClass
方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。
调用 findClass(String)
方法查找类。
如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class)
方法。
鼓励用 ClassLoader 的子类重写 findClass(String)
,而不是使用此方法。
name
- 类的
二进制名称
resolve
- 如果该参数为
true,则分析这个类
ClassNotFoundException
- 如果无法找到类
protected Class<?> findClass(String name) throws ClassNotFoundException
loadClass
方法调用。默认实现抛出一个
ClassNotFoundException。
name
- 类的
二进制名称
ClassNotFoundException
- 如果无法找到类
@Deprecated protected final Class<?> defineClass(byte[] b, int off, int len) throws ClassFormatError
defineClass(String, byte[], int, int)
取代
b
- 组成类数据的字节。
off 与
off+len-1 之间的字节应该具有《
Java Virtual Machine Specification》定义的有效类文件的格式。
off
- 类数据的
b 中的起始偏移量
len
- 类数据的长度
ClassFormatError
- 如果数据不包含有效类
IndexOutOfBoundsException
- 如果
off 或
len 为负,或者
off+len 大于
b.length。
loadClass(String, boolean)
,
resolveClass(Class)
protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError
此方法将默认的 ProtectionDomain
分配给新定义的类。调用 Policy.getPolicy().getPermissions(new CodeSource(null, null))
时,ProtectionDomain 被有效授予所返回的相同权限集。默认域在第一次调用 defineClass
时创建,并在后续调用时被重用。
要将特定的 ProtectionDomain 分配给类,需要使用 defineClass
方法,该方法将 ProtectionDomain 用作其参数之一。
name
- 所需要的类的
二进制名称,如果不知道此名称,则该参数为
null
b
- 组成类数据的字节。
off 与
off+len-1 之间的字节应该具有《
Java Virtual Machine Specification》定义的有效类文件的格式。
off
- 类数据的
b 中的起始偏移量
len
- 类数据的长度
ClassFormatError
- 如果数据不包含有效类
IndexOutOfBoundsException
- 如果
off 或
len 为负,或者
off+len 大于
b.length。
SecurityException
- 如果试图将此类添加到包含由不同证书集签名的类(而不是此类,此类未签名)的包中,或者
name 以 "
java." 开头。
loadClass(String, boolean)
,
resolveClass(Class)
,
CodeSource
,
SecureClassLoader
protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError
defineClass(String, byte[], int, int)
的文档中指定的类。这个类必须分析后才能使用。
包中定义的第一个类确定在该包中定义的所有后续类必须包含的证书的确切集合。从该类的 ProtectionDomain 中的 CodeSource
可以获得类的证书集合。添加到该包中的任何类都必须包含相同的证书集合,否则抛出 SecurityException 异常。注意,如果 name 为 null,则不执行该检查。应该始终传入要定义的类的二进制名称以及字节。这可确保定义该类的正确性。
指定的 name 不能以 "java." 开头,因为 "java.*" 包中的所有类都只能由引导类加载器定义。如果 name 不是 null,则它必定等于由 byte 数组 "b" 指定的类的二进制名称,否则将抛出 NoClassDefFoundError。
name
- 所需类的
二进制名称,如果不知道此名称,则该参数为
null
b
- 组成类数据的字节。从
off 到
off+len-1 的字节应该具有由《
Java Virtual Machine Specification》定义的有效类文件的格式。
off
- 类数据的
b 中的起始偏移量
len
- 类数据的长度
protectionDomain
- 类的 ProtectionDomain
ClassFormatError
- 如果数据不包含有效的类
NoClassDefFoundError
- 如果
name 不等于
b 指定的类的
二进制名称。
IndexOutOfBoundsException
- 如果
off 或者
len 为负,或者
off+len 大于
b.length。
SecurityException
- 如果试图将此类添加到某个包中,而这个包中包含由不同证书集合(而不是该类)签名的类,或者
name 以 "
java." 开头。
protected final Class<?> defineClass(String name, ByteBuffer b, ProtectionDomain protectionDomain) throws ClassFormatError
ByteBuffer
转换为
Class 类的实例。如果该域为
null,则将默认域分配给
defineClass(String, byte[], int, int)
的文档中指定的类。这个类必须分析后才能使用。
有关包中定义的第一个类(它确定了包的证书集合)的规则,以及对类名称的限制,都与 defineClass(String, byte[], int, int, ProtectionDomain)
的文档中指定的相同。
调用形式为 cl.defineClass(name, bBuffer, pd) 的此方法所产生的结果与以下语句产生的结果相同
...
byte[] temp = new byte[ bBuffer .remaining
()];
bBuffer .get
(temp);
return
cl.defineClass
( name , temp, 0, temp.length, pd );
name
- 所需要的类的
二进制名称,如果不知道此名称,则该参数为
null
b
- 组成类数据的字节。从
b.position 到
b.position() + b.limit() -1 的字节应该具有由《
Java Virtual Machine Specification》定义的有效类文件的格式。
protectionDomain
- 类的 ProtectionDomain,或为
null。
ClassFormatError
- 如果数据不包含有效的类。
NoClassDefFoundError
- 如果
name 不等于
b 指定的类的
二进制名称。
SecurityException
- 如果试图将此类添加到某个包中,而这个包中包含由不同证书集合(而不是该类)签名的类,或者
name 以 "
java." 开头。
defineClass(String, byte[], int, int, ProtectionDomain)
protected final void resolveClass(Class<?> c)
c
- 要链接的类
NullPointerException
- 如果
c 为
null。
defineClass(String, byte[], int, int)
protected final Class<?> findSystemClass(String name) throws ClassNotFoundException
此方法通过系统类加载器(参见 getSystemClassLoader()
)来加载该类。返回的 Class 对象具有多个与之相关联的 ClassLoader。ClassLoader 的子类通常不必调用此方法,因为大多数类加载器只需重写 findClass(String)
即可。
name
- 类的
二进制名称
ClassNotFoundException
- 如果找不到类
ClassLoader(ClassLoader)
,
getParent()
protected final Class<?> findLoadedClass(String name)
name
- 类的
二进制名称
protected final void setSigners(Class<?> c, Object[] signers)
c
-
Class 对象
signers
- 类的签署者
public URL getResource(String name)
资源名称是以 '/' 分隔的标识资源的路径名称。
此方法首先搜索资源的父类加载器;如果父类加载器为 null,则搜索的路径就是虚拟机的内置类加载器的路径。如果搜索失败,则此方法将调用 findResource(String)
来查找资源。
name
- 资源名称
public Enumeration<URL> getResources(String name) throws IOException
资源名称是以 '/' 分隔的标识资源的路径名称。
getResource(String)
的文档中描述了搜索顺序。
name
- 资源名称
URL
对象的枚举。如果找不到资源,则该枚举将为空。类加载器无权访问的资源不在此枚举中。
IOException
- 如果发生 I/O 错误
findResources(String)
protected URL findResource(String name)
name
- 资源名称
protected Enumeration<URL> findResources(String name) throws IOException
URL
对象的枚举。类加载器实现应该重写此方法,以指定从何处加载资源。
name
- 资源名称
URL
对象的枚举
IOException
- 如果发生 I/O 错误
public static URL getSystemResource(String name)
getSystemClassLoader()
)来查找资源。
name
- 资源名称
URL
对象,如果找不到资源,则返回
null
public static Enumeration<URL> getSystemResources(String name) throws IOException
URL
对象的
Enumeration
返回。
getSystemResource(String)
的文档中描述了搜索顺序。
name
- 资源名称
URL
对象的枚举
IOException
- 如果发生 I/O 错误
public InputStream getResourceAsStream(String name)
getResource(String)
的文档中描述了搜索顺序。
name
- 资源名称