Java Applet 详解:基础概念、生命周期与核心差异
Applet 是运行在 Web 浏览器中的 Java 程序。因拥有完整 Java API,Applet 可成为功能完备的 Java 应用。
Applet 与独立 Java 应用有重要差异:
Applet 是继承 java.applet.Applet 类的 Java 类。
Applet 不调用 main() 方法,也不会定义 main()。
Applet 设计为嵌入 HTML 页面。
用户查看包含 Applet 的 HTML 页面时,Applet 代码会下载到用户机器。
查看 Applet 需 JVM,可以是浏览器插件或独立运行环境。
用户机器上的 JVM 创建 Applet 类实例,并在 Applet 生命周期中调用各种方法。
Applet 有浏览器强制执行的严格安全规则,常称沙箱安全,如同儿童在沙箱中玩耍须遵守规则。
Applet 所需的其他类可打包在单个 Java Archive (JAR) 文件中下载。
Applet 生命周期
Applet 类中四个方法为构建严肃 Applet 提供框架:
init —— 用于 Applet 所需的初始化。在 applet 标签内的 param 标签处理后调用。
start —— 浏览器调用 init 后自动调用。用户离开包含 Applet 的页面后再返回时也会调用。
stop —— 用户离开 Applet 所在页面时自动调用。因此同一 Applet 可被重复调用。
destroy —— 仅在浏览器正常关闭时调用。因 Applet 生存于 HTML 页面,用户离开包含 Applet 的页面后通常不应留下资源。
paint —— 在 start() 方法后立即调用,以及浏览器中 Applet 需重绘时调用。paint() 方法实则继承自 java.awt。
“Hello, World” Applet
下面是一个名为 HelloWorldApplet.java 的简单 Applet:
import java.applet.*;
import java.awt.*;
public class HelloWorldApplet extends Applet {
public void paint(Graphics g) {
g.drawString("Hello World", 25, 50);
}
}
这些 import 语句将类引入 Applet 类作用域:
- java.applet.Applet
- java.awt.Graphics
没有这些 import 语句,Java 编译器无法识别 Applet 类引用的 Applet 和 Graphics 类。
Applet 类
每个 Applet 都是 java.applet.Applet 类 的扩展。基础 Applet 类提供方法,派生 Applet 类可调用这些方法从浏览器上下文获取信息和服务。
这些方法包括:
- 获取 Applet 参数
- 获取包含 Applet 的 HTML 文件网络位置
- 获取 Applet 类目录网络位置
- 在浏览器打印状态消息
- 获取图像
- 获取音频片段
- 播放音频片段
- 调整 Applet 大小
此外,Applet 类提供接口供查看器或浏览器获取 Applet 信息并控制执行。查看器可:
- 请求 Applet 作者、版本、版权信息
- 请求 Applet 识别的参数描述
- 初始化 Applet
- 销毁 Applet
- 启动 Applet 执行
- 停止 Applet 执行
Applet 类为每个方法提供默认实现,可根据需要重写。
“Hello, World” Applet 仅重写 paint 方法即已完整。
调用 Applet
Applet 可通过在 HTML 文件中嵌入指令,经 Applet 查看器或支持 Java 的浏览器查看文件来调用。
<applet> 标签是在 HTML 文件中嵌入 Applet 的基础。下例调用“Hello, World” Applet:
<html> <title>The Hello, World Applet</title> <hr> <applet code="HelloWorldApplet.class" width="320" height="120"> If your browser was Java-enabled, a "Hello, World" message would appear here. </applet> <hr> </html>
注意 —— 可参考 HTML Applet Tag 了解更多从 HTML 调用 Applet 的信息。
<applet> 标签的 code 属性为必需,指定运行的 Applet 类。width 和 height 也必需,指定 Applet 运行面板初始大小。Applet 指令须以 </applet> 标签闭合。
若 Applet 接受参数,可在 <applet> 和 </applet> 间添加 <param> 标签传递参数值。浏览器忽略 Applet 标签间与 Applet 无关的文本和其他标签。
非 Java 支持的浏览器不处理 <applet> 和 </applet>,因此标签间与 Applet 无关的内容在非 Java 浏览器中可见。
查看器或浏览器在文档位置查找编译后的 Java 代码。要指定其他位置,使用 <applet> 标签的 codebase 属性:
<applet codebase="https://amrood.com/applets" code="HelloWorldApplet.class" width="320" height="120">
若 Applet 位于非默认包中,code 属性须用句点 (.) 分隔包/类组件指定包名。例如:
<applet code="mypackage.subpackage.TestApplet.class" width="320" height="120">
获取 Applet 参数
下例演示如何让 Applet 响应文档中指定的设置参数。此 Applet 显示黑色与第二种颜色的棋盘图案。第二种颜色和每个方格大小可作为参数在文档中指定给 Applet。
CheckerApplet 在 init() 方法中获取参数,也可在 paint() 方法中获取。但在 Applet 启动时一次性获取值并保存设置,比每次刷新获取更方便高效。
Applet 查看器或浏览器调用每个运行 Applet 的 init() 方法。查看器加载 Applet 后立即调用一次 init()。(Applet.init() 实现为无操作。)重写默认实现以插入自定义初始化代码。
Applet.getParameter() 方法按参数名获取参数(参数值始终为字符串)。若值为数字或其他非字符数据,字符串须解析。
CheckerApplet.java 骨架如下:
import java.applet.*;
import java.awt.*;
public class CheckerApplet extends Applet {
int squareSize = 50; // 初始化为默认大小
public void init() {}
private void parseSquareSize(String param) {}
private Color parseColor(String param) {}
public void paint(Graphics g) {}
}
CheckerApplet 的 init() 和私有 parseSquareSize() 方法:
public void init() {
String squareSizeParam = getParameter("squareSize");
parseSquareSize(squareSizeParam);
String colorParam = getParameter("color");
Color fg = parseColor(colorParam);
setBackground(Color.black);
setForeground(fg);
}
private void parseSquareSize(String param) {
if (param == null) return;
try {
squareSize = Integer.parseInt(param);
} catch (Exception e) {
// 保持默认值
}
}
Applet 调用 parseSquareSize() 解析 squareSize 参数。parseSquareSize() 调用库方法 Integer.parseInt() 解析字符串并返回整数。参数无效时 Integer.parseInt() 抛出异常,因此 parseSquareSize() 捕获异常,避免因错误输入导致 Applet 失败。
Applet 调用 parseColor() 将 color 参数解析为 Color 值。parseColor() 通过一系列字符串比较将参数值匹配到预定义颜色名。需实现这些方法使 Applet 工作。
指定 Applet 参数
下面是嵌入 CheckerApplet 的 HTML 文件示例,通过 <param> 标签指定两个参数:
<html> <title>Checkerboard Applet</title> <hr> <applet code="CheckerApplet.class" width="480" height="320"> <param name="color" value="blue"> <param name="squaresize" value="30"> </applet> <hr> </html>
注意 —— 参数名不区分大小写。
应用程序转换为 Applet
将图形化 Java 应用(即使用 AWT、可用 Java 程序启动器启动的应用)转换为可嵌入网页的 Applet 很容易。
转换步骤如下:
制作包含适当标签的 HTML 页面加载 Applet 代码。
提供 JApplet 类的子类,且须为 public,否则无法加载。
移除应用中的 main 方法。不为应用构建框架窗口。应用将在浏览器中显示。
将框架窗口构造器中的初始化代码移至 Applet 的 init 方法。无需显式构建 Applet 对象。浏览器会实例化并调用 init 方法。
移除 setSize 调用;Applet 大小由 HTML 文件中 width 和 height 参数指定。
移除 setDefaultCloseOperation 调用。Applet 无法关闭;浏览器退出时终止。
若应用调用 setTitle,移除该方法调用。Applet 无标题栏(当然可用 HTML title 标签设置网页标题)。
不要调用 setVisible(true)。Applet 自动显示。
事件处理
Applet 从 Container 类继承一组事件处理方法。Container 类定义 processKeyEvent、processMouseEvent 等处理特定事件类型的方法,还有一个 catch-all 方法 processEvent。
为响应事件,Applet 必须重写相应的事件专用方法。
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.applet.Applet;
import java.awt.Graphics;
public class ExampleEventHandling extends Applet implements MouseListener {
StringBuffer strBuffer;
public void init() {
addMouseListener(this);
strBuffer = new StringBuffer();
addItem("initializing the applet ");
}
public void start() { addItem("starting the applet "); }
public void stop() { addItem("stopping the applet "); }
public void destroy() { addItem("unloading the applet"); }
void addItem(String word) {
System.out.println(word);
strBuffer.append(word);
repaint();
}
public void paint(Graphics g) {
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.drawString(strBuffer.toString(), 10, 20);
}
public void mouseEntered(MouseEvent event) { }
public void mouseExited(MouseEvent event) { }
public void mousePressed(MouseEvent event) { }
public void mouseReleased(MouseEvent event) { }
public void mouseClicked(MouseEvent event) { addItem("mouse clicked! "); }
}
调用此 Applet:
<html> <title>Event Handling</title> <hr> <applet code="ExampleEventHandling.class" width="300" height="300"> </applet> <hr> </html>
初始显示“initializing the applet. Starting the applet.” 点击矩形内部后显示“mouse clicked”。
显示图像
Applet 可显示 GIF、JPEG、BMP 等格式图像。在 Applet 中显示图像使用 java.awt.Graphics 类的 drawImage() 方法。
下例演示显示图像的所有步骤:
import java.applet.*;
import java.awt.*;
import java.net.*;
public class ImageDemo extends Applet {
private Image image;
private AppletContext context;
public void init() {
context = this.getAppletContext();
String imageURL = this.getParameter("image");
if(imageURL == null) { imageURL = "java.jpg"; }
try {
URL url = new URL(this.getDocumentBase(), imageURL);
image = context.getImage(url);
} catch (MalformedURLException e) {
e.printStackTrace();
context.showStatus("Could not load image!");
}
}
public void paint(Graphics g) {
context.showStatus("Displaying image");
g.drawImage(image, 0, 0, 200, 84, null);
g.drawString("www.javalicense.com", 35, 100);
}
}
调用此 Applet:
<html> <title>The ImageDemo applet</title> <hr> <applet code="ImageDemo.class" width="300" height="200"> <param name="image" value="java.jpg"> </applet> <hr> </html>
播放音频
Applet 可播放 java.applet 包中 AudioClip 接口表示的音频文件。AudioClip 接口有三个方法:
public void play() —— 从头播放音频片段一次。
public void loop() —— 使音频片段持续重播。
public void stop() —— 停止播放音频片段。
获取 AudioClip 对象须调用 Applet 类的 getAudioClip() 方法。无论 URL 是否解析到实际音频文件,getAudioClip() 立即返回。仅当尝试播放音频片段时才下载音频文件。
下例演示播放音频的所有步骤:
import java.applet.*;
import java.awt.*;
import java.net.*;
public class AudioDemo extends Applet {
private AudioClip clip;
private AppletContext context;
public void init() {
context = this.getAppletContext();
String audioURL = this.getParameter("audio");
if(audioURL == null) { audioURL = "default.au"; }
try {
URL url = new URL(this.getDocumentBase(), audioURL);
clip = context.getAudioClip(url);
} catch (MalformedURLException e) {
e.printStackTrace();
context.showStatus("Could not load audio file!");
}
}
public void start() { if(clip != null) { clip.loop(); } }
public void stop() { if(clip != null) { clip.stop(); } }
}
调用此 Applet:
<html> <title>The ImageDemo applet</title> <hr> <applet code="ImageDemo.class" width="0" height="0"> <param name="audio" value="test.wav"> </applet> <hr> </html>
可用 PC 上的 test.wav 测试上述示例。
java
- 精通 Java 运算符:类型、语法与实战示例
- Java 注释:类型、用法与最佳实践
- 精通 Java if…else:控制流全解析
- 精通 Java 增强 for 循环:语法、示例与最佳实践
- 精通 Java 字符串:创建、方法与最佳实践
- 精通 Java 接口:概念、实现与最佳实践
- 精通 Java 匿名内部类:定义、语法与实战示例
- 精通 Java Try-With-Resources:自动资源管理详解
- Java 注解详解:类型、放置位置与实战示例
- Java 断言实战指南:尽早发现 Bug 与保障代码可靠性
- 深入理解 Java Vector:用法、特性及与 ArrayList 的对比
- Java Applet 详解:基础概念、生命周期与核心差异