Java类加载机制
} }
或者 public class MyClassLoader extends ClassLoader{
public MyClassLoader(){ super(getClass().getClassLoader());
} }
第一种方法更为常用,因为在构造方法中使用 getClass() 方法是不提倡的,因为对象初 始化仅在构造方法结束后才会完成。因此,如果正确设置了类加载器的父类加载器,不论 什么时候从类加载器实例请求一个类时,如果此类加载器不能加载此类,则首先会交给它 的父类加载器处理。如果此父类加载器也不能加载那个类,则又会交给上一层的父类加载 器,依此类推。但是如果 findBootstrapClass0()方法也未能加载那个类时,就会唤醒 findClass() 去处理。findClass()的默认的实现是抛 ClassNotFoundException 异常。所以开发者需要继承 ng.ClassLoader 来实现用户自编写的类加载器。findClass()默认的实现如下:
Java 类加载机制(一)
译:ayi 译文疏漏,请多多指点
原文:/pub/a/onjava/2005/01/26/classloading.html
注:因内容太多,分为一、二两篇文章
类加载是 java 特性的一个很重要的部分。尽管,java 中“advanced topics”的发展,使 java 的类加载机制地位有所下降。但每位编程者都应该知道这部分的工作机制,以及怎样去配 合其工作。这可以使我们节省很多时间,而不必要浪费在调试ClassNotFoundException, ClassCastException, 等。
设置父类加载器,我们有两种方法,在 ClassLoader 的构造方法中。 public class MyClassLoader extends ClassLoader{
public MyClassLoader(){ super(MyClassLoader.class.getClassLoader());
载器的正常工作来说都非常重要。在这里,最重要的是怎样正确的设置父类加载器。类加 载器的父类加载器实例会负责加载此类加载器类。(记住:一个类加载器本身也是一个类。) 在一个类加载器外部请求一个类时,使用 loadClass() 方法。这个方法的具体工作,我们可 以从源代码来看:
protected synchronized Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException{
比如,如果我们试图得到一个核心 java 运行时类的一个类加载器,我们将得到 null 值,如 下: log(ng.String.class.getClassLoader()); 下面要说到的是 java 扩展类加载器。在 java.ext.dirs 路径下面,我们可以放 java 扩展类库, 这样我们可以获得超出 java 核心运行时类的特性。扩展类加载器(ExtClassLoader)将会加 载 java.ext.dirs 目录下的所有 .jar 文件。开发者可以为自己的应用增加新的 .jar 文件 或者 类 库,只要他把它们添加到 java.ext.dirs 目录下面以至于能被扩展类加载器找到。
类加载器
在 java 中,每个类都会被 ng.ClassLoader 的一个实例加载。ClassLoader 类处于 ng
包下面,开发者可以自由的创建它的子类,添加自己功能的类加载器。
每当敲入 java MyMainClass,一个新的 JVM 开始时,引导类加载器(bootstrap class loader ) 首先会把 java 中的一些关键类,像 ng.Objent,和运行时的代码载入内存。这些运行 时类打包在 JRE\lib\rt.jar 文件中。因为是一个本地的接口,我们并不能从 java 文档中得到 引 导 类 加 载 器 ( bootstrap class loader ) 信 息 。 也 正 是 这 个 原 因 , 引 导 类 加 载 器 (bootstrap class loader )的表现也根据 JVM 的不同而异。
这篇文章将从最基本的开始,比如代码和数据的关系,以及他们怎么样关系起来形成一 个实例或者对象。然后将会说到,java 中怎样通过类加载器把代码加载到 JVM 中,以及 java 中实现的主要的几种类型的类加载器。在这篇文章中,然后我们将会了解到 java 类加载机 制的内幕,我们将使用最基本的代码来描述,这些代码执行于类加载器之后,但在加载一 个类之前。在接下来的部分将使用一些例子来证实,对于开发者继承和开发自己的类加载 器的必要性。接着将告诉你们怎样编写自己的类加载器,以及怎样使用它们去创建一个一 般的能加载包括远程客户端辅助代码的类加载器引擎,以及怎样把它在 JVM 中定义,实例 化,然后执行。习惯上,把 J2EEspecific components 中说明的作为 java 类加载的规范,这 篇文章正是从这本手册总结来的。
的字段 class,这个字段表示的就是一个 ng.Class 型的实例。因为它是 public 类型的, 我们可以通过标识符来访问它,像这样:
ng.Class klass = Myclass.class;
只要一个类被加载到 JVM,相同的类(强调:相同的类)将不会被重复加载。这将产 生一个问题,什么才是相同的类?一个对象有一种特定状态和标识,对象总是与它所属类 联系在一起,与这种状况相似,一个被加载到 JVM 中类也有特定的标识,接下来我们就阐 述:
在 java 中,一个类通过认证的类全名来唯一标识。认证的类全名是由包名和类名两部 分组成。但是在一个类被加载到 JVM 中则是通过认证的类全名,还有加载这个类的加载器 来唯一标识。因此,一个类的类名为 C1,包名为 Pg,被类加载器类 KClassLoader 的一个 实例 k1 加载,则 C1,也就是 C1.class ,的类实例,在 JVM 中将被解释为(C1,Pg,k1)。 这就意味着两个不同的类加载器实(Cl, Pg, kl1) 和 (Cl, Pg, kl2) ,加载的类在 JVM 中将有不 同的类实例对象,不是类型可比型(typecompatible)的。在 JVM 中有多少个类加载器实 例呢?下面,我们将讲解这个。
图 1 展 示 了 一 个 带 有 main 方 法 的 应 用 程 序 类 MyMainClass 。 正 如 前 面 所 说 的 , MyMainClass.class 将被 AppClassLoader 加载 ,MyMainClass 创建两个加载器类实例, CustomClassLoader1 和 CustomClassLoader2,他们都能从某些资源(比如说:网络)中加载 第四个类 Target 的字节码。这就意味着 Target 这个类的定义超出了应用程序的 class path 或 者扩展 class path 范围。在这种 情况下,如果 MyMainClass 让客户加载器实例去加载 Target 类。Target 将同时被 CustomClassLoader1 和 CustomClassLoader2 加载和定义。在 java 中这样就会有严重的问题。如果在 Target 中包含一段静态(static)的初始化代码,如果我 们要求这段代码执行且仅贝被执行一次,在我们目前的情况下,这段代码将被执行两次。 在两个 CustomClassLoader 中,都执行了一次。如果 Target 被两个 CustomClassLoader 同时 初始化,他将会有两个实例 target1 和 target2 ,正如下面图 1 所示的,target1 和 target2 是不 可比的。也就是说,在 java 中不能执行这段代码:
// First check if the class is already loaded Class c = findLoadedClass(name); if (c == null) {
try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClass0(name); }
在 Sun 的 java 指南中,文章“理解扩展类加载”(Understanding Extension Class Loading) 对以上三个类加载器路径有更详尽的解释,这是其他几个 JDK 中的类加载器
.URLClassLoader java.security.SecureClassLoader java.rmi.server.RMIClassLoader sun.applet.AppletClassLoader
protected Class<?> findClass(String name)
throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
深入 findClass()方法,类加载器需要从其它资源获取字节码。这些资源可以是文件系统、网 络 URL、数据库、其它的可以把字节码转换为流的应用程序,或者能够产生与 java 特性相 适应的字节码的类似资源。你可以使用BCEL (Byte Code Engineering Library),它能非常方便 的根据运行时的迹象创建类 。BCEL 已经成功的应用在了一些地方,如编译器、优化程序、 模糊程序(ob节码被重新获取,findClass()
类和数据
一个类代表一段要执行的代码,然而数据则代表与这些代码相关联的某种状态。状态可 以改变,代码不能改变。我们把一种特定状态与一个类关联起来时,就得到了这个类的一 个实例。所以同一个类的不同实例有不同的状态,但都参照相同的代码。在 java 中,一个 类通常它的代码就包含在一个 .class 文件中,虽然其中也包括异常。然而,在 java 运行时, 每个类都会构造一个超类对象(firstclass object),它们其实是 ng.Class 的实例。不 论何时编译一个 java 文件,编译器都会在编译后的字节码中嵌入一个 public, static, final 型