java.applet.AppletContext 提供 getApplet(String name) 與 getApplets() 尋找同頁面 Applet,但要求:同一伺服器、同一目錄、同一頁面、同一瀏覽器視窗。這對「主功能 Applet + 獨立說明/導覽視窗」等跨視窗架構構成阻礙。本文揭示利用 共享執行時期環境 (Codebase 相同) 並透過 static 欄位傳遞執行個體引用的實戰技巧。
codebase (伺服器目錄) 的 Applet,即便載入於不同 HTML 頁面/框架/視窗,共享同一個 JVM 類別載入器命名空間。static 欄位屬於類別,而非執行個體,因此對所有 Applet 執行個體可見。this 存入 Applet B 類別的 static 欄位,Applet C 即可讀取並呼叫 B 的公用方法。public class AppletB extends Applet {
// 靜態公用欄位,保存目前執行個體引用
public static AppletB selfRef = null;
public void init() {
selfRef = this; // 初始化時註冊自己
}
// 業務方法:供其他 Applet 呼叫
public void showHelpTopic(String topic) {
// 切換說明內容、高亮顯示等
repaint();
}
public void destroy() {
selfRef = null; // 釋放引用,避免記憶體洩漏
}
}
public class AppletA extends Applet {
private AppletB helpApplet = null;
private void ensureHelpApplet() {
if (helpApplet == null) {
helpApplet = AppletB.selfRef; // 直接讀取靜態欄位
}
}
public void onUserAction(String context) {
ensureHelpApplet();
if (helpApplet != null) {
helpApplet.showHelpTopic(context); // 跨視窗呼叫!
} else {
showStatus("說明視窗尚未載入,請稍候...");
}
}
}
<!-- 主功能頁面 -->
<APPLET code="AppletA.class" codebase="/applets/" width="600" height="400"></APPLET>
<!-- 獨立說明視窗 (以 JavaScript 開啟新視窗) -->
<script>
window.open('/help/help.html', 'helpWin', 'width=400,height=500');
</script>
<!-- help.html -->
<APPLET code="AppletB.class" codebase="/applets/" width="400" height="500"></APPLET>
關鍵:兩個 <APPLET> 標籤的 codebase="/applets/" 完全相同。
null,因視窗載入順序不定。AppletContext 事件或定時輪詢確認對方就緒。destroy() 清除 static 引用,防止記憶體洩漏與殭屍引用。跨 Applet 呼叫發生在 AWT 事件派發執行緒 (EDT) 或自訂執行緒。若目標方法操作 UI 元件,必須用 SwingUtilities.invokeLater() 或 EventQueue.invokeLater() 佇列至 EDT:
public void showHelpTopic(final String topic) {
EventQueue.invokeLater(() -> {
// 安全地更新 UI
textArea.setText(topic);
repaint();
});
}
若同一頁面可能載入多個 AppletB 實例,單一 static 欄位不足。改用 static Map,鍵值可為視窗 ID、Session ID 或隨機 UUID,AppletA 需知曉對應鍵值 (可透過 JavaScript 協商傳遞)。
Applet 子類別。靜態欄位共享引用是 Java Applet 時代突破「同頁面」限制的經典模式,其本質是利用共享類別載入器命名空間實現進程內服務定位。這一思想在現代微服務架構中以「服務註冊與發現」(Consul, Eureka, Nacos)、「模組熱插拔」(OSGi, JPMS) 等形式延續演進。理解其核心機制,有助於掌握分散式系統服務治理的本質。