服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

实 现java 的 动 态 类 载 入 机 制


  作 为 充 分 利 用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 类 型 的 对 象, 虚 拟 机 并 不 知 道 它 包 含 那 些 方 法, 应 从 哪 个 方 法 开 始 执 行。 因 此, 可 以 被 动 态 载 入 的 类 必 须 继 承 某 一 个 抽 象 类 或 实 现 某 一 个 接 口, 因 为 父 类 只 能 有 一 个,

扫描关注微信公众号