getclassannotation 方法返回一个表示基本代码 url 路径的 string,远程方应使用该路径下载指定类的定义。返回的字符串的格式是一个由空格分隔的 url 路径。
返回的基本代码字符串取决于指定类的定义类加载器:
- 如果类加载器是系统类加载器(请参阅
classloader.getsystemclassloader())、系统类加载器的父级(如,用于安装扩展的加载器) 或引导类加载器(可以用 null 表示),则返回 java.rmi.server.codebase 属性的值(或可能是一个原先的缓存值);如果未设置该属性,则返回 null。
- 否则,如果类加载器是
urlclassloader 的实例,则返回的字符串是一个 url 的外部形式的由空格分隔的列表,该 url 通过调用加载器 geturls 方法返回。如果 urlclassloader 由此提供者创建,用于调用其 loadclass 或 loadproxyclass 方法,则不需要任何权限即可获取关联的基本代码字符串。如果它是其他任意一个 urlclassloader 实例,则如果存在安全管理器,则对于 geturls 方法返回的每个 url 都要调用一次其 checkpermission 方法(所用的权限为对每个 url 调用 openconnection().getpermission() 返回的权限);如果这些调用的任何一个抛出 securityexception 或 ioexception,则返回 java.rmi.server.codebase 属性的值(或可能是原先的缓存值);如果未设置该属性,则返回 null。
- 最后,如果类加载器不是
urlclassloader 的实例,则返回 java.rmi.server.codebase 属性的值(或可能是原先的缓存值);如果未设置该属性,则返回 null。
对于下面描述的方法的实现,这些实现都采用作为由空格分隔的 url 列表的名为 codebase 的 string 参数,每个调用都有一个关联的基本代码加载器,它通过将 codebase 与当前线程的上下文类加载器一起使用进行标识(请参阅 thread.getcontextclassloader())。存在安全管理器时,此提供者将维护类加载器实例(至少是 urlclassloader 的实例)的内部表,这些内部表通过其父类加载器及其基本代码 url 路径(排序的 url 列表)键入。如果 codebase 为 null,则基本代码 url 路径是系统属性 java.rmi.server.codebase 的值,或可能是原先的缓存值。对于给定的基本代码 url 路径(该路径作为 codebase 参数传递到下面给定上下文中的方法之一的调用),基本代码加载器位于具有指定基本代码 url 路径的表中且当前线程的上下文类加载器是其父级的加载器。如果不存在这样的加载器,则创建一个这样的加载器并将其添加到表中。该表不维护对其包含的加载器的强引用,以便于允许它们及其定义类在不可另外到达时被垃圾回收。为了防止不受信任的任意代码被隐式加载到不带安全管理器的虚拟机中,如果未设置安全管理器,则基本代码加载器就是当前线程的上下文类加载器(提供的基本代码 url 路径被忽略,所以禁止了远程类加载)。
getclassloader 方法返回指定基本代码 url 路径的基本代码加载器。如果存在安全管理器,则如果该调用上下文没有连接到基本代码 url 路径上的所有 url 的权限,则抛出 securityexception。
loadclass 方法尝试按以下方式加载具有指定名称的类:
如果 defaultloader 为非 null,则它首先尝试使用 defaultloader 加载具有指定 name 的类,比如通过评估
class.forname(name, false, defaultloader)
如果从 defaultloader 成功加载了类,则返回该类。如果抛出 classnotfoundexception 之外的异常,则该异常被抛给调用方。
其次,loadclass 方法尝试使用指定基本代码 url 路径的基本代码加载器加载具有指定 name 的类。如果存在安全管理器,则该调用上下文必须具有连接到基本代码 url 上的所有 url 的权限;否则,将使用当前线程的上下文类加载器,而不是基本代码加载器。
loadproxyclass 方法尝试按以下方式返回具有指定接口的动态代理类:
如果 defaultloader 参数为非 null 且可以通过该加载器解析所有指定接口,则,
- 如果所有解析的接口都为
public,则它首先尝试获得在基本代码加载器中定义的解析接口的动态代理类(使用 proxy.getproxyclass);如果该尝试抛出一个 illegalargumentexception,则它尝试获得在 defaultloader 中定义的解析接口的动态代理类。如果两个尝试都抛出 illegalargumentexception,则此方法将抛出 classnotfoundexception。如果抛出任何其他异常,则该异常将被抛给调用方。
- 如果在同一类加载器中定义所有非
public 解析接口,则其尝试获得在该加载器中定义的解析接口的动态代理类。
- 否则,抛出
linkageerror(因为实现所有指定接口的类无法在任何加载器中定义)。
否则,如果所有指定的接口可通过基本代码加载器解析,则,
- 如果所有解析接口都为
public,则它尝试获得基本代码中解析接口的动态代理类。如果该尝试抛出 illegalargumentexception,则此方法抛出一个 classnotfoundexception。
- 如果在同一类加载器中定义所有非
public 解析接口,则它尝试获得在该加载器中定义的解析接口的动态代理类。
- 否则,抛出
linkageerror(因为实现所有指定接口的类无法在任何加载器中定义)。
否则,将为每个无法解析的指定接口抛出 classnotfoundexception。