按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
的环境,因此不但考虑到同其它的应用程序构建环境竞争,而且Java 还促进它们的发展。这些工具被认真地
使用,它们必须支持Java Beans。这意味着一个平等的应用领域:如果一个更好的应用程序构建工具出现,
我们不需要去约束它就可以使用——我们可以采用并移动到新的工具上工作即可,这会提高我们的工作效
率。这种竞争的环境对应用程序构建工具来说从未出现过,这种竞争能真正提高程序设计者的工作效率。
485
…………………………………………………………Page 487……………………………………………………………
13。21 练习
(1)创建一个有文字字段和三个按钮的程序片。当我们按下每个按钮时,使不同的文字显示在文字段中。
(2)增加一个复选框到练习 1 创建的程序中,捕捉事件,并插入不同的文字到文字字段中。
(3)创建一个程序片并增加所有导致action()被调用的组件,然后捕捉他们的事件并在文字字段中为每个组
件显示一个特定的消息。
(4)增加可以被 handleEvent()方法测试事件的组件到练习3 中。过载handleEvent()并在文字字段中为每个
组件显示特定的消息。
(5)创建一个有一个按钮和一个TextField 的程序片。编写一个handleEvent() ,以便如果按钮有焦点,输入
字符到将显示的TextField 中。
(6)创建一个应用程序并将本章所有的组件增加主要的帧,包括菜单和对话框。
(7)修改TextNew。java,以便字母在t2 中保持输入时的样子,取代自动变成大写。
(8)修改CardLayout1。java 以便它使用Java 1。1 的事件模型。
(9)增加Frog。class 到本章出现的清单文件中并运行jar 以创建一个包括Frog 和 BangBean 的JAR 文件。现
在从SUN 公司处下载并安装 BDK 或者使用我们自己的可激活Bean 的程序构建工具并增加 JAR 文件到我们的环
境中,因此我们可以测试两个 Bean 。
(10)创建我们自己的包括两个属性:一个布尔值为“on”,另一个为整型“level”,称为Valve 的Java
Bean 。创建一个清单文件,利用jar 打包我们的 Bean ,然后读入它到beanbox 或到我们自己的激活程序构建
工具里,因此我们可以测试它。
(11)修改Menus。java,以便它处理多级菜单。这要假设读者已经熟悉了 HTML 的基础知识。但那些东西并不
难理解,而且有一些书和资料可供参考。
486
…………………………………………………………Page 488……………………………………………………………
第 14 章 多线程
利用对象,可将一个程序分割成相互独立的区域。我们通常也需要将一个程序转换成多个独立运行的子任
务。
象这样的每个子任务都叫作一个“线程”(Thread)。编写程序时,可将每个线程都想象成独立运行,而且
都有自己的专用CPU。一些基础机制实际会为我们自动分割CPU 的时间。我们通常不必关心这些细节问题,
所以多线程的代码编写是相当简便的。
这时理解一些定义对以后的学习狠有帮助。“进程”是指一种“自包容”的运行程序,有自己的地址空间。
“多任务”操作系统能同时运行多个进程(程序)——但实际是由于CPU 分时机制的作用,使每个进程都能
循环获得自己的CPU 时间片。但由于轮换速度非常快,使得所有程序好象是在“同时”运行一样。“线程”
是进程内部单一的一个顺序控制流。因此,一个进程可能容纳了多个同时执行的线程。
多线程的应用范围很广。但在一般情况下,程序的一些部分同特定的事件或资源联系在一起,同时又不想为
它而暂停程序其他部分的执行。这样一来,就可考虑创建一个线程,令其与那个事件或资源关联到一起,并
让它独立于主程序运行。一个很好的例子便是“Quit ”或“退出”按钮——我们并不希望在程序的每一部分
代码中都轮询这个按钮,同时又希望该按钮能及时地作出响应(使程序看起来似乎经常都在轮询它)。事实
上,多线程最主要的一个用途就是构建一个“反应灵敏”的用户界面。
14。1 反应灵敏的用户界面
作为我们的起点,请思考一个需要执行某些CPU 密集型计算的程序。由于 CPU “全心全意”为那些计算服
务,所以对用户的输入十分迟钝,几乎没有什么反应。在这里,我们用一个合成的applet/application (程
序片/应用程序)来简单显示出一个计数器的结果:
//: Counter1。java
// A non…responsive user interface
package c14;
import java。awt。*;
import java。awt。event。*;
import java。applet。*;
public class Counter1 extends Applet {
private int count = 0;
private Button
onOff = new Button(〃Toggle〃);
start = new Button(〃Start〃);
private TextField t = new TextField(10);
private boolean runFlag = true;
public void init() {
add(t);
start。addActionListener(new StartL());
add(start);
onOff。addActionListener(new OnOffL());
add(onOff);
}
public void go() {
while (true) {
try {
Thread。currentThread()。sleep(100);
} catch (InterruptedException e){}
if(runFlag)
t。setText(Integer。toString(count++));
487
…………………………………………………………Page 489……………………………………………………………
}
}
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
go();
}
}
class OnOffL implements ActionListener {
public void actionPerformed(ActionEvent e) {
runFlag = !runFlag;
}
}
public static void main(String'' args) {
Counter1 applet = new Counter1();
Frame aFrame = new Frame(〃Counter1〃);
aFrame。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
aFrame。add(applet; BorderLayout。CENTER);
aFrame。setSize(300;200);
applet。init();
applet。start();
aFrame。setVisible(true);
}
} ///:~
在这个程序中,AWT 和程序片代码都应是大家熟悉的,第 13章对此已有很详细的交待。go()方法正是程序全
心全意服务的对待:将当前的 count (计数)值置入TextField (文本字段)t,然后使count 增值。
go() 内的部分无限循环是调用sleep()。sleep()必须同一个 Thread (线程)对象关联到一起,而且似乎每个
应用程序都有部分线程同它关联(事实上,Java 本身就是建立在线程基础上的,肯定有一些线程会伴随我们
写的应用一起运行)。所以无论我们是否明确使用了线程,都可利用Thread。currentThread()产生由程序使
用的当前线程,然后为那个线程调用sleep()。注意,Thread。currentThread()是 Thread 类的一个静态方
法。
注意 sleep()可能“掷”出一个 InterruptException (中断违例)——尽管产生这样的违例被认为是中止线
程的一种“恶意”手段,而且应该尽可能地杜绝这一做法。再次�