没有合适的资源?快使用搜索试试~ 我知道了~
Java的类加载的真实内幕
资源详情
资源评论
资源推荐
类加载是 java 语言提供的最强大的机制之一。尽管类加载并不是讨论的热点话题,但所有的编 程
人员都应该了解其工作机制,明白如何做才能让其满足我们的需要。这能有效节省我们的编码时
间,从不断调试 ClassNotFoundException, ClassCastException 的工作中解脱出来。
这篇文章从基础讲起,比如代码与数据的不同之处是什么,他们是如何构成一个实例或对象的。
然后深入探讨 java 虚拟机( JVM )是如何利用类加载器读取代码,以及 java 中类加载器的主要 类
型。接着用一个类加载的基本算法看一下类加载器如何加载一个内部类。本文的下一节演示一段
代码来说明扩展和开发属于自己的类加载器的必要性。紧接着解释如何使用定制的类加载器来完
成一个一般意义上的任务, 使其可以加载任意远端客户的代码, 在 JVM 中定义, 实例化并执行 它。
本文包括了 J2EE 关于类加载的规范 —— 事实上这已经成为了 J2EE 的标准之一。
类与数据
一个类代表要执行的代码,而数据则表示其相关状态。状态时常改变,而代码则不会。当我们将
一个特定的状态与一个类相对应起来,也就意味着将一个类事例化。尽管相同的类对应的实例其
状态千差万别,但其本质都对应着同一段代码。在 JAVA 中,一个类通常有着一个 .class 文件, 但
也有例外。在 JAVA 的运行时环境中( Java runtime ),每一个类都有一个以第一类 (firstclass) 的
Java 对象所表现出现的代码,其是 java.lang.Class 的实例。我们编译一个 JAVA 文件,编译器都
会嵌入一个 public, static, final 修饰的类型为 java.lang.Class ,名称为 class 的域变量在其字节码
文件中。因为使用了 public 修饰,我们可以采用如下的形式对其访问:
java.lang.Class klass = Myclass.class;
一旦一个类被载入 JVM 中,同一个类就不会被再次载入了(切记,同一个类)。这里存在一个 问
题就是什么是 “ 同一个类 ” ?正如一个对象有一个具体的状态, 即标识, 一个对象始终和其代码 ( 类 )
相关联。同理,载入 JVM 的类也有一个具体的标识,我们接下来看。
在 JAVA 中, 一个类用其完全匹配类名 (fully qualified class name) 作为标识, 这里指的完全匹配 类
名包括包名和类名。 但在 JVM 中一个类用其全名和一个加载类 ClassLoader 的实例作为唯一标识 。
因此,如果一个名为 Pg 的包中,有一个名为 Cl 的类,被类加载器 KlassLoader 的一个实例 kl1 加
载, Cl 的实例, 即 C1.class 在 JVM 中表示为 (Cl, Pg, kl1) 。 这意味着两个类加载器的实例 (Cl, Pg, kl1)
和 (Cl, Pg, kl2) 是不同的,被它们所加载的类也因此完全不同,互不兼容的。那么在 JVM 中到底
有多少种类加载器的实例?下一节我们揭示答案。
类加载器
在 JVM 中,每一个类都被 java.lang.ClassLoader 的一些实例来加载 . 类 ClassLoader 是在包中
java.lang 里,开发者可以自由地继承它并添加自己的功能来加载类。
无论何时我们键入 java MyMainClass 来开始运行一个新的 JVM , “ 引导类加载器 (bootstrap class
loader) ” 负责将一些关键的 Java 类,如 java.lang.Object 和其他一些运行时代码先加载进内存中。
运行时的类在 JRE\lib\rt.jar 包文件中。因为这属于系统底层执行动作,我们无法在 JAVA 文档中
找到引导类加载器的工作细节。基于同样的原因,引导类加载器的行为在各 JVM 之间也是大相 径
庭。
同理,如果我们按照如下方式:
log(java.lang.String.class.getClassLoader());
来获取 java 的核心运行时类的加载器,就会得到 null 。
接下来介绍 java 的扩展类加载器。扩展库提供比 java 运行代码更多的特性,我们可以把扩展库
保存在由 java.ext.dirs 属性提供的路径中。
( 编辑注: java.ext.dirs 属性指的是系统属性下的一个 key ,所有的系统属性可以通过
System.getProperties() 方法获得。在编者的系统中, java.ext.dirs 的 value 是 ” C:\Program
Files\Java\jdk1.5.0_04\jre\lib\ext ” 。下面将要谈到的如 java.class.path 也同属系统属性的一个
key 。 )
类 ExtClassLoader 专门用来加载所有 java.ext.dirs 下的 .jar 文件。 开发者可以通过把自己的 .jar 文
件或库文件加入到扩展目录的 classpath ,使其可以被扩展类加载器读取。
从开发者的角度,第三种同样也是最重要的一种类加载器是 AppClassLoader 。这种类加载器用 来
读取所有的对应在 java.class.path 系统属性的路径下的类。
Sun 的 java 指南中,文章 “ 理解扩展类加载 ” ( Understanding Extension Class Loading )对以上 三
个类加载器路径有更详尽的解释,这是其他几个 JDK 中的类加载器
● java.net.URLClassLoader
● java.security.SecureClassLoader
● java.rmi.server.RMIClassLoader
● sun.applet.AppletClassLoader
java.lang.Thread ,包含了 public ClassLoader getContextClassLoader() 方法,这一方法返回针对
一具体线程的上下文环境类加载器。此类加载器由线程的创建者提供,以供此线程中运行的代码
在需要加载类或资源时使用。如果此加载器未被建立,缺省是其父线程的上下文类加载器。原始
的类加载器一般由读取应用程序的类加载器建立。
类加载器如何工作?
除了引导类加载器,所有的类加载器都有一个父类加载器,不仅如此,所有的类加载器也都是
java.lang.ClassLoader 类型。以上两种类加载器是不同的,而且对于开发者自订制的类加载器的
正常运行也至关重要。最重要的方面是正确设置父类加载器。任何类加载器,其父类加载器是加
载该类加载器的类加载器实例。(记住,类加载器本身也是一个类!)
使用 loadClass() 方法可以从类加载器中获得该类。我们可以通过 java.lang.ClassLoader 的源代码
来了解该方法工作的细节,如下:
protected synchronized Class<?> loadClass
(String name, boolean resolve)
throws ClassNotFoundException{
// 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);
}
} catch (ClassNotFoundException e) {
// If still not found, then invoke
// findClass to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
我们可以使用 ClassLoader 的两种构造方法来设置父类加载器:
剩余19页未读,继续阅读
chenjunhui19840422
- 粉丝: 4
- 资源: 50
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 202304910142原道明(1).pbix
- 基于Lua的聊天过滤修改版设计源码
- Uibot6.0 (RPA财务机器人师资培训第5天 ) 报销汇总机器人案例实战
- 基于Vue的西安美食攻略应用程序设计源码
- tensorflow-2.6.2-cp38-cp38-win-amd64.whl
- 2023-04-06-项目笔记 - 第八十六阶段 - 4.4.2.84全局变量的作用域-84 -2024.03.28
- 基于C语言解决九宫重排问题(源码+剖析)
- 考研分数计算神器(通过考研分数计算规则制作出来的计算工具,结果精准,操作简单,并且还可以与第二个人进行比较)
- 脚本监控重要文件,并邮箱报警
- 九宫重排介绍.zip说明
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0