转自:http://hi.baidu.com/weiqi228/blog/item/046dd6de8c54185395ee377b.html
作 为 充 分 利 用Java 的 动 态 类 载 入 机 制 的 最 好 例 子, 带 有Java 扩 展 的Web 浏 览 器 根 据 请 求 从 网 络 或 本 地 文 件 系 统 中 动 态 加 载Java applet( 遵 循 一 定 规 则 的Java 小 应 用 程 序 类), 然 后 在 本 地 系 统 中 执 行 它, 大 大 增 强 了 主 页 的 功 能。
---- 其 实,Java 本 身 就 是 一 种 极 具 动 态 性 的 语 言。 类 似Windows 的 动 态 链 接 库(DLL),Java 应 用 程 序 总 是 被 编 译 成 若 干 个 单 独 的class 文 件, 程 序 执 行 时 根 据 需 要 由Java 虚 拟 机 动 态 载 入 相 应 的 类。 这 种 机 制 使 编 写 动 态 的 分 布 式 应 用 程 序 成 为 可 能: 我 们 可 以 在 客 户 端 编 写 自 己 的 类 载 入 器, 而 真 正 执 行 的 程 序 却 存 放 在 本 地、 局 域 网 或 世 界 另 一 端 的 主 机 上。 下 面 将 介 绍 如 何 在 自 己 的 应 用 程 序 中 实 现Java 的 动 态 类 载 入 机 制。
与 动 态 类 载 入 有 关 的 系 统 类
---- 为 支 持 动 态 类 载 入 机 制, 在 系 统 类 组java.lang 中 提 供 了 两 个 类:Class 类 和ClassLoader 类。
---- 1、 类java.lang.Class。 在Java 虚 拟 机 中, 每 一 个 类 或 接 口 都 是 由Class 类 来 操 纵 的, 它 不 能 被 显 式 的 实 例 化, 必 须 用 其 他 方 法 来 获 取Class 类 的 对 象。 动 态 类 载 入 机 制 的 关 键 一 步 在 于 如 何 获 得 指 定 类 的Class 类 型 的 对 象。 相 关 方 法 主 要 有:
---- public static Class forName(String className)
---- 这 是 一 个 静 态 方 法, 它 获 取 指 定 名 字 的 类 的Class 类 型 对 象, 类 名 可 以 是 象"sun.applet.Applet" 这 样 的 字 符 串, 但 不 能 带 有 路 径 或 网 络 地 址 等 信 息。 这 是 从 本 地 系 统 中 动 态 载 入 类 的 最 方 便 的 办 法。
---- public Object newInstance()
---- 这 是 最 重 要 的 一 个 方 法, 它 建 立 由Class 类 型 对 象 描 述 的 指 定 类 的 实 例。
---- 下 面 是 一 个 用forName() 和newInstance() 方 法 实 现 动 态 类 载 入 的 代 码,share 类 包 含 一 个 接 口, 详 细 内 容 将 在 第 三 部 分 中 解 释。
try{
//根据类名建立Class类型的对象。
Class cc =Class.forName("类名"));
//建立被载入类类的实例并强制类型转换,
值赋给share类型的变量。
share oo=((share)cc).newInstance();
//调用该类的方法进行工作。
}
catch (Exception ex){
//如果发生例外,则进行相应处理。
};
---- 2、 类java.lang.ClassLoader。 这 是 一 个 抽 象 类, 如 果 打 算 运 用 它, 必 须 继 承 它 并 重 写 它 的loadClass() 方 法。 其 主 要 方 法 有:
---- protected ClassLoader();
---- 这 是 一 个 建 构 元, 可 以 用 它 建 立 一 个ClassLoader 类 的 实 例。 注 意 继 承 这 个 类 的 类 必 须 重 写 这 个 方 法, 而 不 能 使 用 缺 省 的 建 构 元。
---- protected abstract Class loadClass(String name, boolean resolve)
---- 载 入 指 定 的 类 数 据, 建 立Class 类 型 的 对 象 并 根 据 需 要 解 析 它。 这 是 一 个 抽 象 方 法, 大 家 必 须 在 自 己 的 子 类 中 重 写 这 个 方 法, 重 写 的 规 则 可 以 参 考 第 三 部 分 的 例 子。
---- protected final Class defineClass(byte data[], int offset, int length)
---- 将 字 节 数 组 中 的 数 据 定 义 为Class 类 型 的 对 象, 字 节 数 组 的 格 式 由 虚 拟 机 规 定。
---- protected final Class findSystemClass(String name)
---- 根 据 指 定 的 类 名 载 入 类, 它 会 自 动 在 当 前 目 录 和 环 境 变 量"CLASSPATH" 指 定 的 路 径 中 寻 找, 如 果 找 不 到, 则 会 抛 出ClassNotFoundException 例 外。
---- protected final void resolveClass(Class c)
---- 通 过 载 入 与 指 定 的 类 相 关 的 所 有 类 来 解 析 这 个 类, 这 必 须 在 类 被 使 用 之 前 完 成。
扩 充ClasslLader 类 以 实 现 动 态 类 载 入
---- 理 解 动 态 类 载 入 机 制 的 最 好 办 法 是 通 过 例 子, 下 面 这 个 完 整 的 例 子 由 四 个 类 组 成, 分 别 解 释 如 下:
---- 1、MyClassLoader 类 是ClassLoader 类 的 子 类, 它 重 写 了loadClass 方 法, 实 现 了 将 网 络 上 用URL 地 址 指 定 的 类 动 态 载 入, 取 得 它 的Class 类 型 对 象 的 功 能。 读 者 可 根 据 自 己 载 入 类 的 具 体 方 式 改 写 下 面 的 代 码。
import java.io.*;
import java.util.*;
import java.net.*;
public class MyClassLoader extends ClassLoader {
//定义哈希表(Hashtable)类型的变量,
用于保存被载入的类数据。
Hashtable loadedClasses;
public MyClassLoader() {
loadedClasses = new Hashtable();
}
public synchronized Class loadClass(String className,
boolean resolve) throws ClassNotFoundException {
Class newClass;
byte[] classData;
//检查要载入的类数据是否已经被保存在哈希表中。
newClass = (Class) loadedClasses.get(className);
//如果类数据已经存在且resolve值为true,则解析它。
if (newClass != null){
if (resolve)
resolveClass(newClass);
return newClass;
}
---- /* 首 先 试 图 从 本 地 系 统 类 组 中 载 入 指 定 类。 这 是 必 须 的, 因 为 虚 拟 机 将 这 个 类 载 入 后, 在 解 析 和 执 行 它 时 所 用 到 的 任 何 其 他 类, 如java.lang.System 类 等, 均 不 再 使 用 虚 拟 机 的 类 载 入 器, 而 是 调 用 我 们 自 制 的 类 载 入 器 来 加 载。*/
try {
newClass = findSystemClass(className);
return newClass;
} catch (ClassNotFoundException e) {
System.out.println(className+" is not a system class!");
}
//如果不是系统类,
则试图从网络中指定的URL地址载入类。
try {
//用自定义方法载入类数据,
存放于字节数组classData中。
classData = getClassData(className);
//由字节数组所包含的数据建立一个class类型的对象。
newClass = defineClass(classData, 0, classData.length);
if (newClass == null)
throw new ClassNotFoundException(className);
} catch (Exception e) {
throw new ClassNotFoundException(className);
}
//如果类被正确载入,
则将类数据保存在哈希表中,以备再次使用。
loadedClasses.put(className, newClass);
//如果resolve值为true,则解析类数据。
if (resolve){
resolveClass(newClass);
}
return newClass;
}
//这个方法从网络中载入类数据。
protected byte[] getClassData(String className)
throws IOException {
byte[] data;
int length;
try {
//从网络中采用URL类的方法
载入指定URL地址的类的数据。
URL url = new URL(className.endsWith(".class") ?
className : className + ".class");
URLConnection connection = url.openConnection();
InputStream inputStream = connection.getInputStream();
length = connection.getContentLength();
data = new byte[length];
inputStream.read(data);
inputStream.close();
return data;
} catch(Exception e) {
throw new IOException(className);
}
}
}
---- 2、 由 于Java 是 强 类 型 检 查 语 言, 通 过 网 络 载 入 后 的 类 被 实 例 化 后 只 是 一 个Object 类 型 的 对 象, 虚 拟 机 并 不 知 道 它 包 含 那 些 方 法, 应 从 哪 个 方 法 开 始 执 行。 因 此, 可 以 被 动 态 载 入 的 类 必 须 继 承 某 一 个 抽 象 类 或 实 现 某 一 个 接 口, 因 为 父 类 只 能 有 一 个, 所 以 通 常 用 实 现 特 定 接 口 的 办 法。 下 面 的 代 码 定 义 了 一 个 接 口 类share 和 它 的 方 法start()。
public interface share {
public void start(String[] option);
}
---- 3、TestClassLoader 类 通 过 使 用MyClassLoader 类 的loadClass() 方 法, 将 指 定URL 地 址 的 类 载 入 并 在 本 地 系 统 执 行 它, 实 现 了 类 的 动 态 载 入。 注 意 在 执 行 被 载 入 类 的 方 法 前 一 定 要 将 它 进 行 强 制 数 据 类 型 转 换。
public class TestClassLoader {
public static void main(String[] args){
MyClassLoader ll = new MyClassLoader();
Class cc;
Object oo;
String ss = "http://kyzser.ydxx/classLoader/Tested.class";
if (args.length != 0) ss = args[0];
try {
System.out.println("Loading class "+ss+"...");
//使用重写的方法loadClass()载入类数据。
cc = ll.loadClass(ss);
System.out.println("Creat instance...");
//创建Object类型的类实例。
oo = cc.newInstance();
System.out.println("Call start() method...");
//强制类型转换并执行被载入类中的方法。
((share) oo).start(args);
}catch (Exception e) {
System.out.println("Caught exception : "+e);
}
}
}
---- 4、Tested 类 很 简 单, 可 以 将 它 放 在 任 何WEB 服 务 器 上, 但 应 注 意 能 动 态 载 入 且 被 执 行 的 类, 一 定 要 实 现 预 先 定 义 的 接 口 中 的 方 法。 下 面 的 例 子 实 现 了 接 口share 的start 方 法。
public class Tested implements share{
public void start(String[] option){
//填写程序代码。
}
}
动 态 类 载 入 机 制 的 几 点 应 用
---- 1、 开 发 分 布 式 应 用。 这 对 开 发 远 程 的 客 户 端 应 用 程 序 最 有 用, 客 户 端 仅 需 要 安 装 一 些 基 本 的 系 统 和 一 个 能 实 现 动 态 类 载 入 机 制 的 类, 需 要 本 地 系 统 不 存 在 的 功 能 时, 仅 需 要 从 网 络 动 态 载 入 并 执 行 相 应 类 即 可 获 得 特 定 功 能。 因 为 客 户 端 所 使 用 的 总 是 软 件 的 最 新 版 本, 所 以 不 再 存 在 软 件 的 升 级 和 维 护 问 题, 即 实 现 了 所 谓 的" 零 管 理" 模 式。
---- 2、 对.class 文 件 加 密。 由 于Java 的 字 节 码(bytecode) 容 易 被 反 编 译, 大 部 分 开 发Java 应 用 程 序 的 公 司 均 担 心 自 己 的 成 果 被 别 人 不 劳 而 获。 其 实 可 以 将 类 文 件 进 行 适 当 的 加 密 处 理, 执 行 时 使 用 自 己 的 类 载 入 器 进 行 相 应 的 解 密, 就 可 以 解 决 这 个 问 题。
---- 3、 使 第 三 方 开 发 者 易 于 扩 展 你 的 应 用。 从 前 面 可 知, 所 有 可 以 被 你 的 类 载 入 器 动 态 载 入 并 被 执 行 的 类, 必 须 继 承 你 定 义 的 类 或 实 现 你 定 义 的 接 口, 这 样, 你 可 以 制 订 一 些 规 则, 使 其 他 开 发 者 不 必 了 解 你 的 应 用 程 序 也 可 以 扩 充 功 能。
---- 当 然, 有 利 必 有 弊, 在 网 络 中 使 用 动 态 类 载 入 的 主 要 缺 陷 在 于 安 全 性, 很 难 保 证 不 载 入 不 怀 好 意 的 代 码, 这 个 问 题 要 靠Java 的 安 全 管 理 器 和 适 当 的 加 密 算 法 来 解 决, 已 超 出 本 文 的 讨 论 范 围。
分享到:
相关推荐
在Java编程语言中,动态类加载机制是一种强大的特性,它允许程序在运行时加载、实例化和执行未在编译时硬编码的类。这种能力是通过Java的反射API实现的,它为开发者提供了深入洞察和操作Java对象的能力。本文将深入...
在Java编程语言中,`package`和`import`机制是构建大型、模块化代码库的关键要素,它们有助于组织和管理类以及确保代码的可重用性。本篇将深入探讨这两个概念,以及如何通过Visual Studio .NET来操控Java虚拟机(JVM...
1. **字节码与类加载机制**:Java源代码被编译成.class文件,这些文件包含字节码,这是JVM能够理解和执行的二进制指令。类加载器是JVM的一部分,负责查找和加载类文件,确保程序运行时正确地引用到所需的类。 2. **...
Java类加载器和类加载机制实例分析 Java类加载器和类加载机制...通过本文,我们了解了Java类加载器和类加载机制的原理、实现方法及相关操作技巧,为我们在实际开发中使用Java类加载器和类加载机制提供了有价值的参考。
【JAVA五子棋简单实现】是一个适合初学者的项目,旨在通过编程实现一个基本的五子棋游戏,以此巩固和加深对Java基础知识的理解。在这个项目中,开发者将学习到如何运用SWF(Simple Widget Framework)框架来构建用户...
总的来说,解决"java 载入dll之后无法切换输入法"的问题需要对Java、JNI、DLL和Windows操作系统有深入的理解,同时需要具备良好的调试技巧。通过仔细分析代码、调试和日志记录,通常能找到问题的根源并提出解决方案...
### 实现Java自定义注解拦截器 #### 概述 本文主要介绍如何在Spring Boot项目中使用自定义注解来实现对特定方法的拦截功能。具体场景为:当访问项目中的控制器方法时,需要进行“token验证”,但登录等特殊方法...
总结,深入理解Java的类别载入器不仅可以帮助我们更好地理解JVM的工作机制,还能在处理类冲突、优化性能、实现热部署等高级应用场景中提供有力支持。在日常开发中,我们应该充分利用类加载器的特性,提高代码的可...
Java虚拟机(JVM)的类加载机制是导致此问题的关键。自JDK 1.2以来,JVM采用委托模式加载类,先由引导类加载器(Bootstrap ClassLoader)加载核心类,接着是由扩展类加载器(Extension ClassLoader)加载扩展类,...
在《Java深度历险》这本书的第二章中,作者深入探讨了类加载器在实现Java程序动态性中的核心作用。 #### 类加载器的动态性 Java语言天生具备动态性,这意味着开发者无需依赖底层操作系统的特定机制(如动态链接库...
书中可能详细讲解了自定义类加载器的创建、类加载的生命周期、以及如何利用类加载机制实现动态加载和热部署。 接下来,“CH_03.Java与MS Office.pdf”这部分可能会探讨Java与Microsoft Office系统的集成。Java提供...
在 Java 中,类加载器是通过委派机制来实现的,即一个类加载器可以委派另一个类加载器来加载类。这篇文章将深入探讨 Java 类加载器中的静态变量初始化机制,了解其背后的工作原理和载入过程。 静态变量初始化机制 -...
在Java中,这种特性主要通过类加载器(Class Loader)实现。 #### 二、传统语言中的动词性实现 大多数编程语言并不天然具备动词性,如C、C++等。为了实现这种特性,程序员通常需要依赖底层操作系统提供的机制,...
Java采用了委托模型机制,这个机制简单来讲,就是“类装载器有载入类的需求时,会先请示其Parent使用其搜索路径帮忙载入,如果Parent 找不到,那么才由自己依照自己的搜索路径搜索类”。 类加载器的委托模型 这个...
它是Java平台的独特特性,因为它允许动态加载类,增强了软件的可扩展性和灵活性。这篇博文(虽然链接不可用)可能深入探讨了ClassLoader的工作原理及其在Java应用程序中的应用。 ClassLoader分为三个主要层次:...
它按照双亲委派模型工作,保证了类的唯一性,并且允许自定义类载入器以实现特定的加载策略,比如动态加载或热更新。 接下来,Java与MS Office的集成,主要是通过Java的COM(Component Object Model)接口来实现的,...
Java中的反射机制可以让开发人员在运行时动态地加载类、方法和变量,从而实现更加灵活的编程。Java中的反射机制包括Class、Method、Field和Constructor四个部分。通过反射机制,开发人员可以在运行时动态地调用方法...
同时,自定义类加载器允许你实现特定的加载策略,比如动态加载或加密的类文件。 接下来,我们转向Ant,这是一个由Apache基金会开发的自动化构建工具。在Java项目中,Ant常用于编译源代码、创建JAR文件、运行测试和...