作 為 充 分 利 用Java 的 動 態 類 載 入 機 制 的 最 好 例 子
帶 有Java 擴 展 的Web 浏 覽 器 根 據 請 求 從 網 絡 或 本 地 文 件 系 統 中 動 態 加 載Java applet( 遵 循 一 定 規 則 的Java 小 應 用 程 序 類)
然 後 在 本 地 系 統 中 執 行 它
大 大 增 強 了 主 頁 的 功 能
其 實
Java 本 身 就 是 一 種 極 具 動 態 性 的 語 言
類 似Windows 的 動 態 鏈 接 庫(DLL)
Java 應 用 程 序 總 是 被 編 譯 成 若 干 個 單 獨 的class 文 件
程 序 執 行 時 根 據 需 要 由Java 虛 擬 機 動 態 載 入 相 應 的 類
這 種 機 制 使 編 寫 動 態 的 分 布 式 應 用 程 序 成 為 可 能
我 們 可 以 在 客 戶 端 編 寫 自 己 的 類 載 入 器
而 真 正 執 行 的 程 序 卻 存 放 在 本 地
局 域 網 或 世 界 另 一 端 的 主 機 上
下 面 將 介 紹 如 何 在 自 己 的 應 用 程 序 中 實 現Java 的 動 態 類 載 入 機 制
與 動 態 類 載 入 有 關 的 系 統 類
為 支 持 動 態 類 載 入 機 制
在 系 統 類 組java
lang 中 提 供 了 兩 個 類
Class 類 和ClassLoader 類
類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){
//如果發生例外
則進行相應處理
};
類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 類 以 實 現 動 態 類 載 入
理 解 動 態 類 載 入 機 制 的 最 好 辦 法 是 通 過 例 子
下 面 這 個 完 整 的 例 子 由 四 個 類 組 成
分 別 解 釋 如 下
MyClassLoader 類 是ClassLoader 類 的 子 類
它 重 寫 了loadClass 方 法
實 現 了 將 網 絡 上 用URL 地 址 指 定 的 類 動 態 載 入
取 得 它 的Class 類 型 對 象 的 功 能
讀 者 可 根 據 自 己 載 入 類 的 具 體 方 式 改 寫 下 面 的 代 碼
import java
io
*;
import java
util
*;
import
*;
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
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);
}
}
}
由 於Java 是 強 類 型 檢 查 語 言
通 過 網 絡 載 入 後 的 類 被 實 例 化 後 只 是 一 個Object 類 型 的 對 象
虛 擬 機 並 不 知 道 它 包 含 那 些 方 法
應 從 哪 個 方 法 開 始 執 行
因 此
可 以 被 動 態 載 入 的 類 必 須 繼 承 某 一 個 抽 象 類 或 實 現 某 一 個 接 口
因 為 父 類 只 能 有 一 個
所 以 通 常 用 實 現 特 定 接 口 的 辦 法
下 面 的 代 碼 定 義 了 一 個 接 口 類share 和 它 的 方 法start()
public interface share {
public void start(String[] option);
}
TestClassLoader 類 通 過 使 用MyClassLoader 類 的loadClass() 方 法
將 指 定URL 地 址 的 類 載 入 並 在 本 地 系 統 執 行 它
實 現 了 類 的 動 態 載 入
注 意 在 執 行 被 載 入 類 的 方 法 前 一 定 要 將 它 進 行 強 制 數 據 類 型 轉 換
public class TestClassLoader {
public static void main(String[] args){
MyClassLoader ll = new MyClassLoader(); <
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26668.html