1
第一章
Java 的类
北京大 学计算机系 代亚 非
2
• • • • • • • • • •
第一章 Java 的类 1.1 有关面向对象的 概念 1.2 Java 语言的 特点 1.3 Java 的开发 环境 1.4 第一个 Java 程序 1.5 Java 类型系 统 1.6 Java 中字符 串的类 1.7 Java 中的类 、方法和变 量 1.8 Java 名空间 及访问规则 1.9 Java 中的抽 象类、接口 和程序包 1.10 对象的构造 函数
3
1.1 有关面 向对象的概 念 • 什么是类? • 类是描述对象的 “基本原型 ”,它定义 一 种对象所能拥有 的数据和能 完成的操作 , 在面向对象的程 序设计中 , 类是程序的 基 • 本单元。 程序中的对 variables 象 是类 的一个实例, 是一个软件单 元,它由一组 methods 结构化的数据 和在其上的一
4
• • • • • • • •
1.1 有关面 向对象的概 念 变量:即指对象 的所知道的 状态 方法:指对象的 功能单元。 什么是消息? 软件对象通过相 互间传递消 息来相互作 用 和通信 message 一个消息由三部 分组成 : 1. 接受消 息的对象 对象 B 2. 要完成 方法的名字 3. 方法需 要的参数 对象 A
5
1.1 有关面 向对象的概 念 • 一个例子 class Hello {
}
private String s ; public void showString ( ) { System.out.println(s);} public void changeString(String str) { s=str; return s;}
• 在程序中操作对 象是类的一 个实例 : 即对 象 • 创建一个对象 Hello obj=new Hello(); • 调用方法 obj.showString(“Hello World!”)
6
1.1 有关面 向对象的概 念 • 什么是封装 ? • 封装把对象的所 有组成部分 组合在一起 , 封装定义程序如 何引用对象 的数据,封 装 实际 上使用 方法将类 公有数据 的数据 隐藏起来 数据 私有 数 ,控制 用户对类 据 的修改 和访问数 方 据的程 度。 方 法 对象 A
法
对象 B
7
1.1 有关面 向对象的概 念 • 什么是子类 ? • 子类是作为另一 个类的扩充 或修正所定 义 的一个类 . bicycle (super class)
sub class
Mountain bikes
Racing bikes
Tandem bikes
8
1.1 有关面 向对象的概 念 • 什么是继承 ? • 继承是子类利用 父类中定义 的方法和 变量 就像它们属于子 类本身一样 . class Car { int color_number; int door_number; int speed;
class Trash_Car extends Car { double amount; fill_trash() { … }
push_break() { … } add_oil() { … } }
}
9
1.1 有关面 向对象的概 念 • 什么是方法的覆 盖 ? • 在子类中重新定 义父类中已 有的方法。 class Car { int color_number; int door_number; int speed; push_break() { speed=0; } add_oil() { … } }
class Trash_Car extends Car { double amount; fill_trash() { … } push_break() { speed=speed-10; } }
10
1.1 有关面 向对象的概 念 • 什么是 方法的重载 ( 多态性 ) ? • 在同一 个类中至少 有两个方 法用同一个 名 字,但 有不同的参 数。 123
类
1.23
void show(int int_num) void show(double double_num)
123,1.23
void show(nit nit_ um, float float_um)
11
1.2 Java 语言的 特点 • Java 是什么? Java= “C++”--“ 复杂 性和奇 异性 ” +“ 安全 性和 可移 植性”
• • • • •
Java 由那些特性 ? (1) 面向对象 封装性、多态性 、继承性、 动态链接 (2) 操作平 台无关性 严格的语言定义 :“ 没有依 据机器的不 同 而不同” 或“由 编译器决定” 等字眼 , 最后的目标码都 是一致的 , 初值都 是确定
12
1.2 Java 语言的 特点 • 两种工作模式的 比较
源 程 序
Java 编译器
Java 解释器
Powerpc
Powerpc
pentium
中 间 码
pentium
SPARC
二进制
编译器
Powerpc 源 程 序
pentium
二进制
Powerpc
pentium
SPARC SPARC
SPARC
13
1.2 Java 语言的 特点 • . 编译 , 没有绝对地 址
Java 源程序 (.java 文件 ) Java 编译器
调入包含 , 继承 所 用道的所 有类 , 内 存分配确 定 , 编程 真正可执 行的 机器 码
Bytecode 载入器 字节码 校验器 Bytecode 解释器
Java Bytecode (.class 文件 ) 系统执行平 台
不存 在伪 造的指 针 不违 反访 问权限 不非 法访 问对象 不导 致操 作栈溢 出
14
1.2 Java 语言的 特点 • Java 虚拟机
不同的 操作系 统有 不同的 虚 Java Just-in-time 拟机 . interpreter compiler 它类似 一个小 巧而 高效的 CPU. byte-code 代码是 与平台 无关 的 是虚拟 机的机 器指 令 . Runtime System Java 字节代 码运行 的两 种方式 : interpreter( 解释方 式 ) Operating System Just-in-time( 即时 编译 ): 有代 码 生成器 将字节 代码 转换成 本机 的机器 代码 , 然后可 以以 较高速 Hardware 度执行 .
15
1.2 Java 语言的 特点 • (3) 安全问 题 • Java 是在网络环 境下使用的 语言 • 一个安全的网络 至少要防止 以下几种破 坏 的可能性 : • 毁灭系统资源 • 消耗系统资源 • 挖掘系统或个人 机密 • 骚扰正常工作的 进行
16 public protecte d private final 语言定 义
取消指 针 自动回 收 垃圾
1.2 Java 语言的 特点
限定对 象的 存取权 限 系统堆 栈溢出 参数类 型一致
Java 源程序 (.java 文件 )
Bytecode 载入器
Java 编译器
Bytecode 解释器
Java Bytecode (.class 文件 )
Bytecode 检查
程序执 行系统 系统执行平台 WWW 浏览器 限制 Java 小应用 程序 的不正 当使用
17
1.2 Java 语言的 特点 • (4) 多线程 • Java 提供 现成 的类 Thread ,只要 继承这 个类 就 可以编 写多线 程的 程序。 • (5) Java 与 C 及 C++ 的区 别 • 不再有 #include 和 #define 等于处 理功能 • 不再有 structure,union 及 typedef • 不再有 函数、 不再 有指针 、不 再有多 重继 承 • 不再有 goto • 不再有 操作符 重载 (Operatior Overloading) • 取消自 动类型 转换 , 要求强 制转换
18
1.3 Java 的开发 环境 • Java 开发环境 JDK • JDK 中有 Java 编译器和 bytecode 解释器 Applwtviewer 是小应用程序的 bytecode 解 释器 • JDK 的安装 • 直接执行 JDK.exe
19
1.3 Java 的开发 环境 产生如 下目 录结构
java\bin 的目录 下包含义下 主要文件 : javac: Java 编译器 , 用来将 java 程序编译成 Bytecode java: Java 编译器 , 执行已经转换成 Bytecode 的 java 应用程序 . jdb: Java 调试器 , 用来调试 java 程序 javap: 反编译 , 将类文件还原回 方法和变量 . javadoc :文档 生成器 , 创建 HTML 文件
20
1.3 Java 的开发 环境 • \java\lib 子目录 • 库函数 , 其中 classese.zip 不要解开 . • 在 autoexec.bat 中加入以下两条 命令 1. PATH c:\…\java\bin 2. SET CLASSPATH=. ; c:\...\lib\classes.zip; c:\myclasses;
21
1.3 Java 的开发 环境 C:\
java bin javac
lib classes.zip appletviewer
java
用户类 文件 所在目 录 myclasses
当前目 录
22
1.3 Java 的开发 环境 • • • • • • •
vj1.1++ 的使用 1. 进入 vj, 创建一个 project 2. 加入 java 文件 3. 编辑 java 文件 4. 编译 java 文件 5. Build 一个 project 文件 6. 运行 java 程序 -- 如果是 小应用程序 , 则直接在 VJ 环境 下运行
23
1.4 你的第一个 Java 程序 • Java 应用和 Java 小应用程序 class HelloWorldApp { public static void main(String args[]) { System.out.println(“Hi, ”+args[0]); } }
• 编辑存盘:主类 名 ( 含有 main 方法 ) 和 文件名 要一致性 HelloWorldApp.java • 编译程序 : javac HelloWorldApp.java • 运行程序 : java HelloWorldApp “myjava” • 运行结果 : Hi, myjava
24
1.4 你的第一个 Java 程序 public class HelloWorldApp { public static void main(String args[]) { System.out.println(“Hi, ”+args[0]); }}
1. 声明一 个类 : public class HelloWorldApp{} , 类名的第一 个字母要 大写 2. 一个类 中可有很多 方法 , main 方法是运 行程序的第一个 方法,方法 名的第一个 字母要小写 . 3. System.out.println 是向屏幕输出 , 相当于
25
1.4 你的第一个 Java 程序 public class HelloWorldApp { public static void main(String args[]) { System.out.println(“Hi, ”+args[0]); }}
4. 命令行参数 的获取 c:>java HelloWorldApp myjava! 6. 字符串的拼 接
26
1.4 你的第一个 Java 程序 Java 小应用程序不 能直接执 行和使用 , 必须 要在浏 览器中执 行 import java.applet.Applet; import java.awt.*; public class HelloApplet extends Applet { public void paint(Graphics g) { g.drawString(“Hello World”,0,50); } }
编辑 存盘: 主类 名 (extends Applet) 和文 件名一 致 编译 代码 : javac HelloApplet.java 编写 HTML 文件 : HelloApplet.html
27
1.4 你的第一个 Java 程序
•运行 applet 程序 : 1. appletviwer HelloApplet.html 2. 在浏览器中运行 • 运行结 果 : Hello World!
28
1.4 你的第 一个 Java 程序 import java.applet.Applet; import java.awt.*; public class HelloApplet extends Applet { public void paint(Graphics g) { g.drawString(“Hello World”,0,50); } }
• 理解程序 1. import 语句相 当于 C 语言中的 include 每 2. 每一个 applet 都是 java.applet.Applet 的子 类 用 extends 继承 3. applet 中没有 main 方法
29
1.4 你的第一个 Java 程序 import java.applet.Applet; import java.awt.*; public class HelloApplet extends Applet { public void paint(Graphics g) { g.drawString(“Hello World”,0,50); } } 4. 当 applet 被浏 览器运 行时 ,paint 语句自 动执 行 5. 在 applet 中与 屏幕输 出有 关的操 作通 过 Graphics 对象 来实现 6. 一个 Java 源文件内 最多 只能有 一个 public 类 , 称为主 类,且 必须 和文件 名同 名
30
1.5 Java 类型系统 Java type system
primitive char
numeric
integral
byte
short
reference
boolean class interface array floating-point
int
long
null
float
double
31
1.5 Java 类型系统 • byte 8 位 (byte) 0 • short 16 位 (short) 0 • int 32 位 0 • long 64 位 0L • float 32 位 准 0.0f
2 的补码 2 的补码 2 的补码 2 的补码 IEEE 754 浮点数标
32
1.5 Java 类型系统 • 程序 : 保留字 , 标识符 ( 类名、域名 、方法 名、符号常量、 局部变量, 标号、… ) , 操作符、界定符 ,字面常量 。 • 声明一个变量 • int data=10; Boolean isAlived; • Java 中的操作符 : 与 C 基本一致 • Java 中不再有指 针了
33
•
•
•
•
1.5 Java 类型系统 在 Java 中”引用“是指 向一个对象 在内 存中的位置 , 在本质上是 一种带有很 强的 完整性和安全性 的限制的指 针 . 当你声明某个类 , 接口或 数组类型的 一个 变量时 , 那个变量的值总 是某个对象 的引 用或者是 null 引用 . 指针就是简单的 地址而已 , 引用除了 表示 地址而外 , 还象被引用的数 据对象的 缩影 , 还提供其他信息 . 指针可以有 ++,-- 运算 , 引用不可以运算 .
34
1.5 Java 类型系统 例 : String s1;String s2; s1=“a string”; s2=s1; class Mydate { int year; int month; int day; }
s1
10001
s2
10001
a string
0 today 10008
Mydate today=new MyDate()
0 0
35
1.5 Java 类型系统 • 能够动 态取得的内 存有两种 , 一种是 对象 实体 , 一种数 组 . • Java 用 new 申请内存 , 不需要 自己释放不 用的内 存 . • 在 Java 中,定 义数组时 不必给出数 组的 大小, 因为 Java 的数组 是动态分配 的。 • 数组变 量实际上是 一个引用 变量,因此 要 实例化 才能使用。 • 例: int Array[] ; Array=new int[8] ;
36
1.5 Java 类型系统 • 例: String arrayOfString[]=new String[10] ;每个数组 元素包含一 个对字 符串对象的引用 ,此时值分 配了包含字 符 串引用的空间, 并没有对字 符串本身分 配 内存,此时不能 访问。 arrayOfString[0] 对 arrayOfString arrayOfString[1] 字 符 对数 组的 引用 arrayOfString[8] 串 arrayOfString[9] 的 引 for(int i=0;i<arrayString.length;i++) 用
arrayOfString[i]=new String(“Hello”+i)
37
• • • • • • • • • •
1.6 Java 中的字 符串
Java 中的 字符 串类 String 和 StringBuffer String 类的 定义和 实例 的生成 例 : String str; str=“this is a string” 或 : String str1=new String(“hello”); 或 : String str2=“aaaa”; String 类与 其它类 型的 转换 例 1: 将实型数转换成字符串 . System.out.println(String.valueOf(Math.PI));
38
1.6 Java 中的字 符串 • • • • • • • •
有两个字符串 str1,str2 str1=str2; 是指 两个引用指 向同一个地 址 str1.equals(str2) 是指两个字符串 内容相等 获取 String 对象的信息 例如: String s=“this is a string”; int len=s.length(); boolean result=s.equal(“this is a 特 test”);
39
1.6 Java 中的字 符串 • StringBuffer 的字符 串的内容是 可以改变 的 • 创建 StringBuffer 对象 • StringBuffer str=new Stringbuffer(“hello”); • 获取 StringBuffer 对象的信 息 • 例int len=str.length(); :StringBuffer sb=new StringBuffer(“Drink Java!”); sb.insert(6,”Hot ”); System.out.println(sb.toString()); Drink Hot Java!
System.out.println 接受的是 String
40
1.7 Java 中的类、方 法和变量 • 试用一 个简单的 类 class CarDemo { public static void main(String args[]) { Car Democar=new Car(); DemoCar.set_number(3838); class Car DemoCar.show_number(); { int car_number; }} void set_number(int car_num) { car_number=car_num;} My car number is 3838
void show_number() { System.out.println (“My car No. is :”+car_number); } }
41 class TrashCar extends Car { int capacity; 1.7 Java 中的类、方 法和变量 void set_capacity(int trash_car_capacity) • 类的继承 { capacity=trash_car_capacity;}
关系
void show_capacity(); { System.out.println(“My capacity is: ”+ capacity);}}
class Car { int car_number; void set_number(int car_num) { car_number=car_num;}
void show_number() {System.out.println (“My car No. is :”+car_number); } }
42
1.7 Java 中的类、方 法和变量 • TrashCar 中继承了 Car 中的两 个方法 class CarDemo { public static void main(String args[]) { TrashCar DemoTrashCar=new TrashCar(); DemoTrashCar.set_number(4949); DemoTrashCar.set_capacity(20); DemoTrashCar.show_number(); DemoTrashCar.show_capacity(); } }
Car 是父类 , TrashCar 是子类
43
1.7 Java 中的类、方 法和变量 • 何时选择继承性 ? • 一个很好的经验 : “B 是一个 A 吗 ?” • 如果是则让 B 做 A 的子类 . 常犯的 错误 A 有一个 B 吗 ? 例如 让汽车 轮子成为 汽车的子类 是错 误的
44
1.7 Java 中的类、方 法和变量 • 类的严格定义及 修饰字public, abstract, final 或者没 有 [ 类的修饰 字 ] class 类名 称 [extends 父类 名称 ] { …. }
•方法和变量的定 义及修饰字 public 、 protected 、 private
[ 变量 修饰 字 ] 变量数 据类型 变 量名 1, 变量名 2[= 变量初值 ]…;
[ 方法修饰 字 ] 方法的 返回值 类型 { …// 方法的内 容 }
方法名 称 ( 参数 1, 参数 2,…
45
1.8 Java 名空间 及访问规则 • 每个类都创造了 有自己的名 字空间,指 方法 和变量可以知道 彼此的存在 ,可以使用 。 • abstract 类不能直接产生 属于这个类 的对象 • final 类不能被其他 任何类所 继承 ( 安全的 考 虑) • public 类不但 可以被同一 程序包中的其 它类 使用 , 别的程 序包中的类 也可以使 用 . • friendly( 缺省 ) 类只能被 本包中的 其它类使 用
46
1.8 Java 名空间 及访问规则 • 变量和方法的修 饰字 public 、 protected 、 private
• public: 任何其它类 、对象只 要可以看到 这个类的话,那 么它就可以 存取变量的 数 据,或使用方法 。 class ABC { public int pub_i=5 ; public void show)() { System.out.println (“pub_i”+pub_i); }
47
1.8 Java 名空间 及访问规则 class Demo { public static void main(String args[]) { ABC abc=new ABC(); System.out.println(“abc.pub_i”+abc.pub_i); abc.pub_i=10; abc.show(); } abc.pub_i=5 } pub_i=10;
48
1.8 Java 名空间及 访问规则 • protected 变量和方法 • 如果一个类中变 量或方法有 修饰字 protected ,同一类, 同一包可以 使用。不 同包的类要使用 ,必须是该 类的子类可 以 存取变量或调用 public class ABC { protected int pro_i=5; protected void show() { System.out.println (“pro_i=” +pro_i;) } }
49
1.8 Java 名空间及 访问规则 • 不同中的类不能 使用 class DEF { public static void main(String args[]) { ABC abc=new ABC(); System.out.println (“abc.pro_i=“+abc.pro_i); abc.pub_i=10; abc.show(); } }
50
1.8 Java 名空间及 访问规则 • 不同包但是是子 类 import mytest.pack.ABC; class DEF extends ABC { public static void main(String agrs[]) { DEF def=new DEF(); System.out.println(def.i); def.i=10; def.show(); } }
pro_i=5 pro_i=10
51
1.8 Java 名空间 及访问规则 • • • •
private 不允许任何其他 类存取和调 用 friendly( 前边没有修 饰字的情况 ) 在同一程序包中 出现的类才 可以直接使 用 它的数据和方法 .
52
1.8 Java 名空间 及访问规则 • 当子类中的变量 名与父类的 相同 , 原来的 变量被遮盖 . class demo { public static void main(String args[]) { C c=new C(); c.println_out(); }} class A { int data_a=3;} data_a=5 class B extends A { int data_a=5;} A.data_a=3 class C extends B B.data_a=5 { void print_out() { System.out.println(“data_a= ”+data_a); System.out.println(“A.data_a= ”+A.data_a); System.out.println(“B.data_a= ”+B.data_a); }}
53
1.8 Java 名空间 及访问规则 • 方法的覆盖 (overriding) 和重载 (overloading) • 子孙类中定义的 方法和祖先 类中某个方 法 同名 , 同参数 行 , 则祖先 类中的该 方法被 覆盖 . • 方法的重载是指void 一个对象的 多态性 , 即多 show(int int_num) 123 个方法用相同的 名称 , 但参数行不同 . 类
1.23
void show(double double_num)
123,1.23
void show(nit nit_ um, float float_um)
54
• • • • • •
1.8 Java 名空间 及访问规则 到此为止 -----final final 在方法之前 , 防止该方 法被覆盖 . final 在类之前 , 标是该类不 能被继承 final 在变量之前 , 定义一个 常量 . b 属于类的变量和 方法 ----static object char data static 在变量或方法之 前 , b static int object c 表明它 们是属于类 的 object ,char data share_data class ABCD { char data; static int_share_data; } class Demo { ABCD a,b,c,d}
char data
Object b char data
55
1.8 Java 名空间 及访问规则 • 静态变量在各实 例间共享 • 如果是 public 静态变 量 , 则其它 类可以不 通过实例化访问 它们 • 静态方法称为类 的方法 , 因此不用实 例化 即可调用 ( 面向过 程 ) • 一个对象的方法 可以访问对 象的数据成 员 , 尽管 不属于方法 的局部变量 • 一个类的方法只 能访问自己 的局部变量
56
• • • • • • • •
1.8 Java 名空间 及访问规则 例 : 不正确的引 用 class StaticError { String mystring=“hello”; public static void main(String args[]) { System.out.println(mystring);} } 错误信息 :can’t make a static reference to nonstatic variable. 为什么不正确 ? 只有对 象的方法可 以访问 对象的变量 .
57
1.8 Java 名空间 及访问规则 • • • • • • •
解决的办法 : 1. 将变量 改称类变量 class StaticError { static String mystring=“hello”; public static void main(String args[]) { System.out.println(mystring);} }
58
1.8 Java 名空间 及访问规则 • • • • • • • •
2. 先创建 一个类的实 例 class NoStaticError { public static void main(String args[]) { String mystring=“hello”; System.out.println(mystring);} } }
59
1.9 Java 中的抽象类、 接口和程 序包 • 抽象类是指不能 直接被实例 化的类 , 因此 一般作为其它类 的超类 , 与 final 类正好相 反 • 抽象类中的抽象 的方法 - 在该类中定义但 不在该类中提供 实现 , 由继承类提供细 节 • public abstract class SomeAbstractClass • { void method1() • { System.out.println(“Hi, Java”);} • void method2(); • }
60
1.9 Java 中的抽象类 、接口和程 序包
// 已有两个 类 Circ le 和 Recta ngle , 完成相 关参 数的计 算 cla ss Ci rcle { p ublic int r; Circle( int r) {t his.r= r} / /this 指 " 这个 对象的 " public int area( ) {ret urn 3*r*r ; } // 取 近似 } cla ss Re ctan ge { p ublic int width ,heig ht; // 这里不 需 "this " Rectang le ( int w , int h)
61
1.9 Java 中的抽象类、 接口和程 序包 • 假设有 若干个 Circle, 以及 若干 个 Rectangle, 希望 计算它 们的总 面积 , 直截了 当的做 法是 将它们 分 别放到 两个数 组中 , 用两个 循环 , 加上一 个加 法 , 这种做 法是不 漂亮 的 • 如果还 有其它 形状 ,triangle,ellipses 等 , 上述 方法 显得“ 累赘” , 我们 希望有 一种 统一的 表示 , 例 如用一 个数组 shape[], 接受 所有 的形状 , 然后用
• for (i=0; i<sha pe.le ngth; i++) { • ar ea_to tal+= shape [i].a rea() ;
62
abstract 1.9class JavaShape 中的抽象、接口 和程序包 { abstract float area();} class Circle extends Shape { public int r; Circle(int r) {this.r=r;} public float area() { return 3.14*r*r; } } class Square extends Shape {public int width,height; Rectangle (int w, int h){ width=w,height=h;} public float area() {return width*height; }
63
1.9 Java 中的抽象类 、接口和程 序包 • 利用接 口可实 现多 重 继承 ( 可同时 实现多 个接口 ) • 接口的 作用和 抽象 类 类似 , 指定原 型 , 不 直 接定义 方法 的内容 . • 关键字 implement 用 来实现 方法 , 即在使 用 时要用 给出方 法的 实
interface Stack { void push(object x); object pop();} class A extends Applet implements Stack { void push(object x) { …;// 具体内 容 } object pop() { …;// 具体内 容 } }
64
1.9 Java 中的抽象类 、接口和程 序包 • 程序包: 相当于 其它语言中 的库函数 • 打包 package Graphics; class Square {…;} class Circle {…;} class Triangle {…;}
• 使用程序包中的类要用 import 命令 . 表示路 径 ,* 表示使用包中的所有类 java • import java.io.FileInputStream ; io • import java.io.* ;
FileInputStream
65
1.10 对象的构造函数
class Demo1 // 数组的 配置 •{ public 使用 new static来做内存配置 void main(String args[]) { int array[][]; array=new int[5][5]; array[1][4]=5; } class myClass // 对象实 体的 产生 } { int data=5;} class Demo2 { public static void main(String args[]) { myClass obj;// 建立一 个引用 obj=new myClass(); System.out.println(obj.data); }}
66
1.10 对象的构造函数 • Constructor 和 finalizer • constructor( 构造函数 ), 在一个类中和类同名 的方法叫构造函数 . 系统在产生对象时会自 动执行 . class UsePoint
class Point { Point point_A=new Point(); { int x,y; Point point_B=new Point(5,7); Point() } { x =0;y=0;} Point(int new_x,int new_y) { x=new_x,y=new_y;} }
67
1.10 对象的构造 函数 • 构造函数应包含 哪些内容 ? • 构造函数多半定 义一些初值 或内存配置 工 作 • 一个类可以有多 个构造函数 ( 重载 ), 根据 参数的不同决定 执行哪一个 . • 如果程序中没有 定义构造函 数 , 则创造 实 例时使用的是缺 省函数 , 它是一个无 内容 的空函数 .
68
1.10 对象的构造函数 • this • this 指自己这个对象 • this 的作用是要将自己这个对象当作参数 , 传 送给别的对象中的方法 . class ThisClass { public static void main() { Bank bank=new Bank(); bank.someMethod(this); } }
class Circle { int r; Circle(int r) {this.r=r;} public area() { return r*r*3;} }
69
• • • • • • • •
1.10 对象的构造 函数 super 指这个对象的父类 super 用来引用父类中的方法及变量数据 . public class apple extends fruits { public apple(int price) { super(price); } } 以上句子表示使用超类的构造函数生成实例 super 必须是子类构造器的第一条语句
70
小结 • 一个 Java 程序 ( 包括小应用 程序 ) 由若干 个类组成 , 它们分布在由 CLASSPATH 指 定的一个目录中 • 一个 Java 程序中只能由一 个主类 , 并且与 文件同名 . • CLASSPATH 指定多 个目录 , 它们和起来 被看成是这个目 录的根 , 根中的类构 成缺 省包 • 目录树中每个子 目录中的类 的集合对应 Java 一个包 (package), 子目录的层 次与包
71
小结 C:\
package myclass.calculate class A{} class B{} classC{}
java lib bin javac
classes.zip appletviewer
java 让 PATH 包含 … \java\bin SET CLASSPATH =.; C:\...\myclasses
javasource
myjava.java
myclass calculate A
B
C
import java.io.*; import java.awt.Graphics; import mycalss.calculate.*; public class test {}
72
小结 • 名空间及访问规 则 • --package,class/object,member, 局部变量 • --public ,private,protected,default 成员的可 视性描 述 public protected 缺省 private 同一 类中 同一 包中 不同包 的 子类中 非子类 也不同 包
yes yes
yes yes
yes yes
yes no
yes
yes*
no
no
yes
no
no
no
73
小结 • • • •
对象模型 ---Java 的类 和对象 ( 一般 , 抽象 , 接口 ) -- 继承机 制 ( 单继承 , 多实现 ) static, import, final 的含义 和作用
74
小结 • 避免在类中使用 太多的基本 类型 • • • • • • • • • •
private String senderName; private String senderStreet; private String senderCity; private String senderState; private String senderZip; private String receiverName; private String receiverStreet; private String receiverCity; private String receiverState; private String receiverZip;
address sender address receiver
75
第 2 章 Java 小应用 北京大 学计算机系 代亚 非
76
第 2 章 Java 小应用 • • • • • • • •
2.1 所有小应用程序 的根源 2.2 小试身手 2.3 图形操作 2.4 URL 类 2.5 载入现有图像文 件 2.6 动画效果 2.7 播放声 音 2.8 小 结
77
2.1 所有小应 用程序 的根源 • 2.1.1 小应用 的特点 • 回忆一下小应用 程序的书写 格式 import java.applet.*; public class MyApplet extends Applet { ;} • applet 都继承自 java.applet.Applet 类 , 由 Sun 公司事先定义好 了 . • 每个小应用都有 一个主程序 类 , 之前必 须 加上 public.
78
2.1 所有小应用程序的根源 http://someLocation/file.html 1. Browser loads URL <Applet code= ….> Applet class
2. Browser loads HTML document 3. Browser loads applet classes
Location: http://someLocation/file.html
Loading...
4. Browser run applet
79
2.1 所有小应 用程序 的根源 • Applet 的限 制 Browser
SERVER Applet 被下载的
SERVER
co
nn
ec ti
on
n n o c
n o i t ec
本地程 序
applet
file
local
与 applet 无关的 本地 方法
80
2.1 所有小应 用程序 的根源 • 2.1.2 applet 的生命周期 Java.applet.Applet public void init() public void start()
public void destroy() public void stop()
public void paint(Graphics g)
• paint() 虽不 在生命周期 内 , 但它的作用相 当于 applet 的灵魂
81
2.1 所有小应 用程序 的根源 • 一个 applet 的可视周期 init start 离开 web 页面 stop destroy
重新装 入或改 变页 面大小 或返回 Web 页面
82
2.1 所有小应 用程序 的根源 • 有关 paint() 方法 • Applet 本身 是一个容器 , 因此任 何输出都 必须用图形方法 paint() • 当小应用首次被 装载,以及 每次窗口放 大 、缩小、刷新时 都要调用 paint 方法 • paint() 是由 浏览器调用 的 , 而不是 由程序 调用,当程序希 望调用 paint 方法 时,用 repaint 命令 • paint 方法的参数 是 Graphics 类的对象 g ,它在 java.awt.Graphics 内
83
2.1 所有小应 用程序 的根源 AWT thread ( waiting ) repaint()
Exposure update () { clear arae call paint ()
paint ()
84
2.2 小试身手 • 2.2.1 起始页 上的时间和 日期 0Mon Dec 07 14:23:50 GMT+08:00 1998
• 介绍两个类 : 1. 类名 :Date 创建一 个实例 Date timeNow=new Date(); 2. 类名 Font 创建一个实 例 Font msgFont=new Font(“TimesRoman”,Font.ITALIC,30);
85
2.2 小试身手 看下 面的例 子 , 想一想 生命周 期的 四个方 法哪 去了 ? import java.awt.*; import java.util.Date; public class showDate extends java.applet.Applet { Date timeNow=new Date(); Font msgFont=new Font(“TimesRoman”,Font.ITALIC,30); public void paint(Graphics g) { g.setFont(msgFont); g.setColor(Color.blue); g.darwString(timeNow.toString(),5,50); }
86
2.2 小试身手 2.2.2 在起始 页中加入 applet • html 中有关的代码 <APPLET CODE=“showdate.class” width=600 height=80> • CODEBASE 的作用 当 class 文件与起始页文 件不在同一 个目 录下时 , 使用 CODEBASE 说明 <APPLET CODE=“showdate.class” width=600 height=80> CODEBASE=“\myjava\class”
87
2.2 小试身手 <APPLET <APPLET CODE=“showdate.class” CODE=“showdate.class” width=600 height=80> height=80> width=600 CODEBASE=“\myjava\class” public public Index.html Index.html
C:\C:\
myjava myjava javacode class javacode class
showdate
showdate
88
2.2 小试身手 • ALIGN,HSPACE,VSPACE 其它 文字 hspace
Java applet vspace
其它 文字
<APPLET CODE=“showdate.class” width=600 height=80> vspace=100 hspace=100
89
2.2 小试身手 • 向 applet 传递参数的 两个步骤 1. 在起始 页中要有
标签 2. 在 applet 中要有 getParameter 方法 在起始 页中有 :
在 applet 中有 : string title=getParameter(rem); 在显示 时间的命令 中加入 title:
90
2.2 小试身手 import java.awt.*; import java.util.Date; public class showDate extends java.applet.Applet { Date timeNow=new Date(); String title; Font msgFont=new Font(“TimesRoman”,Font.ITALIC,30); public void paint(Graphics g) { g.setFont(msgFont); g.setColor(Color.blue); g.darwString(title+ timeNow.toString(),5,50); }
public void init() {title=getParameter (“rem”); if (title==null) title=“”; }
91
2.2 小试身手 • 例 : 利用一个可 以显示运行 字符串的类 , 显 示自己的字符串 (htmlpara.html)
92
2.2 小试身手 public void init() { String paramete; parameter=getParameter("MESSAGE"); if (parameter!=null) message=parameter; parameter=getParameter("FONT"); if (parameter!=null) font_to_use=parameter; parameter=getParameter("POINT_SIZE"); if (parameter!=null) point_size=Integer.parseInt(parameter); }
93
2.3 图形处理 2.3.1 图形坐标系统 x 任何与 绘图有关的 操作 0 第一个 要用的是 java.awt.Graphics 类 Graphics 类的对象不是 y 由 new 产生的 , 而是由系 统或其 他方式直接 将生好的 Graphics 对象当 作方法 的参数 , 再交给程序设 计者去处 理 . 例如 : paint(Graphics g)
94
2.3 图形处理 • Graphics 的方法 paint(Graphics g) { g.clearRect(); g.copyArea(); g.drawAre() ; g.drawLine(); g.drawOval();g.drawRect(); g.drawPolygon(); g.fillArc(); g.fillOval(); g.fillPolygen(); g.fillRect(); g.getColor(); g.getFont() g.setFont(); g.setColor(); g.getFontMetrics() g.fillRoundRect() }
95
2.3 图形处理 2.3.2 字型和 颜色的设置 2.3.2.1 字型设置的 方法 Font font=new Font(“TimesRoman”,Font.ITALIC,24); g.setFont(font); • 在小应用程序中 显示输出的 方法 g.drawString(String, int x, int y); g.drawChars(char data[], int offset, int length, int x, int y);
96
2.3 图形处理 g.drawBytes(byte data[],int offset, int length, int x, int y); 例 :g.drawString(“This is a test”,5,10); • 获取字体的属性 Font font=g.getFont(); • Font 类中常用的 方法 GetFamily() getName() getSize() getStyle() isItalic() isPlain() isBold() toString()
97
2.3 图形处理 import java.awt.Graphics; import java.awt.Font; public class drawtext extends java.applet.Applet { Font fn=new Font("TimesRoman",Font.ITALIC,20); public void paint(Graphics g) { g.setFont(fn); g.drawString(”Font demo”,5,10); } } Font demo
98
2.3 图形处理 •获取更详细 的数据 请查阅 有关 FontMetrics 类的方 法 fontMetrics=getFontMetrics(font); •FontMetrics 中比较 重要的方法 有 : stringWidth, charWidth, getAscent, getDescent, getLeading, getHeigh
99
2.3 图形处理 2.3.2.2 颜色的调整 • Color 对象的使用 创造自 己的颜色 : Color mycolor=new Color(int red, int blue, int green);
• g.setColor(Color.yellow) • g.setColor(mycolor); • 例 : 随机产生颜 色 , 并画圆
100
2.3 图形处理 import java.awt.Graphics; import java.awt.Color; public class drawcircle extends java.applet.Applet { public void paint(Graphics g) { int red,green,blue,x; for (x=0;x<370;x+=30){ red=(int)Math.floor(Math.random()*256); green=(int)Math.floor(Math.random()*256); blue=(int)Math.floor(Math.random()*256); g.setColor(new Color(red,green,blue)); g.fillOval(x,0,30,30); }}}
101
2.4 URL 类 2.4.2 构造 URL 类 ( 全名 java.lang.URL) • 绝对 URL 的构造方法 : URL(String spec) 例 : URL url=new URL (http://www.hit.edu.cn/cv/index.html”) • 相对 URL 的构造方法 : 某绝对地址 : http://rainy.hit.edu.cn/test.html 在该目录下 有两个文件 mywork.html myfamily.html
102
2.4 URL 类 URL base=new URL(“http://rainy.hit.edu.cn”);
URL url1=new (base, “mywork.html”); URL url2=new (base, “mywork.html”); • 其他 URL 的构造方法 : URL url=new URL (“http”, “www.hit.edu.cn”,“/~dyf/test.html”);
103
2.4 URL 类 2.4.3 获取小 应用程序 HTML 页面 的 URL 和小应用程序本 身的 URL • • • •
URL html=getDocumentBase(); System.out.print(html); URL codebase=getCodeBase(); System.out.print(codebase); web page
html applet
浏览 器
服务器
104
2.4 URL 类 • 2.4.4 URL 异常 (MalformedURLException) 当创建 URL 时发生错误 , 系统会 产生异 常 try{ URL url=new URL(str); }catch(MalformedURLException( e) { DisplayErrorMessage();} • 2.4.5 URL 类的基本方法 String getProtocol(), String getHost(), ing getPort(), String getFile(),
105
2.4 URL 类 • 构造 URL 的实例 import java.net.URL; import java.net.MalformedURLException; public class Test { URL url1,url2,url3; void test() { try { url1= new URL(“file:/D:/image/example.gif”); url2= new URL(“http://www.hit.edu.cn/cv/”); url1= new URL(url2, “hit.gif”); }catch (MalformedURLException e); // 处理 例外 } }}
106
2.5 载入现有图像文件 Image 类 • java 支持 gif 和 jpg 两种格式的 图像 • 图像文件的 URL: URL picurl= new URL (“http://xxx.yyy.edu/Applet/img1.gif”); • 取一幅图像构成 图像对象 Image img1 = getImage(picurl); Image img2 = getImage(getCodeBase(), “img2.gif”);
107
2.5 载入现有图像文件 • 显示一幅图像 : g.drawImage(img1, x, y, this); g.drawImage(img1, x, y,Color.red, this); g.drawImage(image1, x, y,x2,y2,Color.red, this); 规定 尺寸
规定 背景
108
2.5 载入现有图像文件 • 完整的过程 不要忘记 AWT 包 定义 Image 对象了 吗?
在类中
指定图像的 URL 了 吗? 把图像取出来吧 .
在 init0 中
还记得画图像用什么方法和命令 吗?
在 paint0 中
109
2.5 载入现有图像文件 import java.applet.*;import java.awt.*; public class image extends Applet { Image img; public void init() { img=getImage(getCodeBase(),"img0001.gif");} public void paint(Graphics g) { int width=img.getWidth(this); int height=img.getHeight(this); g.drawRect(52,52,width+30,height+30); g.drawImage(img,57,57,width+20,height+20,this);}}
110
2.6 动态效果 --- 线程的应 用 2.4 动态效 果 --- 线程的应用 • 什么是线程 ? 线程是执行 中的程序中 的单个顺序控 开始 制流 . • Java 支持多线程 显示进 度
数学运 算
引出最 后结果
线程 1
线程 2
111
2.6 动态效果 --- 线程的应 用 • 静态的 情况 import java.applet.*; import java.awt.Graphics; public class maguee extends Applet { public void paint(Graphics g) { g.drawString("Hello, Java!",0,0); } }
112
2.6 动态效 果 --- 线程的应用 • 动态的 情况 ( 不是多 线程 ) public void init() { x=size().width; y=size().height/2; width=x; } public void paint(Graphics g) { while(true) { g.drawString("Hello, Java!",x,y); x-=10; if(x<0) x=width; } }
113
2.6 动态效果 --- 线程的应 用 • 实现一个线程 让 Applet 类去实现 Runable 接口 , 创建一个线程 类 改写方法 start, 在其中产生一个新的线程来 工作 改写 stop 方法 , 在其中编写结束线程的程 序代码 引入新的方法 , 将分给线程的工作写到 run 中
114
2.6 动态效果 --- 线程的应 用 第一步:实现 Runable 接口 public class xc extends java.applet.Applet implements Runnable { Thread smallthread=null; … } Thread 是一个类 , 只有是它的实例才能具有线 程的功能 主函数中要定义一个线程变量
115
2.6 动态效果 --- 线程的应 用 第二步 :改写 方法 start public void start () { if ( smallthread == null ) { smallthread= new Thread ( this ); smallthread.start(); // 从现 在开始 程序 由两个 线程 在执行 }} 第三步 :改写 stop 方法 public void stop () { smallthread.stop(); // 停止线 程 smallthread = null; // 释放线 程对象 }
116
2.6 动态效果 --- 线程的应 用 第四步 : 新的方法 run 将让线 程要做的事 放 run 中 public void run() { while (true) { repaint(); try {Thread.sleep(1000);} catch(InterruptedException e){} } }
117 import java.applet.*; import java.awt.Graphics; public class Applet用 2.6MovingCharacter 动态效果 ---extends 线程的应 implements Runnable { int x=200; Thread my_thread=null; //------------------------------------------------public void start() { my_thread=new Thread(this); my_thread.start(); } public void run() { while(true) { repaint(); try { Thread.sleep(100); } catch(InterruptedException e){} }}
118
2.6 动态效果 --- 线程的应 用 • .
public void stop() { my_thread.stop(); }
public void paint(Graphics g) { g.drawString("Hello, Java!",x,y); x-=10; if(x<0) x=200; }
119
2.6 动态效果 --- 线程的应 用 • 跳动的小球
up=false; x=x-10; if(x<0) x=width; if (up) y=y+10;else y=y-10; if (y<0) up=true; if (y>height) up=false; g.setColor(Color.red); g.fillOval(x,y,30,30);
120
2.6 动态效果 --- 线程的应 用 例 : 起始页上的小 时钟 一个必 须用到的类 ----Date 类 , 给出系统时 间 Date NowTime=new Date(); NowTime.getHours(), NowTime.getMinutes() 自己需 要写什么样 的类 ? (Hour*60*60+minute*60+second)/43200*2.0*PI Clock--把数字时间 成图形表示 (minute*60+second)/3600*2.0*PI second/60*2.0*PI
121
2.6 动态效果 --- 线程的应 用 主类 取时间
paint() {}
clock 类 clock(){} 初始化
Show(){} 换算 弧度
drawNiddle(){} 画图
122
class Clock 2.6 动态效果 --- 线程的应 用 {int hours,minutes,second,radius; Clock(int hrs,int min,int sec) { hours=hrs%12; minutes=min; second=sec; } void show(Graphics g, int x, int y,int redius) { int hrs_len=(int)(radius*0.5); int min_len=(int)(radius*0.7); int sec_len=(int)(radius*0.85); double theta; g.drawOval(x ,y, radius*2, radius*2);
123
theta=(double)(hours*60*60+minutes*60+second)/ 2.6 动态效果 --- 线程的应 用 43200.0*2.0*Math.PI; drawNiddle(g,Color.blue, x, y, hrs_len, theta); theta=(double)(minutes*60-second)/3600.0*2.0*Math.PI; drawNiddle(g,Color.blue, x, y, min_len,theta); theta=(double)second/60.0*2.0*Math.PI; drawNiddle(g,Color.red, x, y, sec_len, theta); }
124
2.6 动态效果 --- 线程的应 用 private void drawNiddle(Graphics g, Color c, int x, int y, int len, double theta) { g.setColor(c); g.drawLine(x,y,(int)(x+len*Math.sin(theta)), (int)(y-len*Math.cos(theta))); } }
125
2.6 动态效果java.util.Date; --- 线程的应 用 import java.awt.*;import public class ClockDemo extends java.applet.Applet { public void paint() { Date timeNow = new Date(); Clock myClock = new Clock(timeNow.getHours(), timeNow.getMinutes(), timeNow.getSeconds()); myClock.show(g,100,100,100); } }
126
2.6 动态效果 --- 线程的应 用 主类 生成时 间对象,取 时间 生成 Clock 对象,将时 间 传递给 Clock 对象
paint() {}
clock 类 clock(){}
Show(){}
drawNiddle(){}
初始 化
换算弧度
画图
127
2.6 动态效果 --- 线程的应 用 主类 start() 启动 新线 程
clock(){} 初始 化
stop()
paint()
run()
停止线 生成 clock 类实例 repaint() 程 clock 类 Show(){} 换算 弧度
drawNiddle(){} 画图
128
2.6 动态效果 --- 线程的应 用 例 : 在主 页上显 示 字 符串并 且颜 色从左 至右 不断 变化 让我们 来想 一想 : 需要那些 数据 成员 ? String msg, Font fnt, Color clr, spot_clr; Thread thread; String Msg="Welcome to HIT"; 需要哪 些方 法 ? init, start, stop, run, paint; public void init() { fnt= new Font("TimeRoman",Font.PLAIN,30); clr=new Color(255,0,0); spot_clr=new Color(0,0,255);
129
2.6 动态效果 --- 线程的应 用 run() 中做什 么 ? 反复调 用 repaint public void run() { while(true) { repaint(); try{Thread.sleep(50);} catch(InterruptedException e) {} } }
130
2.6 动态效果 --- 线程的应 用 paint() 中做 什么 ? 输出两 次字 符串 , 第一次 用一 种颜色 , 第二 次用另 一种颜 色 ( 该颜 色只作 用于 指定的 区域 )
You are Welcome to HIT g.clipRect(x,y,width,height) public void paint(Graphics g) { FontMetrics fntM=g.getFontMetrics(); int font_height=fntM.getHeight(); int base_line=size().height/2+font_height/2;
131
2.6 动态效果 --- 线程的应 用 g.setFont(fnt); g.setColor(clr); g.drawString(Msg,0,base_line); g.clipRect(strPt-50,0,str_bk_size,size().height);
g.setColor(spot_clr); g.drawString(Msg,0,base_line); strPt=(strPt+1)%(size().width+100); } }
132
2.6 动态效果 --- 线程的应 用 在 Java 中播放 动画 1. 需要多张图片 2 调用图片的方法 ? getImage, 3. 将多幅图像存入 图像对象数 组 Image frame[]=new Image[10]; for (int i=0;i
4. 显示图像
drawImage(x,y,0,0,this),
133
2.6 动态效果 --- 线程的应 用 import java.awt.*; public class nina extends java.applet.Applet implements Runnable {Image frame[]; Thread threadNina; int frame_i; int delay_time; public void init() { frame=new Image[10]; threadNina=null; frame_i=0; for (int i=0;i
134
2.6 动态效果 --- 线程的应 用 public void run() { while(true) { repaint(); try{ Thread.sleep(100);} catch(InterruptedException e) {} frame_i=(frame_i+1)%frame.length; } } public void paint(Graphics g) { g.drawImage(frame[frame_i],0,0,this);}
135
2.7 播放声音 java 支持 au 格式的 声音 两个方 法 : void play(URL url) void play(URL url, String name) 例 :play(getCodeBase(), “boing.au”); ( 注 : 它是一 次性的 ) 如果想 反复播放怎 么办 ? 借用类 AudioClip(loop(),play(),stop())
136
2.7 播放声音 例 :AudioClip bg_sound= getAudioClip(getCodeBase(), “boing.au”); bg_sound.play(); 或 : bg_sound.loop(); import java.applet.AudioClip; public class audio extends java.applet.Applet {AudioClip sound=getAudioClip(getCodeBase(),"boing.au"); public void start() { my_sound.loop(); } public void stop(){ { if(my_sound!=null) my_sound.stop();}}
137
2.7 播放声音 • 图像加声音岂不 是更有吸引 力 1. 在 init 中既取 图像也取声 音片断 frame[i]=getImage(getCodeBase(), "img000"+i+".gif"); SoundClip=getAudioClip(getCodeBase(),"boing.au");
2. 在 init 中加入 SoundClip.loop(); 3. 在 stop 中加入 if (SoundClip!=null) SoundClip.stop();
138
2.8 可通用的代码 • 同时包含 main() 方法和 init() 方法 • 由于 application 本身不是 图形环境 , 因此 需要在程序中加 入图形环境 , 以便可 以作 为普通的 application 使用 • import java.applet.Applet; import java.awt.*; • import java.awt.event.*; • import java.util.*;
139
2.9 小结
• 小应用程序是在 浏览器中运 行的 , 每个小应 用程序中必须有 一个主类 , 冠以 public, 并且 继承自 java.applet. • 小应用程序包括 生命周期的 四个环节和 paint() • 根据程序要求 , 用户可以 在主类中 定义其它 方法 , 或定义 其它类 . • public class myapplet extends Applet • { init() {…};start() {…}; • stop() {…};destroy() {…}; • paint(Graphics g){…} • }
140 init() applet 启动后 第一个 被执 行 , 在此初始 化
2.9 小结
applet 主类
start() init() 后被执 行 , 程序主 要代码 写在 此 paint() start() 后被执 行 , 写与输 出有 关的代 码 stop() 浏览 器变 换页面 时执 行 , 可以 省略 重写 destroy() 浏览器关 闭时 执行 , 可以省 略重写
Classes
自定义方 法 不能 自动 被执行 , 可以 由前 三 个方 法调 用 . 例如 : start() { mymethod()}
mymethod1 mymethode2
. Classes myclass =new Classes() .myclass.method1();
141
class Myclass { int v1; method(int num) {v1=num;} }
2.9 小结
public class Demo extends Applet { public void init() { Myclass test1=new Myclass(); test1.method(20); Myclass test2=new Myclass(); test2.method(10); } }
test1 v1 20
test2 v1 10
内存
142
2.9 小结 • 线程是实现动态 效果的核心 , 运行线程必 须继承 Thread 类或者实现 Runable 接口 . • run 是线程 的主体 , 它反复调用 repaint() 方 法 , 其中必 须有休眠 sleep(). • sleep() 语句要捕获中断 异常 ( 右面 讲 ) • try{Thread.sleep(100);} • catch(InterruptedException e) {} • 有线程的小应用 ,start(),stop() 方法必须重 写. • 需要获取网络资 源时 ( 包括本地资源 ), 要
143
第三章
事 件处理
北京大学计 算机系
代亚 非
144
第 3 章 事件处理 ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚
3.1 什么是事件 3.2 鼠标产生的事件 3.3 键盘产生的事件 3.4 动作事件 3.5 通用事件处理程序 3.6 发送自己的事件 3.7 Java 1.1 事件处理模型 3.9 小结
145
3.1 什么是事件 ❚ CGI 之外 的选择 form cgi www 浏览器 url Web server interact applet
外部程序 C 程序 数据库程 序
•
什么是 事件 ? 用户 用于交 互而 产生的 键盘 或
• •
鼠标动 作 . 响应 用户的 动作 称为处 理事 件 . 在类 Event 中 , 定义了 所有的 事件 处理方 法 , 小应用 已经继 承了 这些方 法 .
146
3.1 什么是事件 ❚ import java.awt.Event; ❚ Event 在 java.awt 包中 , 无论哪 个键 按下或 者 释放 , 还是鼠 标移动 , 按下 鼠标或 释放 鼠标 , AWT 都会 捕获 , 并产生 一个事 件 . ❚ 处理事 件的核 心是 重写处 理事 件的方 法 ❚ 通用方 法 : ❚ handEvent(Event evt, Object arg) ❚ 专用方 法 : ❚ MouseDown(Event evt, Object arg)
147
3.1 什么是 事件 ❚ Even t 类的 数据域 int clickCount
int id
int modifiers
int x
Event
int y
long when
int key
Object target
Ob je ct ar g
148
3.1 什么是 事件 如果你 不 覆盖你 要 处理的 方 法,则 缺 省的方 法 返回一 个 假值, 通 知系统 没 有处理 事 件
MouseUp() Event
MouseDown() MouseDrag()
HandleEvent()
MouseMove() MouseEnter()
action()
MouseExit() keyDown()
。
KeyUp()
149
3.2 鼠标产生的 事件 ❚ ❚ ❚ ❚ ❚ ❚ ❚
鼠标事 件的三 个参 数 : 1. 事件的 类型 ( 是移动 ? 托拽 ) 2. 是按下 还是 放开 ? 3. 鼠标的 位置 (x,y) 方法的 重写 : public boolean mouseDown(Event evt,int x,int y) {….}
150
3.2 鼠标产生的 事件 ❚ 例 : 在鼠 标单击 的地 方显示 “ ” .(MouseClick.html) 捕获事 件 mouseDown
❚ ❚ ❚ ❚ ❚
获得参数 (x,y) (Event evt, int x, int y)
在 (x,y) 处画 叉 paint() drawLine
思路 : 记忆鼠标点过的所有点 1.Point marks[]=newPoint[20];( 在 init 方法中 ) 2.marks[i++]=new Point(x,y); (MouseDown 方法中 ) 3. 将所有的点画出来 ( 在 paint 方法中 ) g.fillOval(x,y,10,10);
151
import java.awt.*;import java.applet.*; extends Applet事件 .public class mark 3. 2 鼠标产生的 { int i; Point Marks[]; public void init() {Marks[] =new Point[20]; i=20;} boolean mouseDown(Event evt, int x, int y) { Marks[i++]=new Point(x,y); repaint(); } public void paint(Graphics g) { int k; for (k=0;k
152
3.2 鼠标产生的 事件 import java.awt.*;import java.applet.Applet; public class CountClick extends Applet {int CurrentMarks=0; public boolean mouseDown(Event evt,int x,int y) { CurrentMarks++; repaint(); return true; } public void paint(Graphics g) { g.drawString(" "+CurrentMarks,10,10);} } ❚ [ 练习 ] 对鼠 标的点 击动 作计数
153
3.3 键盘产生的 事件 捕获的 方法 keyDown(Event evt, int key) Event 类的键 常量 常量 键 常量 常量 键 DOWN 下箭 头键 END End 键 F1 键 F2 F2 键 F3 F3 键 F4 F4 键 F5 F5 键 F6 F6 键 F7 F7 键 F8 F8 键 F9 F9 键
键 F1
154
3. 3 键盘产生的 事件 ❚ 例题 : 显示用 户按下 的字 母键内 容 import java.applet.Applet;import java.awt.*; { char Presskey; public boolean keyDown(Event evt, int key) { Presskey=(char)key; repaint(); return true; } public void paint(Graphics g) { g.drawString(Presskey,10,10); } }
155
3. 3 键盘产生的 事件 ❚ 键盘事 件处理 通常 包括 : 显示字 符 , 光标 移动 ❚ 特殊键 public boolean keyDown(Event evt, int key) { switch(key) { case Event.F1: {….}; case Event.PGUP: {…} } } ❚ 修正键 if(evt.shiftDown()) if(evt.controlDown());
156
3.3 ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚
键盘产 生的事件
练习题 : 在屏幕上 显示 用户输 入的 字符串 在前一 题的基 础上 , 将字符串 起来 , 但是不 能用 : String s; s=s+presskey; 应该用 StringBuffer 对象 的 append 方法 StringBuffer sb; sb.appned(presskey); sb 的内 容不能 直接 用 g.drawString() 应该用 g.drawString(sb.toString(),x,y);
157
3.4 动作 事件 ❚ 凡是由 构件产 生的 事件叫 动作 事件 ACTI ON_EV ENT, 处理这 类事件 的方 法是 : acti on().
music
确定
sports
取消
art
158
3.4 动作事 件 ❚ acti on(Ev ent evt, O bject arg ) ❚ evt. targe t: 指明 事件类 型 ❚ (but ton,c heck box,li st,.. .) int clickCount
int id int modifiers
int x
Event
int y
long when
int key
Object target
Ob je ct ar g
159
3.4 动作 事件 ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚
判断组 件类型 ( 如是 but ton 或 chec kbox ) if(e vt.ta rget insta nceof But ton) if(e vt.ta rget insta nceof Che ckbox) 判断是 哪多个 同类 组件中 的哪 一个 if(e vt.ta rget ==butt on1) if(e vt.ta rget =butto n2) 或者通 过判断 标签 内容 if(a rg==“ 确定 ” ) if(a rg==“ 取消 ” )
160
3.4 动作 事件
例 : 记录按 下按 钮的次 数 , 并显示 出来 . import java.awt.*; import java.applet.Applet; public class CountClick extends Applet { int CurrentMarks=0; public init() { Button b1=new Button(“ 按钮 ” ); 按钮 add.b1; } public boolean action(Event evt,Object arg) 10 { CurrentMarks++; repaint(); return true; } public void paint(Graphics g) { g.drawString(" "+CurrentMarks,10,10);} }
161
3.4 动作事 件 ❚ 例 : 根据 用户选 择画 图形 ❚import 思路 :java.awt.*; 园 方 ❚import 1. 设计两个按钮 ( 后面详细讲 ) java.applet.Applet; class drawing ❚public 2. 事件处理 action extends Applet circlemark=true; ❚{ boolean 根据选择 , 分别标记园或方 public init() ❚ {3 Button 根据标记画出相应图形 b1=new Button(“ 园” ); ❚ Button g.drawCirlce(50,50,50,50); b2=new Button(“ 方” ); add.b1; add.b2; ❚ g.drawRect(25,25,75,75); }
162
3.4 动作事 件 ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚
public void paint(Graphics g) { if (circlemark) g.filloval(10,10,30,30); else g.fillRect(20,20,40,40}; } public boolean action(Event evt,Object arg) { if (evt.target==b1) circlrmark=true; else circlrmark=false; repaint(); return true; }
163
3. 5 通用 的事件处理 程序 ---- handl eEven t ❚ hand leEve nt 处理 所有的 小应 用程序 所接 受的 事件 , 由它将 事件送 给相 对应的 方法 . ❚ 让我们 看一下 handl eEvent 的缺省 实现 public boolean handleEvent(Event evt) { switch(evt) { case Event.MOUSE_ENTER: return mouseEnter(evt,evt.x,evt.y); case Event.MOUSE_EXIT: return mouseExit(evt,evt.x,evt.y); case Event.MOUSE_MOVE: return mouseMove(evt,evt.x,evt.y);
164
3. 5 通用 的事件处理 程序 ---- hand leEve nt case Event.MOUSE_DRAG: return mouseDrag(evt,evt.x,evt.y); case Event.MOUSE_UP: return mouseUp(evt,evt.x,evt.y); case Event.MOUSE_DOWN: return mouseDown(evt,evt.x,evt.y); case Event.KEY_PRESS: case Event.KEY_ACTION: return keyDown(evt,evt.key); case Event.KEY_RELEASE:
165
3.5
}
通用的 事件处理程 序 --handl eEven t
case Event.KEY_ACTION_RELEASE: return keyUp(evt,evt.key); case Event.ACTION_EVENT: return action(evt,evt.arg); case Event.GOT_FOCUS: return gotFocus(evt,evt.arg); case Event.LOST_FOCUS: return lostFocus(evt,evt.arg); } return false;
3.5
通用的事件 处理程序 --hand leEve nt
166
❚ 覆盖 ha nd le Eve nt 的情 况 ( 原来的 han dle Eve nt 不被 执行 ): 只处理 我们感 兴趣 的事 :
public
bo olean
han dleE vent( Event
evt) { sw itch( evt.id ) { cas e Ev ent.M OUSE_E NTER : //d oing some thing; cas e Ev ent.M OUSE_E XIT: //d oing some thing; default:return super.handelEvent(evt); return false;
}}
167
.
3.7 Java1.1 事件 模型 ❚ Java 1.0 的事 件管理 机制 ❚ 在 Java1.0 中,多数 事件 发生在 类 component 里,并 通过 handleEvent() 方法将 事件 传递给 相应的 处理方 法 , 如果没 有这样 的方 法 , 则沿 着包含 层次传 给上 一级容 器 , 直到最 顶层容 器 仍没有 处理 , 则合理 遗弃 , 不适于 重用 . 例如 一个发 生在按 钮上 的事件 , 处理 它的 action 方 法通常 属于包 含按 钮的父 类容 器 , 这不 符合 面 向对象 的设计 原则 ❚ Java 1.1 的事 件管理 机制 ❚ 在 Java 1.1 中, 一个事 件常 常被其 它对 象处理 ,这些 对象称 为事 件监听 器, 当特定 事件 发 生时, 相应的 监听 器能够 知道 。 AWT 共有 11
168
3.7 Java1.1 事件 模型 ❚ ❚ ❚ ❚ ❚ ❚ ❚ ❚
在 Java 1.1 中如 何捕获 事件 ? 三个步 骤 : 1. 必须定 义一个 类来 实现接 口 class ButtonTracker implements ActionListener{…} 2. 定义方 法 3. 向构件 注册该 类的 一个实 例 button1.addActionListener(this); checkbox.addActionListener(this);
169
3.7 Java1.1 事件 模型 ❚ Java1.0 和 Java1.1 事件模 型的区 别 ? ❚ 在 Java1.1 中 , 事件 不再沿 着包 含层次 向上 传 递 , 而是 传给一 个监 听器 , 因此在 Java1.1 中 , 你希望 发生在 构件 事件由 哪个 监听器 处理 , 就 将该监 听器注 册到 构件上 .
170
3.7 Java1.1 事件 模型 窗口
panel
窗口或面 板 的监听器
button
按钮的监 听器
171
3.7 Java1.1 事件模型
❚ 常用的 监听器 及其 方法
❚ 键盘监 听器 :KeyListener, 方法 : ❚ keyPressed, KeyReleased, keyTyped. ❚ 鼠标监 听器 : MouseListener, 方法 : ❚ mouseClicked, mousePressed, mouseReleased, ❚ mouseEntered, mouseExited ❚ 构件监 听器 :ActionListener, 方法 : ❚ actionPerformed(); ❚ 如果一 个监听 器有 若干各 方法 , 则必须 将这 些 方法全 部覆盖
172
3.7 Java1.1 事件 模型 ❚ ❚ ❚ ❚ ❚ ❚ ❚
例: import java.awt.event.*;import java.awt.*; import java.applet.*; public class TestButton extends Applet { Button button1; Color color;
❚ }
173
3.7 Java1.1 事件 模型
public void init() { button1 = new Button("Test Button"); button1.addActionListener (new ButtonHandler(this)); add(button1); Font font = new Font("TimesRoman", Font.PLAIN, 48); g.setFont(font); color = Color.black; resize(400, 200); }
174
3.7 Java1.1 事件模型 public void paint(Graphics g) { g.setColor(color); g.drawString("TEST COLOR", 55, 120); }
175 public class ButtonHandler implements ActionListener { TestButton a; 3.7 Java1.1 事件模型 ButtonHandler(TestButton tb) { a=ts;} public void actionPerformed(ActionEvent event) { String arg = event.getActionCommand(); if (arg == "Test Button") { if (a.color == Color.black) a.color = Color.red; else a.color = Color.black; a.repaint(); }
176
3.7 Java1.1 事件 模型 100101
class TestButton button color=black; paint()
class ButtonHandler a 100101 a.color=black;
new ButtonHandler(this);
177 public class TestButtoninner extends Applet { Button button1; Color color; Font font; 3.7 Java1.1 事件 模型 class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent event) { String arg = event.getActionCommand(); if (arg == "Test Button") { if (color == Color.black) color = Color.red; else color = Color.black; repaint(); } }
178
class Example3.7 Java1.1 事件 模型 {public void init() 部定 义的类 叫内 部类 ❚ 在某个 类的内 Button(“button”); ❚{ Button 内部类button1=new 的特点 : button1.addActionListener(new ButtonHandler() ❚ 内部类 可以访 问外 部类的 数据 和方法 { public void actionPerformed(ActionEvent event) ❚ 内部类 的匿名 是指 : { String arg =形式 event.getActionCommand(); ❚ 在定义 if (arg == "Test 一个新 类的Button") 同时创 建一 个实例 . { if (color == Color.black) color = Color.red; else color = Color.black; repaint(); } . };
179
3.7 Java1.1 事件 模型 ❚ 适配器 ❚ 简化代 码 ❚ 不用适 配器时 , 必须 对某个 适配 器的多 个方 法 进行重 写 , 加入 适配 器后可 以为 这些方 法提 空 实现 class MouseAdapter implements MousListener { public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {}
180
3.7 Java1.1 事件 模型 ❚ 继承某 个适配 器的 子类 , 则程序 中只需 覆盖 你 需要的 方法 , 其余方 法则从 父类 继承 ❚ class MouseTrack extends MouseAdapter ❚ { public void mouseClicked(MouseEvent e) ❚ { //…handle mouse click event; ❚ } ❚ }
181
3.8 小结 ❚ 事件由 用户的 使用 了鼠标 和键 盘动作 引起 的 ❚ 事件由 事件处 理器 来处理 ❚ hand leEve nt() 方法是 App let 从 comp onen t 继承而 来的 . ❚ 重写 hand leEv ent() 方法时 注意返 回 fals e 指 明有些 情况被 忽略 , 将其传给 上层 对象 . ❚ 在组件 上产生 的动 作叫动 作事 件 ,acti on 方法 类处理
182
3. 10 作业 ❚ 1. 在鼠 标按 下的两 点之 间画一 条线
第 4 章
异常
北京大 学计 算机系 代亚非
第 4章 ■ ■ ■ ■ ■ ■ ■
4.1 4.2 4.3 4.4 4.5 4.6 4.7
异常
异常的 概念 异常的 分类 捕获异 常 声明异 常 抛出异 常 创造自 己的异常 总结
184
185 4.1 异常 的概念 ■ 什么是异常 ? 异常实 际上是程序 中错误导致中 断 了正常的指令流 的一种事件 . ■ 没有处理错误的 程序 : read -file { op enThe File; de termi ne it s siz e; al locat e tha t muc h mem ory; cl oseTh eFile ; }
■
4.1 异常的概念 以常规方法处理 错误
ope nFil es; if (the Files Open) { deter mine t he le nth if (g otTheF ileLe ngth all ocate that much if (gotE nough Memor read the fi le i if (r eadFai led) else errorC ode= }el se e rrorC ode=}else error Code= -4 ; }el se er rorC ode=-5 ;
of the file ; ){ memo ry; y) { nto m emory; erro rCode= -1; -2; 3;
186
4.1 异常的 概念 ■
■
■ ■
观察前面的程序 在出错处理上了 只把能够想到的 情况无法处理 程序可读性差 出错返回信息量
187
你会发现大 部分精力花 . 错误考虑到 , 对以外 的
太少
4.1 异常的概念 ■
188
用异常的形式处 理错误
rea d-Fil e; { t ry { ope nTheF ile; det ermin e it s size ; all ocate tha t much memo ry; clo seThe File ; }catch( fileo penF ailed) { do some thing; } catch (sizeD eter mineF ailed) {dos ometh ing; } catch (memor yAll ocate Failed ){ doso methi ng;}
4.1 异常的 概念
189
和传统的方法比 较异常的优 点 : 1. 把错误 代码从常规 代码中分离 出来 2. 把错误传播给调 method4 产生异常 method3 传 用堆栈 method2 3. 按错误类型和 递 method1 处理异常 错误差别分 组 4. 系统提供了对于 一些无法预 测的错误 的捕获和处理 5. 克服了传统方法 的错误信息 有限的问 题 ■
4.1 异常的 概念
190
class ■ . ExcepTest { public void main(String args[]) { int b=0; int a; try { a=4/b;} catch(ArithmeticException e) { System.out.println(“divided by 0”);} }} try{ URL url=new URL(http://www.hit.edu.cn/”,”hit.gif”);} catch(MalformedURLEception e) { badURL=true; repaint();}
4.2 异常的分类 ■
■
■
■
■
191
异常是 一个对 象 , 它继承 自 Throwable 类 , 所 有的 Throwable 类的 子孙类 所产 生的对 象都 是例外 . Error: 由 Java 虚拟 机生成 并抛 出 ,Java 程序 不做处 理 . Runtime Exception( 被 0 除等 系统 错误 , 数组 下标超 范围 ): 由系 统检测 , 用户 的 Java 程 序可不 做处理 , 系统 将它 们交给 缺省 的异常 处理程 序 . Exception( 程序 中的问 题 , 可预知 的 ): Java 编译器 要求 Java 程序必 须捕 获或声 明所 有的 非运行 时异常 throw: 用户 自己产 生异 常
4.2 异常的分类 ■
.
192
Throwable
用户 自己 产生的 异常 Exc ep tion 要处 理
Error RuntimeException
不做 处理 由用户 捕获或 声明并处 理 缺省的异 常 处理程序
4.3 捕获异 常 ■ 捕获并处理异常 try { // 接受监视的 程序块 , 在此区 域内 发生 // 的异常 , 由 ca tch 中指定的程序 处理 ; }ca tch ( 要处理的异常种 类和标识符 ) { // 处理异常 ; }ca tch ( 要处理的异常种 类和标识符 ) {
193
4.3 捕获异常 ■
常见的异常
■
Arit Arra Arra IOEx File Null Malf Numb OutO
■ ■ ■ ■ ■ ■ ■ ■
hmeti yInde yStor cepti NotFo Point ormed erFor fMemo
cExcep xOutOf eExcep on undExc erExce URLExc matExc ryExce
tion Band sExce ption tion 如果在 使用 能 够产生 异常 的 epti on 方法而 没有 捕 ptio n 获和处 理, 将 epti on 不能通 过编 译 epti on ptio n
194
4.3 捕获异常 ■ ■ ■ ■
例 : 编写 Java 程序 , 包含三种异常 算术异常 , 字符串越界 , 数组越界 观察输出信息 : 每个异常对象可 以直接给出 信息
195
class first_exception 4.3 捕获异常 { public static void main(String args[]) { char c; int a,b=0;int[] array=new int[7]; String s="Hello"; try {a=1/b;} catch(ArithmeticException ae) { System.out.println(“Catch “+ae));} try {array[8]=0;} catch(ArrayIndexOutOfBoundsException ai) { System.out.println((“Catch “+ai);} try{ c=s.charAt(8));} catch(StringIndexOutOfBoundsException se) { System.out.println((“Catch “+se);}}}
196
4.3 捕获异常 一定会执行的程 序块 ---fin ally 异常处 理的统一 出口 try { // 常规的代码 ; } catc h() { // 处理异常 } fina lly { // 不论发生什 么异常 ( 或者不发生任 何异常 ), 都要执行的部 分 ; }
197
4.3 捕获异常 ■ ■ ■ ■ ■ ■ ■ ■
finally 在文件处理 时非常有用 try { 对文件 进行处理的 程序 ; }catch(IOException e) { // 对文件 异常进行处 理 ; }finally { 不论是否发生异 常 , 都关闭 文件 ; }
198
4.4 声明异常
199
一个方 法不处 理它 产生的 异常 , 而是沿 着调用 层次向 上传递 , 由调用 它的 方法来 处理 这些异 常 , 叫声明 异常 . 声明异 常的方 法 在产生 异常的 方法 名后面 加上 要抛出 (thr ows) 的异常 的列表 ■ void com pute( int x) thro ws Arit hmet icExc eption {…} ■ retu rnTy pe meth odNa me([p aramet erli st]) throw s exce ptio nList ■
4.4 声明异常 例 :若 因某 种 原因 不 想在 创 建 URL 的方 法 中处 理 异常
200
public int compute(int x) throws ArithmeticException e) { return z=100/x;} public method1() { int x; try { x=System.in.read(); compute(x);} catch(IOException ioe) { System.out.println(“read error”); } catch(ArithmeticException e) { System.out.println(“devided by 0”); } }
4.4 声明异常
201
method1 处理
computer
抛出
异常
4.4 声明异常
202
例 : 说出 程序执 行结 果 public class exception1 { void Proc(int sel) throws ArithmeticException, ArrayIndexOutOfBoundsException { System.out.println(“In Situation" + sel ); if (sel==0) { System.out.println("no Exception caught"); return; }else if(sel==1) {int iArray[]=new int[4]; iArray[10]=3; }
4.4 声明异 常
203
public static void main(String args[]) { try { Proc(0); Proc(1); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("Catch"+e); } } c:>j In S no E In S Catc java on:1
view itua xcep itua h .lan 0
thro tion tion tion
wsExce ptio n 0 caught 1
g.Arr ayInde xOut OfBou ndsExc epti
4.5 抛出异常 抛弃异
204
常 : 不是出 错产生 , 而是 人为地
抛出 ■ throw ThrowableObject; ■ throw new ArithmeticException(); ■ 例 : 编写程序人 为抛出 (JavaThrow.prj) ArithmeticException, ArrayIndexOutOfBoundsException Another method A method Exception StringIndexOutOfBoundsException caught throw
class JavaThrow 4.5 抛出异 常 205 { public static void main(String args[]) { try{ throw new ArithmeticException();} catch(ArithmeticException ae) { System.out.println(ae); } try{ throw new ArrayIndexOutOfBoundsException();} catch(ArrayIndexOutOfBoundsException ai) { System.out.println(ai); } try { throw new StringIndexOutOfBoundsException();} catch(StringIndexOutOfBoundsException si){ { System.out.println(si); }
■
■
■
4.6 创造自己的 异常 206 不是由 Java 系统监测到 的异常 ( 下标越 界 , 被 0- 除等 ), 而是由 用户自己定 义的 异常 . 用户定义的异常 同样要用 try--catch 捕 获 , 但必须由 用户自己 抛出 throw new MyException. 异常是一个类 , 用户定义的 异常必须继 承自 Throwable 或 Exception 类 , 建议 用 Exception 类 .
4.6 创造自己的 异常
207
■
形如 :
■
class MyException extends Exception {….}; 例 1 : 计算 两个数 之和 , 当任 意一 个数超 出范 围时 , 抛出自 己的异 常
■ ■
public class NumberRangeException extends Exception { public NumberRangeException(String msg) { super(msg); } }
4.6 创造自己的 异常 ■public .
boolean action(Event evt, Object arg)
{ try { int answer = CalcAnswer(); answerStr = String.valueOf(answer); }catch (NumberRangeException e) { answerStr = e.getMessage(); } repaint(); return true; }
208
public int CalcAnswer() throws NumberRangeException 创造自己的 异常 209 { int int1, int2; 4.6 int answer = -1; String str1 = textField1.getText(); ■ . str2 = textField2.getText(); String try { int1 = Integer.parseInt(str1); int2 = Integer.parseInt(str2); if ((int1 < 10) || (int1 > 20) || (int2 < 10) || (int2 > 20)) { NumberRangeException e = new NumberRangeException (”Numbers not within the specified range."); throw e; } answer = int1 + int2; }catch (NumberFormatException e) { answerStr = e.toString(); } return answer;
4.6 创造自己的 异常 ■
■
■
■
■
210
例 2 : 在定义 银行类时 , 若取钱数大 于 余额则作为异常 处理 (InsufficientFundsException). 思路 : 产生异常的 条件是余额 少于取额 , 因此是 否抛出异常 要判断条件 取钱是 withdrawal 方法中 定义的动作 , 因此在该方法中 产生异常 . 处理异常安排在 调用 withdrawal 的时 候 , 因此 withdrawal 方法 要声明异常 , 由上级方法调用 要定义好自己的 异常类
class Bank 4.6 创造自己的 异常 { double balance; public ■ . void deposite(double dAmount) { if(dAmount>0.0) {balance+=dAmount;}}
211
public void withdrawal(double dAmount) throws InsufficientFundsException { if (balance
4.6 创造自己的 异常 public class ExceptionDemo { public static void main(String args[]) { try { Bank ba=new Bank(50); ba.withdrawal(100); System.out.println(“Withdrawal successful!”); }catch(Exception e) { System.out.println(e.toString()); } }
212
4.6 创造自己的 异常
213
■ .class InsufficientFundsException extends Exception public { private Bank excepbank; private double excepAmount;
InsufficientFundsException(Bank ba, double dAmount) { excepbank=ba; excepAmount=dAmount; } public String excepMesagge() { String str=“The balance”+ excepbank.showBalance()+ “The withdrawal was”+excepAmount; return str; }
4.7 小结 1. 一般 格式 : 正常程序和 出错处理分 离 开来 try { Java statement; }catche(ExceptionType1 ExceptionObject) { Exception1 handling; } catche(ExceptionType2 ExceptionObject) { Exception2 handling; }…. }finally { final handling; // ( 统一 的出口 , 最终 必定要 执行 )
214
4.4 小结 ■
215
2. 把异 常传播给堆 栈 , 沿着被 调用的顺序 往前寻找 , 只要找到符合该 异常种类彻 底 异常处理程序 , 就交给这部 分程序去处 理 call
Method1
throws
Method2
call Method3 call Read-file
throws
throws 产生 异常
Try catch
4.4 小结 3. 异常可 以人为地抛 出 , 用 throw new 语句 4. 异常可 以是系统已 经定义好的 , 也可 以是用 户自己定义 的 5. 用户自 己定义的异 常一定继承自 Throwable 或 Exception 类
216
作业 ■
217
当用户按“ T” 或“ t” 时 , 人为抛出一个 算术异常 , 处理 方式为打印 出错信息
import java.awt.*; import java.applet.*; 218 public class keyException extends Applet { final int LOWERCASE_T = 116; final int UPPERCASE_T = 84; String str; int count=0; public void paint(Graphics g) { g.drawString(" "+str+count, 5,20); } public boolean keyDown(Event evt, int key) {if ((key == LOWERCASE_T) || (key == UPPERCASE_T)) { try{ throw new ArithmeticException();} catch(ArithmeticException e) { count++; str=e.toString(); repaint();} return true; } return false; }
第 5章 构成用户界 面的窗口环 境 北京大 学计算 机系 代亚非
219
构成用 户界面的窗 口环境
220
✔ 5.1 使用 AWT(Abstract Window Toolkit) 构件 ✔ 5.2 包含 构件的 构件 ---- 构件容 器
( container ) ✔ 5.3 事件 的传递 ✔ 5.4 各种 构件的 应用 实例 ( 一 ) ✔ 5.5 外观 的管理 与控 制 ✔ 5.6 各种 构件的 应用 实例 ( 二 ) ✔ 5.7 总结
5.1 使用 AWT 构件
221
✔ 在 AWT 的概念 中,窗 口系 统所显 示的 各种
对象统 称为构 件: Button , Menu , List 等等都 是构件 。 ✔ Component 是代表 构件最 基本 的类。 ✔ Component 类中定 义了各 种窗 口对象 中最 基
本、最 重要的 方法 和性质 。随 时随处 都有 可能利 用 Component 定义 的方 法。
5.1 使用 AWT 构件
222
✔ 已经 学过 的:
✔ 没有 学过 的:
✔ getFont ,
✔ action,
✔ handleEvent,keyUp ✔ keyDown,mouseUp ,
✔
✔ mouseDown ,
✔
✔ mouseMove ,
✔
✔ mouseEnter ,
✔
✔ mouseExit ,
✔
✔ mouseDrag, repaint
✔
✔ setFont , resize ✔ ✔
disable , enable , getBackground , getForeground , hide , inside , isEnable , isShowing , isVisible , locate , location , move , setBackground , setForeground , show , size
5.2 包含 构件的 构件 ---- 构件容器 (container )
列表
按钮
窗口,对话框 另一个窗口
223
菜单
container container
5.2 包含 构件的 构件 ---- 构件容器 (container ) import java.awt.*; import java.applet.Applet; public class CountClick extends Applet { int CurrentMarks=0; public init() { Button b1=new Button(“ 按钮” ); add.b1; } } 按钮
224
5.2 包含 构件的 构件 ---- 构件容器 (container )
225
✔ AWT 使用 Container 类来定 义最基 本的 构件
容器 , 它有两 个子类 :Window 类和 Panel 类 . ✔ 在 Window 类还有两 个子类 ✔ 1. 定义 对话 框 , 用 Dialog 子类 ; ✔ Java 还提了一 个 Dialog 的子类 ---FileDialog,
用它生 成文件 对话 框 ✔ 2. 定义 一般 意义的 窗口 , 用 Frame 类 .
5.2 包含 构件的 构件 ---- 构件容器 (container )
226
✔ Panel 干什 么用的 呢 ? ✔ 使你更 方便的 组织 你的构件 , 得到赏 心悦目
的布局 ✔ Applet 是 Panel 的子类 , 因此 在小应 用程 序
里可以 直接加 入构 件 , 而一 般的 应用程 序必 须先定 义构件 容器 . ✔ 小应用 程序在 浏览 器中所 显示 的区域 就是
Panel, 所占 的尺寸 就是 缺省得 Panel 尺寸 .
5.2 包含 构件的 构件 ---- 构件容器 (container )
227
Component Container Button
Panel Applet
Menu Textfield Checkbox
Window Frame Dialog FileDialog
5.3 事件的 传递 (1.02)
228
当动作发 生在 按钮上 窗口
panel
时 , 首先看 按钮 这个 类有没有 action 方法 , 如果没有 则看 包含按 钮的容器 类 ( 即 panel) 有没有 action 方法 , 如果没有 事件 就传递 窗口 , 如果 没有 就传 递给 component 的通
按钮
用处理方 法 , 如果程 序中没有 定义 任何 action 方法 , 实际上事
class MyClass extends Frame { MyPanel p=new Mypanel(); add(p); Button b=new Button(exit); add(b); boolean action() {…….;} }
窗口
229
Panel
ok exit
class MyPanel extends Panel class MyBtn extends { Button MyBtn b=new MyBtn(“ok”); { add(b); boolean action() boolean action() { …….; {…….;} return true;} } }
5.3 事件的传递 (1.02)
230
✔ 事件由 包含层 次由 内向外 传递 . ✔ 每个处 理事件 的方 法要有 一个 返回值 , 通知
是否继 续向上 传递 boolean action(Event evt, Object arg) { ……; return true; }
5.3 事件的 传递 (1.1) 窗口
231
panel
窗口获面 板 的监听器
button
按钮 的监 听器
5.4 各种构 件的应用 实例 -- 按钮
232
✔ Button 类 ✔ 功能 : 创建按 钮事件 ✔ 创建一 个 Button ✔ Button myButton = new Button(str); ✔ 将 button 放到 窗口系 统中 :
add(new Button(“ 确定 ” ); 确定 ✔ add(new Button(“ 取消 ” ); ✔ Button 类的常 用方法 ✔ getLabel setLabel ✔
取消
5.4 各种构 件的应用 实例 -- 按钮
233
✔ 处理 button 产生的 事件 ✔ 例 : 创建 一个按 钮 , 每当按 下它时 , 在屏 幕
显示文 字 (singlebutton.html) ✔ 想一想 : ✔ 应该有 哪些类 ? Button ,Font; ✔ 应有哪 些方法 ? init--- 建立 button action--- 接受动 作事 件 , 调用 repaint paint--- 显示文 字
5.4 各种构 件的应用 实例 -- 按钮 import java.awt.*;import java.applet.Applet; public class button extends Applet { Font font; Button b1; public void init() { font= newFont("TimesRoman",Font.BOLD,20); b1=new Button("push"); add(b1); setFont(font); }
234
5.4 各种构 件的应用 实例 -- 按钮 ✔ boolean action(Event evt,Object arg) ✔ { y+=5; repaint(); ✔
return true;
✔} ✔ paint(Graphics g) ✔ { g.drawString("Button”, 10,y);}
235
5.4 各种构 件的应用 实例 -- 按钮 import java.awt.*;\\ 例 : 不在 applet 中的按 钮 class ButtoninFrame { public static void main(String args[]) { Frame myframe=new Frame(); myframe.setTitle("Button in Frame"); myframe.resize(200,200); myframe.show(); Button b1=new Button("Button1"); Button b2=new Button("Button2"); myframe.add(b1);myframe.add(b2); } . }
236
5.4 各种构 件的应用 实例
237
✔ 一般步 骤 :
创建 new
加入 add
响应 action
处理
5.4 Computer 各种构 件的应用 实例 Computer
238
MusicTextField(20); Music New 常用 的方 法 new TextArea( “this is a test”,20,40); Sports getText();setText(); Sports setEchoCharacter(char c) Scrollbar(VERTICAL,50,0,1,100); Art Art CheckboxGroup gr=new CheckboxGroup(); 1 Checkbox(label, New Checkbox(label,gr,null, false); New false); New Checkbox(label,gr,true);
min
start
max
5.4 各种构 件的应用 实例 --CheckBox
239
✔ 应用举 例 ✔ 建立三 个复选 框 , 被选中 者的标 签内 容变成
“ changes” – 应有的 类 :Checkbox – 应有的 方法 : – init: 建立 复选框 – action: 接受动 作事件 – setLabel(“*****”);
5.4 各种构 件的应用 实例 --CheckBox
240
import java.awt.*; public class checkbox extends java.applet.Applet { Checkbox b1,b2,b3; public void init() { b1=new Checkbox("Label1",null,false); b2=new Checkbox("Label2",null,false); b3=new Checkbox("Label3",null,false); add(b1); add(b2); add(b3); }
5.4 各种构 件的应用 实例 --- CheckBox 241 public boolean action(Event evt, Object arg) { if (evt.target instanceof Checkbox){ Checkbox selectedbox=(Checkbox)evt.target; String str=selectedbox.getLabel(); if (str=="Label1") selectedbox.setLabel("Chnage1"); else if (str=="Label2") selectedbox.setLabel("Chnage2"); else if (str=="Label3") selctedbox.setLabel("Change3"); } repaint();return true; }
5.4 各种构 件的应用 实例 --- TextField
242
✔ 例 : 在文 本行中 输入 , 并用 字符串 接受 , 显
示出来 ✔ 类的数 据构 成 :Textfield,Button, String ✔ 类的方 法构 成 : ✔ init(), ✔ action(): 接受按 钮事 件 , 调用 paint() ✔ paint(): 用 getText() 方法 得到输 入内 容 , 并显 示.
5.4 各种构 件的应用 实例 --- TextField
243
import java.awt.*; public class textfieldkey extends java.applet.Applet { TextField t;String s;Button button; public void init() { t=new TextField("",25); add(t); button=new Button("getText"); add(button); }
5.4 各种构 件的应用 实例 --- TextField public boolean action(Event evt, Object arg) { if(evt.target instanceof Button) { repaint();} return true; } public void paint(Graphics g) { s=t.getText(); g.drawString(s,40,80); }
244
5.5 外观的 管理与制
0 1 5
2
3
4
245
0
1
3
4
4
5
5.5 外观的 管理与制
246
✔ Panel 类 ( 面板 ) ✔ 功能 : 容纳其 他对象 , 安排 合理布 局 ✔ 创建面 板 :
Panel myPanel=new Panel(); ✔ add(myPanel); ✔ 将面板 作为容 器 : ✔ mypanel.add(button) button1 ✔
button3
button2 button4
import java.awt.*; 247 5.5 外观的 管理与制 public class Panel extends java.applet.Applet { ✔Panel panel1,panel2; 例 :(panel.htm) Button button1,button2,button3,button4; public void init() { panel1=new Panel(); panel2=new Panel(); add(panel1); add(panel2); button1=new Button("Button1"); button2=new Button("Button2"); button3=new Button("Button3"); button4=new Button("Button4"); panel1.add(button1); panel1.add(button2); panel2.add(button3); panel2.add(button4); }}
5.5 外观的 管理与制
248 北
✔ BorderLayout 类 ✔ 功能 :Applet 分成 五个区
西
中
✔ 创建 ✔ setLayout(new BorderLayout()); ✔ 将其他 构件加 入 ✔ add(“East”, new Button(“ 东” ); ✔ add(“South”, new Button(“ 南” ); ✔ add(“West”, new Button(“ 西” ); ✔ add(“North”, new Button(“ 北” ); ✔ add(“Center”, new Button(“ 中” );
南
东
5.5 外观的 管理与制 ✔ FlowLayout 类 ✔ 缺省的 输出管 理器 ✔ GridLayout 类 ✔ GridLayout mylayout = new ✔ GridLayout(3,3,0,0)
rows
cols
hspace
✔ setLayout();
vspace
249
5.5 外观的 管理与制
250
✔ GridBagLayout 类和
GridBagConstraints 类 ✔ 功能 : 借助于 GridBagConstraints 类 , 实现 更灵活 的外观 管理 ✔ 每个构 件后都 跟随 一个 GridBagLayout 对象 实体 , 来决定 构件的 外观 . ✔ 创建 ✔ GridBagLayout myLayout=new ✔ GridBagLayout(); ✔
5.5 外观的 管理与制
251
✔ GridBagConstraints 类的 约束条 件 gridwidth,
gridheight, gridx, gridy, ✔ weightx, weighty, ipadx, ipady, insets ✔ fill 及其设 置 ✔ GridBagConstraints.NONE ✔ GridBagConstraints.HORIZONTAL ✔ GridBagConstraints.VERTICAL ✔ GridBagConstraints.BOTH ✔ GridBagConstraints.RELATIVE
5.5 外观的 管理与制
252
✔ 例 :(GridBagApplet.html)
button1
button2
button3
button4 button5 button7
button6 button8 button9
public init()管理与制 253 5.5 void 外观的 { GridBagLayout layout=new GridBagLayout(); setLayout(layout); GridBagConstraints GBC = new GridBagConstraints(); Button button1=new Button("button1"); Button button2=new Button("button2"); Button button3=new Button("button3"); Button button4=new Button("button4"); Button button5=new Button("button5"); Button button6=new Button("button6"); Button button7=new Button("button7"); Button button8=new Button("button8"); Button button9=new Button("button9");
GBC.fill=GridBagConstraints.BOTH; 254 5.5 外观的 管理与制 ( 按钮可 以在水 平和 垂直两 个方 向扩展 ) layout.setConstraints(button1,GBC); add(button1); GBC.gridwidth=GridBagConstraints.RELATIVE; (BOTH 依然起 作用 , 紧挨着最 后一 个按钮 ,) layout.setConstraints(button2,GBC); add(button2); GBC.gridwidth=GridBagConstraints.REMAINDER; ( 填充剩 余部分 ) layout.setConstraints(button3,GBC); add(button3); But1 But2 But3
5.5 外观的 管理与制
255
✔ GBC.gridwidth=
GridBagConstraints.REMAINDER; ✔ ( 表示该按 钮独 占一行 ) ✔ layout.setConstraints(button4,GBC); ✔ add(button4); But1
But2 But4
But3
5.5 外观的 管理与制
256
✔ GBC.gridwidth=2; ✔ ( 表示该按 钮占 两个单 元 ) ✔ layout.setConstraints(button5,GBC); ✔ add(button5);
But1
But2 But4 But5
But3 But6
✔ GBC.gridwidth=
GridBagConstraints.REMAINDER; ✔ layout.setConstraints(button6,GBC); ✔ add(button6); ✔
5.5 外观的 管理与制
257
✔ GBC.gridwidth=1; ✔ GBC.gridheight=2; ✔ ( 高度为两 个单 元 ) ✔ layout.setConstraints(button7,GBC); ✔ add(button7); But1
But2 But4 But5
But7
But3 But6
5.5 外观的 管理与制
258
✔ GBC.gridwidth=
GridBagConstraints.REMAINDER; ✔ GBC.gridheight=1; ✔ layout.setConstraints(button8,GBC); ✔ add(button8); But1 But2 But3 ✔ layout.setConstraints But4 ✔ (button9,GBC); But5 But6 ✔ add(button9); But7
But8 But9
5.6 各种构 件的应用 实例 ---Canvas
259
✔ 5.6.2 Canvas 类 ( 画布 ) ✔ 功能 : 制作 其他构 件 , 通常用 来放置 图形 图
像 , 或绘 图 . ✔ 画图可 以直接 在 applet 区域上 进行 , 定义了 Canvas 对象 后将 paint() 语句 作为该 对象 的 方法 , 这些动 作就自 动发 生在画 布区 . ✔ 通常不 需要处 理画 布上发 生的 事件 ✔ 创建 ✔ Canvas canvas=new Canvas(); ✔ add(canvas);
5.6 各种构 件的应用 实例 ---Canvas
260
✔ 例 : 根据 程序说 出运 行结果 ✔ 注意一 个程序 中生 成一个 canvas 类的实 例 ,
另一个 程序没 有
import java.awt.*; import java.applet.*; 件的应用 实例 ---Canvas public 5.6 class各种构 canvas_test_2 extends Applet { public void init() { setLayout(new BorderLayout()); add("North", new Button("button1")); add("South", new Button("button2")); add("West", new Button("button3")); add("East", new Button("button4")); }
261
public void paint(Graphics g) { g.setColor(Color.red); g.fillRect(0,0,50,100); g.setColor(Color.blue); g.fillRect(30,0,100,40);} }
5.6 各种构 件的应用 实例 ---Canvas import java.awt.*; import java.applet.*; public class canvas_test extends Applet { MyCanvas mycanvas=new MyCanvas(); public void init() { setLayout(new BorderLayout()); add("Center",mycanvas); add("North",new Button("button1")); ….; add("East",new Button("button4")); } }
262
5.6 各种构 件的应用 实例 ---Canvas class MyCanvas extends Canvas { public void paint(Graphics g) { g.setColor(Color.red); g.fillRect(0,0,50,100); g.setColor(Color.blue); g.fillRect(30,0,100,40); } }
263
5.6 各种构 件的应用 实例 ---Canvas
264
5.6 各种构 件的应用 实例 ---Canvas
265
✔ 例 : 按动 鼠标改 变画 布的颜 色
(CanvasApplet) ✔ 有哪些 类 ? Canvas, Button, Color; ✔ 哪些方 法 ? init(), action(),swapColor(),paint() color
利用输 出管理 器按钮 和画布
color
color
按钮接收 鼠标事件
变换颜 色
执行重画
5.6 各种构 件的应用 实例 ---Canvas class CanvasApplet extends Applet { MyCanvas mycanvas=new MyCanvas(); public void init() { setLayout(new BorderLayout()); Button button = new Button("Color"); add("North",button); add(“Center”,mycanvas); resize(200,250); } .
266
5.6 各种构 件的应用 实例 ---Canvas ✔ boolean action(Event evt, Object arg) ✔{ ✔ if(arg=="Color") mycanvas.swapColor(); ✔ return true; ✔}
267
class MyCanvas extends Canvas 5.6 各种构 件的应用 实例 ---Canvas { Color color; MyCanvas() { color=Color.red; } public void paint(Graphics g) { g.setColor(color); g.fillRect(20,20,100,100); g.setColor(color.white); g.drawString("CANVAS",40,40);} public void swapColor() { if(color==Color.black) color=Color.red; else if(color==Color.red) color=Color.green; else color=Color.black; repaint(); } . }
268
5.6 各种构 件的应用 实例 ---Frame
269
✔ 5.6.3 Frame 类 ✔ 功能
: 制作 一般的 独立 窗口 , 它是构 件容
器 ✔ 创建 ✔ Frame fmInstance=new Frame(); ✔或 Frame fmInstance= ✔ new Frame(“The window for test”); ✔ 将其显 示到屏 幕上 ✔ fmInstance.show() ✔ 注意 : 不用 add()
5.6 各种构 件的应用 实例 ---Frame ✔ 常用的 方法
dispose,getCursorType,getIconImage, ✔ getMenuBar,getTitle,isResizable, ✔ setCursor,setIconImage,setMenuBar, ✔ setResizable,setTitle ✔ 窗口的 相关事 件 : ✔ Event.WINDOW_DEICONIFY, ✔ _DESTROY ✔ _EXPOSE, ✔ _ICONIFY, ✔ _MOVED ✔
270
5.6 各种构 件的应用 实例 ---Frame
271
✔ 例 : 创建 一个窗 口 , 并用按 钮控制 它的 显示
或 ✔ 隐藏 FrameApplet Frame Window This is CustomFrame window
hide window Show window
5.6 各种构 件的应用 实例 ---Frame ✔ 在 applet 中 action 处理 Button 的事件 button.label is show
action 捕获 button button.label is hide
Frame.show Frame.hide
272
5.6 各种构 件的应用 实例 ---Frame
273
为了 将字 符显 Frame Window 示在 自定 义窗 口中 , 包含 输 This is CustomFrame window 出语 句的 方法 必须 在自 定义 的窗. 口类 中 关闭 窗口的 事件 在窗口 类本 身处理
✔.
注 : 处理 窗口中 的事 件用 handelEvent() public boolean handleEvent(Event evt) { switch(evt.id) { case Event.WINDOW_DESTROY: dispose();System.exit(0); default: return super.handleEvent(evt); } }
public class FrameApplet extends Applet 274 5.6 各种构 件的应用 ---Frame { CustomFrame frame; Button实例 button; public void init() { frame=new CustomFrame ("Custom Frame Window"); button=new Button("Show Window"); add(button); } } public boolean action(Event evt, Object arg) { boolean visible=frame.isShowing(); if(visible){ frame.hide(); button.setLabel("Show window");} else {frame.show();button.setLabel("Hide Window"); return true; } }
class CustomFrame extends Frame 5.6 各种构 件的应用 { CustomFrame(String title) 实例 ---Frame { super(title);}
275
public boolean handleEvent(Event evt) { switch(evt.id) { case Event.WINDOW_DESTROY: dispose();System.exit(0); default: return super.handleEvent(evt); } } public void paint(Graphics g) { resize(200,100); g.drawString("this is a custom window.",30,30); } }
5.6 各种构 件的应用 实例 ---Frame
276
✔ 多窗口 (FrameApplet\ButtonsFrames.class-f1.bat)
button1
button1 Button1 button2 button2
10 1
Button1 button2 button2
0 7
5.6 各种构 件的应用 实例 ---Frame
277
1. 一个 窗口类 创建 两个实 例 2. 由于 有不同 的事 件发生 ( 按钮 , 关窗 口 ), 因 此事件 先由通 用事 件处理 程序 来接收 , 然后 再根据 情况做 相应 的处理 . switch(evt.id) { case Event.WINDOW_DESTROY: dispose(); return true; case Event.ACTION_EVENT: return action(evt, evt.arg); default: return super.handleEvent(evt);} }
5.6 各种构 件的应用 实例 ---Frame
278
✔ 3. 任何 时候 只有一 个窗 口是活 动的 (active)
的因此 不必考 虑那 个判断 是哪 一个窗 口发 生的事 件 ✔ 4. 一般 的结构 ✔ 在 main() 中 , 只做与 窗口有 关的 事情 : 创建 窗口 , 显示窗 口 ✔ 在构造 方法中 , 安排 窗口中 的构 件
import java.awt.*; 5.6 各种构 件的应用 实例 ---Frame class ButtonsInFrames extends Frame { int a1=0,a2=0; public static void main(String args[]) { ButtonsInFrames myframe1=new ButtonsInFrames(); myframe1.setTitle("Button in Frame1"); myframe1.resize(200,200); myframe1.show(); ButtonsInFrames myframe2=new ButtonsInFrames(); myframe2.setTitle("Button in Frame2"); myframe2.resize(200,200); myframe2.show(); }
279
ButtonsInFrames() 5.6 各种构 件的应用 实例 ---Frame { setLayout(new BorderLayout()); Button b1=new Button("Button1"); Button b2=new Button("Button2"); add("North",b1);add("South",b2); } public boolean handleEvent(Event evt) { switch(evt.id) { case Event.WINDOW_DESTROY: dispose(); return true; case Event.ACTION_EVENT: return action(evt, evt.arg); default: return super.handleEvent(evt);} }
280
5.6 各种构 件的应用 实例 ---Frame
281
✔ public boolean action(Event evt, Object arg) ✔{ ✔ ✔ ✔
if(evt.target instanceof Button) if(arg=="Button1") a1++; else a2++; repaint(); return true;
✔} ✔ public void paint(Graphics g) ✔{ ✔ ✔ }}
g.drawString("button1 "+a1,5,80); g.drawString("button2 "+a2,5,100); .
与 5.6 List 各种构 类有关 的事件 public boolean handleEvent(Event 件的应用 实例 --- 练习 evt)282 Event.LIST_DESELECT, { switch(evt.id){ case Event.WINDOW_DESTROY: Event.LIST_SELECT dispose(); System.exit(0); 例 : List List default: return super.handleEvent(evt); (FontDisplay.class---f3.bat) } FontDisplayer add add Arial } FontDisplay! arae
Panel 类
add
TextArea 类 add
area.setfont( Frame 类 handleEvent LIST_SELECT
Courier New Courier New
Times New Roman
18 20 字型 22 , 字体 24 26
You can input something here.
, 字号 )
handleEvent WINDOW_DESTROY
.
import java.awt.*; 283 5.6FontDisplay 各种构 件的应用 实例 --- 练习 class extends Frame { TextArea FontShower; public static void main(String args[]) { FontDisplay myFrame=new FontDisplay(); myFrame.setTitle("FontDisplayer"); myFrame.resize(450,300); myFrame.show(); } public FontDisplay() { setLayout(new BorderLayout(5,5)); FontShower=new TextArea("Font Display! ”); add("West", new FontPanel(FontShower)); add("Center",FontShower);}
5.6 各种构 件的应用 实例 --- 练习 public boolean handleEvent(Event evt) { switch(evt.id){ case Event.WINDOW_DESTROY: dispose(); System.exit(0); default: return super.handleEvent(evt); } }
对窗口 来说只有一 个事 件
284
5.6 各种构 件的应用 实例 --- 练习
285
在 panel 中创建 两个列 表 往列表 中加 入条目 用 additem(str) 得到列 表选项 用 getItem 事件处 理用用 handleEvent, 得到两 个参数 -- 字 型 , 字号 . 对右 边的文 本区 设置属 性 , 利用引 用传递 . void updateFontShower() { area.setFont(new Font(CurrentFontName, Font.PLAIN, CurrentSize));}} .
5.6 各种构 件的应用 实例 --- 练习
286
✔ public boolean handleEvent(Event evt) ✔ { switch(evt.id){
case Event.LIST_SELECT: ✔ List target=(List)evt.target; ✔ String itemName= ✔
✔
target.getItem(((Integer)evt.arg).intValue()); ✔ if(target==FontSelector) ✔ CurrentFontName=itemName; ✔ else CurrentSize=Integer.parseInt(itemName);
5.6 各种构 件的应用 实例 --- 练习
287
✔ String FontNames[]={"Arial", "Courier
New", "Times New Roman"}; ✔ List FontSelector=new List(); ✔ for (i=0;i
5.6 各种构 件的应用 实例 --- 练习
288
class FontPanel extends Panel { int CurrentSize=20; String CurrentFontName; TextArea area;; List FontSelector,SizeSelector;
updateFontShower() { area.setFont(param1,param2,param3)
FontPanel(TextArea FS) // 把另一个 对象 做参数 289 各种构 件的应用 实例 --- "Courier 练习 New", { int i;5.6String FontNames[]={"Arial", "Times New Roman"}; setLayout(new GridLayout(2,1,5,5)); FontSelector=new List(); for (i=0;i
public boolean handleEvent(Event evt) 290 5.6 各种构 件的应用 实例 --- 练习 { switch(evt.id){ case Event.LIST_SELECT: List target=(List)evt.target; String itemName= target.getItem(((Integer)evt.arg).intValue()); if(target==FontSelector) CurrentFontName=itemName; else CurrentSize=Integer.parseInt(itemName); updateFontShower(); return true; default: return super.handleEvent(evt); }} void updateFontShower() { area.setFont(new Font(CurrentFontName, Font.PLAIN, CurrentSize));}}
5.6 各种构 件的应用 实例 ---menu ✔ 5.6.6 菜单 系统 类 MenuBar
菜单系 统 一般菜 单
菜单容 器 类 Menu 类 MenuItem 非菜单 容 器
可撕下 菜单 帮助菜 单
选项 #1 选项 #2 菜单中的 菜单 选项 #3 选项 #4
选项 #1 选项 #2 第三层菜 单
选项 #3
选项 #1 选项 #2
291
5.6 各种构 件的应用 实例 ---menu ✔ 创建菜 单条 ✔ mb=new MenuBar(); ✔ setMenuBar(mb);( 类 Frame 中的 方法 ) file
edit
✔ 创建菜单 ✔ menu1=new Menu(“file”); ✔ menu2=new Menu(“edit) ✔ mb.add(menu1);mb.add(menu2);
292
5.6 各种构 件的应用 实例 ---menu ✔ 创建菜 单项 ✔ ✔ ✔ ✔ ✔
mi1=new MenuItem(“new”); mi2=new MenuItem(“open”); mi3=new MenuItem(“save”); mi4=new MenuItem(“close”); menu1.add(mi1); menu1.add(mi2); File New open Save Close
edit
293
5.6 各种构 件的应用 实例 ---menu 如何处 理事件 public boolean action(Event e, Object arg) { if (e.target instanceof MenuItem) { MenuItem selected=(MenuItem)e.trget; tring s=selected.getLabel(); switch(s) { case “new”: ….; case “open”: ….; case “save”: ….; case “close”: ….; } }
294
5.6 各种构 件的应用 实例 ---menu
295
✔ 在处理 菜单事
件 时应该注 意的事 情是 : 判断层 次
A
A
✔ MenuContainer uplevel;( 定义一个菜单容器 ) ✔ MenuItem target=(MenuItem)evt.target;( 当前被
选中的对象 ) ✔ uplevel=target.getParent(); ✔ strMessage=uplevel.getLabel()( 得到上一级容器 的标签 )
public boolean action(Event evt, Object arg) 296 5.6strMessage; 各种构 件的应用 实例 ---menu { String if(evt.target instanceof MenuItem){ MenuItem target=(MenuItem)evt.target; MenuContainer uplevel; uplevel=target.getParent(); while(uplevel instanceof Menu) { strMessage=((Menu)uplevel).getLabel()+strMessage; uplevel=((Menu)uplevel).getParent(); } strMessage="you selected"+strMessage; taMessage.appendText(strMessage); return true; } else return false;}
5.6 各种构 件的应用 实例 ---menu
297
✔ Java1.1 处理菜 单的方 法 ✔ 两个主 要的策 略 : ✔ 1. 让每 个菜 单项有 一个 唯一的 监听 器 ✔ 2. 将一 个大 的监听 器用 于用于 所有 菜单项
5.6 各种构 件的应用 实例 ---menu
298
class Example { class MenuFileOpen implements ActionListener { public void actionPerformed(ActionEvent e) { openFile(e.getActionCommand());} } class MenuFileSave implements ActionListener { public void actionPerformed(ActionEvent e) { saveFile(e.getActionCommand());} }
5.6 各种构 件的应用 实例 ---menu
299
public void init() { MenuItem OpenItem=new MenuItem(“Open…”); OpenItem.addActionListener (new MenuFileOpen()); MenuItem SaveItem= new MenuItem(“Save…”); SaveItem.addActionListener (new MenuFileSave()); }
5.6 各种构 件的应用 实例 -- 综合练 习
300
✔ 设计用 户界面 可根 据用户 选择 办理银 行业
务 ✔ Bankapp\Bankapp.class---f2.bat ✔ 控制流 程
5.6 各种构 件的应用 实例 -- 综合练 习 ✔ class Bank ✔ { long balance; ✔ public Bank() ✔ { balance=50; } ✔ public void deposite(long amount) ✔ { if(amount>0.0) {balance+=amount;}} ✔ void withdrawal(long amount) ✔ { if(amount>0.0 &&amount <= balance) ✔ { balance-=amount;} ✔ } ✔ public long show_balance() ✔ { return (long)balance; } ✔}
301
5.6 各种构 件的应用 实例 -- 综合练 习 public class BankDemo { public static void main(String agrs[]) { Bank account1=new Bank(); Bank account2=new Bank(); account1.deposite(100); account2.withdrawal(50); account1.show_balance(); account2.show_balance(); } }
302
5.6 各种构 件的应用 实例 -- 综合练 习
WelCome to Bank 100 Create account Show nbalance Deposit Withdrawal
303
5.6 各种构 件的应用 实例 -- 综合练 习 辅类 Bank
主类 Bankapp (Frame 的子类 )
Bank() 创建 账户
main() 定义并显 示窗口
show_balance diposite() withdrawal()
Bankapp() 布局安排 handleEvent() 关闭 窗口 action() 根据按钮 做处 理
满足 Bank 要求
304
辅类 Warningbox Warningbox(String str) 布局安排 , 显示对话 框 显示警告 信息 action() 关闭对话 框 它是模态 的 不满足 Bank 要求
5.6 各种构 件的应用 实例 -- 综合练 习
public static void main(String args[]) { Bankapp frame=new Bankapp(); frame.setTitle("Bank Application"); frame.resize(200,200); frame.show(); }
305
5.6 各种构 件的应用 实例 -- 综合练 习
306
public Bankapp() {setLayout(new GridLayout(6,1)); Label lb=new Label("welcome to Bank",Label.CENTER); tf=new TextField("0",15); add(lb);add(tf); b1=new Button("create account"); add(b1); b2=new Button("show balance"); add(b2); b3=new Button("diposite"); add(b3); b4=new Button("withdrawal"); add(b4); resize(450,100); }
5.6 各种构 件的应用 实例 -- 综合练 习 public boolean handleEvent(Event evt) { switch(evt.id) { case Event.WINDOW_DESTROY: dispose(); System.exit(0); return true; case Event.ACTION_EVENT: return action(evt, evt.arg); default: return super.handleEvent(evt); } }
307
public boolean action(Event evt,Object arg) 5.6 各种构 件的应用 {if(evt.target instanceof Button)实例 -- 综合练 习 308 { String targetLabel=tf.getText(); long amount=Long.valueOf(targetLabel).longValue(); if (arg=="diposite") { if (!haveAccount) {wb=new WarningBox(this,"create a account first!"); wb.show(); } else { if(amount==0) { wb=new WarningBox(this,”need the amount"); wb.show(); } else { bank.deposite(amount); tf.setText("0"); }} return true; } return false; }
public WarningBox(Frame parent,String str) 5.6 各种构 件的应用 实例 -- 综合练 习 { super(parent,"Warning!",true); Panel panel=new Panel(); panel.setLayout(new GridLayout(2,1)); panel.add(new Label(str,Label.CENTER)); panel.add(new Button("OK")); add(info_panel); } public boolean action(Event evt,Object arg) { if (evt.target instanceof Button) { this.dispose(); return true; } return false; }
309
class Bank 各种构 件的应用 实例 -- 综合练 习 { long5.6 balance; public Bank() { balance=50; } public void deposite(long amount) { if(amount>0.0) {balance+=amount;}} void withdrawal(long amount) { if(amount>0.0 &&amount <= balance) { balance-=amount;} } public long show_balance() { return (long)balance; } }
310
5.7 总结
311
✔ 5.8 总结 ✔ 1 使用 AWT 构件的应 用实 例 ✔ 2 事件 的传 递 ✔ 3 外观 的管 理与控 制 了解类 及其常 用方 法 设计 好容 器层 次
创建 输出 管理器 setLayout
定义事件 的处 理 action
创建 类的 实 例 new
加到上 一级容 器中 add
作业
312
✔ 将文本 行的输 入加 入到文 本域 中
追加
第6章
数据流的运用
北京大学计算机系 代亚非
314
第 6 章 数据流的运用 ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
6.1 输入 输出方 法 6.2 输入输 出流的 基类 6.3 File I/O 6.4 数据输 入输出 流 6.5 随机存 取文件 6.6 文件的 其它操 作 6.7 java 中的 unicode 6.8 管道 流 6.9 对象 流 6.10 流的 分类 6.11 小结
315
6.1 输入输 出方法 ■
什么是 数据流 ? 文件
起 点
文件 , 字符串 存储 区
文件
程序
程序
网络端 点
终端
数据流
终 点
网络端 点 ■
数据流是指所有的数据通信通道
■
在 java 中有关流的操作使用 java.io.*
■
出于安全的考虑 , 小应用不能实现文件 I/O 流
316
6.1 输入输 出方法 ■ ■ ■ ■ ■ ■ ■ ■
System 类管理 标准输 入输 出流和 错误 流 System.out: 把输出 送到缺 省的 显示 ( 通常是 显示器 ) System.in 从标准 输入获 取输 入 ( 通常 是键盘 ) System.err 把错误 信息送 到缺 省的显 示 每当 main 方法被执 行时 , 就自 动生成 上述 三个对 象
317
6.1 输入输 出方法 public class ReadHello { public static void main(String args[]) { char inchar; System.out.println(“Enter a character:”); try{ inChar=(char)System.in.read(); Syste.out.println(“ “+ inChar); }catch(IOException e) { Sytem.out.println(“Error reading from user”); } } }
318
6.1 输入输 出方法 import java.io.*; class IOTest { public statics void main(String args[]) {try { byte bArray[]=new byte[128]; System.out.println(“Enter something:”); System.in.read(bArray); System.out.print(“You entered:”); System.out.println(bArray); }catch(IOException ioe) { System.out.println(ioe.toString()); } } stream\Iostream.class---f4.bat }
319
6.1 输入输 出方法 ■ ■
■ ■ ■ ■ ■ ■ ■
为什么 输入的 是字 符 , 输出是乱 码 ? 原因 :System.out.println(bArray) 输出 的是数 组的地 址而不 是字 符 改进 : 将字符 数组变 换成 字符串 原来是 :System.out.println(bArray); 现在为 :String s=new String(bArray,0); System.out.println(s); System.in 是属 于 BufferedInputStream 类型 System.out 是属 于 PrintStream 类型 System.err 也是 属于 PrintStream 类型
320
6.2 输入输 出流的基类 ■
■ ■ ■ ■ ■ ■ ■ ■ ■
Java 中每 一种 流的基 本功 能依赖 于基 本类 InputStream 和 OutputStream 它们是 抽象类 , 不能 直接使 用 属于 InputStream 类的 方法有 : read(): 从流 中读入 数据 skip(): 跳过 流中 若干字 节数 available(): 返回流 中可 用字节 数 mark(): 在流 中标记 一个 位置 reset(): 返回 标记 过得位 置 markSupport(): 是否支 持标记 和复 位操作 close(): 关闭 流
321
6.2 输入输 出流的基类 ■
■ ■ ■ ■ ■ ■ ■
方法 read() 提供 了三种 从流 中读数 据的 方法 . int read(): 读一个 整数 int read(byte b[]): 读多 个字节 到数 组中 int read(byte,int off,int len); 属于 OutputStream 类的方 法有 : write(int b): 将一个 整数 输出到 流中 write(byte b[]): 将数 组中的 数据 输出到 流中 write(byte b[], int off,int len): 将数组 b 中从 off 指定的 位置开 始 len 长度的 数据输 出到 流中
322
6.2 输入输 出流的基类 ■ ■ ■ ■
■ ■ ■
■
flush(): 将缓冲 区中的 数据 强制送 出 close(): 关闭流 . PrintStream 类 println() 不属于 OutputStream 类 , 它是 PrintStream 类的子 类 , 能提供 复杂的 输出 PrintStream 类的方 法有 : write, flush, checkError,print, println,close. 其中 println 可以输出 多种 形式的 数据 . 例 如: println(String s), println(char c) 等
323
6.3 File I/O ■ ■ ■ ■ ■
文件对 象的建 立 File fp=new File(“tempfile.txt”); 对文件 操作要 定义 文件流 FileInputStream 类用 来打开 一个 输入文 件 FileOutputStream 类用来 打开 一个输 出文 件 write
输出文件
输入文件
read
324
6.3 File I/O ■ ■ ■
■ ■ ■
文件流 的建立 FileInputStream in=new FileInputStream(fp); FileOutputStream out=new FileOutputStream(fp); 例 : 文件 拷贝 ( 注意要 捕获文 件异 常 ) 输入流 的参数 是用 于输入 的文 件名 输出流 的参数 是用 于输出 的文 件名 file1.txt
输入流
输出流
file2.txt
import java.io.*; 325 class filestream 6.3 File I/O { public static void main(String args[]) { try{ File inFile=new File("file1.txt"); File outFile=new File("file2.txt"); FileInputStream fis=new FileInputStream(inFile); FileOutputStream fos=new FileOutputStream(outFile); int c; while((c=fis.read())!=-1) fos.write(c); fis.close(); fos.close(); }catch(FileNotFoundException e) { System.out.println("FileStreamsTest: "+e); }catch(IOException e) { System.err.println("FileStreamsTest: "+e); }}}
326
6.3 File I/O ■
增加缓 冲区流 , 减少 访问 硬盘的 次数 , 提高 效率
file1.txt
输入 缓冲 区 输出 缓冲 区
输入流
file2.txt 输出流
文件 文件流
缓冲区 流
6.3 File I/O ■ ■
■ ■ ■ ■ ■ ■ ■ ■
327
缓冲区 流 : BufferedInputStream 和 BufferedOutputStream 将它们 与文件 流相 接 FileInputStream in=new FileInputStream(“file1.txt”); BufferedInputStream bin= new BufferedInputStream(in,256) int len; byte bArray[]=new byte[256]; len=bin.read(bArray); len 中得到 是长度 , bArray 中得 到的是 数据
328
6.3 File I/O ■ ■
■
只有缓 冲区满 时 , 才会将 数据送 到输 出流 . Java 在输出 数据流 中 , 当对方 尚未将 数据 取 走时 , 程序就 会被阻 塞 . 有时要 人为地 将尚 未填满 的缓 冲区中 的数 据 送出 , 使用 flush() 方法 .
文件
329
6.4 数据输 入输出流 ■ ■
■ ■
■ ■ ■
什么时 候需要 数据 输入输 出流 ? 文件流 和缓冲 区流 的处理 对象 是字节 或字 节数组 ,利用 数据 输入输 出流 可以实 现对 文件的 不同数 据类 型的读 写 . DataInputStream 、 DataOutputStream 一种较 为高级 的数 据输入 输出 方式 , 除了字 节和字 节数组 , 还可 以处 理 int,float,boolean 等类型 . 还可以 用 readLine 方法 读取一 行信 息 可使用 的方法 : write,writeBoolean…,read,readByte… 等
330
6.4 数据输 入输出流 ■ ■ ■ ■ ■
■
■
数据流 的建立 FileOutputStream fos= new FileOutputStream(”file2.txt")); DataInputStream dis= new DataInputStream(fos) 数据输 出流可 以是 一个已 经建 立好的 输入 数据流 对象 , 例如网 络的 连结 , 文件等 . 下面的 例子显 示如 何利用 数据 输入输 出流 往文件 中写不 同类 型的数 据
331 class datainput_output 数据输 入输出流 args[]) throws IOException { public6.4 static void main(String { FileOutputStream fos=new FileOutputStream(“a.txt”); DataOutputStream dos=new DataOutputStream (fos); try{ dos.writeBoolean(true); dos.writeByte((byte)123); dos.writeChar('J'); dos.writeDouble(3.141592654); dos.writeFloat(2.7182f); dos.writeInt(1234567890); dos.writeLong(998877665544332211L); dos.writeShort((short)11223); }finally{ dos.close(); }
332 DataInputStream dis=new DataInputStream( 6.4 数据输 入输出流 new FileInputStream("a.txt")); try{ System.out.println("\t "+dis.readBoolean()); System.out.println("\t "+dis.readByte()); System.out.println("\t "+dis.readChar()); System.out.println("\t "+dis.readDouble()); System.out.println("\t "+dis.readFloat()); System.out.println("\t "+dis.readInt()); System.out.println("\t "+dis.readLong()); System.out.println("\t "+dis.readShort()); }finally{dis.close();} }}
Stream\datainputandoutput--->f5.bat
333
6.4 数据输 入输出流 ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
DateLine(InputStream in)( 计算 字符和 行数 ) { DataInputStream data=new DataInputStream(in); String currentLine; int lineCount=0; int charCount=0; while((currentLine=dataIn.readLine())!=null) { ++lineCount; charCount+=currentLine.length(); } return (charCount/(float)lineCount); }
334
6.5 随机存 取文件 ■ ■ ■
■ ■ ■ ■
类 RandomAccessFile zip 文件需 要用 随机方 法处 理 文件目 录给出 个文 件的入 口 , 可以随 机读取 . 创建一 个随机 文件 new RandomAccessFile(“file1.txt”, “r”); new RandomAccessFile(“file2.txt”, “rw”); 随机文 件可以 同时 完成读 和写 操作 . zip 文件
文件目录
335
6.5 随机存 取文件 ■ ■ ■ ■ ■ ■ ■
■
支持随 机文件 操作 的方法 : readXXX() 或 writeXXX() skipBytes(); 将指 针乡下 移动 若干字 节 seek(): 将指针 调到 所需位 置 getFilePointer(): 返回 指针当 前位 置 pos length(): 返回文件 长度 利用 seek(long pos) 方法 查找随 机文 件中的 信息 例 : 把若 干个 32 位的 整数写 到一 个名为 “ temp.dat” 的文 件中 , 然后利 用 seek 方法 , 以 相反的 顺序再 读取 这些数 据
336 public class random_file 6.5 随机存 取文件 { public static void main(String args[]) { int data_arr[]={12,31,56,23,27,1,43,65,4,99}; try { RandomAccessFile randf=new RandomAccessFile(“temp.dat”); for (int i=0;i>data_arr.length;i++) randf.writeInt(data_arr[i]); for(int i=data_arr.length-1;i>=0;i--) { randf.seek(i*4); System.out.println(randf.readInt()); } randf.close(); }catch (IOException e) { System.out.println(“File access error: “+e);} } }
337
6.6 文件的其它 操作 ■
使用文 件类获 取文 件的路 径信 息
■
设 f 是一 个文件 对象
■
File f=new File(“data”,temp.dat”);
■
f.getName(): 返回 文件名
■
f.getParent(): 返回文件 所在 目录名
■
f.getPath(): 返回 文件路 径
■
f.getAbsolutePath(): 返回绝 对路 c:\myprog\data\temp.dat
temp.dat data
data\temp.dat
338
6.6 文件的 其它操作 ■
■ ■ ■ ■ ■ ■ ■ ■ ■ ■
例 : 获取当 前目录 下所 有文件 名和 文件的 尺 寸: import java.io.*; public class file_size { public static void main(String args[]) { File files=new File(“.”); String file_list[]=files.list(); for(int i=0;i
339
6.7 java 中的 unicode ■ ■
在 java 中用 unicode 表示字 符和 字符串 DatainputStream 的 readLine 方法 , 以字 节 形式读 入 , 以 unicode 形式输出
byte + 00000000 8 bit ❚ ❚
Unicode 16bit
DataInputStream 不适 合输入 是 unicode 的形 式 处理字 符用 InputStreamReader 类和 BufferedReader 类 (jdk1.1)
6.7 java 中的 unicode import java.io;( 从键盘 上读一 个字 符串 ) public class CharInput { public static void main(String args[]) {String s; throws IOException InputStreamReader ir; BufferedReader in; ir=new InputStreamReader(System.in); in=new BufferedReader(ir); 可以将 字符 串转换 成整 String s=in.readLine(); 数加以 运算 int i=Integer.parseInt(s); i=i*2; 123 System.out.println(“the result is” +i); } }
340
341
6.7 java 中的 unicode ■ ■
■ ■ ■
问题 : 如果字 符流不 是来 自本地 , 有可 能编 码不一 样 , 直接 读取 会读出 不正 确字符 处理方 法 : ir=new InputStreamReader(is,”8859_1”); 采用的 是 iso8859_1 编码方 式 , 在不同 平台 之间正 确转换 字符 .
342 import java.io.*; 6.7filetounicode java 中的 unicode class { public static void main(String args[]) { try{ FileInputStream fis=new FileInputStream("toyamei.txt"); InputStreamReader dis=new InputStreamReader(fis); BufferedReader reader=new String s; BufferedReader(dis); while((s=reader.readLine())!=null) { System.out.println("read: "+s);} dis.close(); }catch(IOException e) { } } }
6.8 使用管 道流 输出流 ■ ■ ■
■
■ ■
■
343
输入流
PipedInputStream 和 PipedOutputStream 创建管 道流 : PipedInputStream pis=new PipedInputStream(); PipedOutputStream pos=new PipedOutputStream(pis); 或: PipedOutputStream pos=new PipedOutputStream(); PipedInputStream pis=new PipedInputStream(pos);
6.8 使用管 道流 ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
344
管道流 一定是 输入 输出并 用 例 : 将数 据从输 出管 道进 , 从输入 管道出 import java.io.*; class pipedstream { public static void main(String args[]) throws IOException { byte aByteData1=123, aByteData2=111; PipedInputStream pis= new PipedInputStream(); PipedOutputStream pos= new PipedOutputStream(pis); System.out.println("PipedInputStream");
345
6.8 使用管道流 ■ ■ ■ ■ ■ ■ ■ ■ ■
try{ pos.write(aByteData); pos.write(aByteData2); System.out.println((byte)pis.read()); System.out.println((byte)pis.read()); } finally { pis.close(); pos.close(); }
346
6.9 对象流 ■ ■
■ ■ ■ ■ ■ ■
在 java. io 包中 什么是 对象 的持续 性 ? 能够纪 录自己 的状 态一边 将来 再生的 能力 , 叫对象 的持续 性 什么是 串行化 ? 对象通 过写出 描述 自己状 态的 的数值 来记 录自己 的过程 叫串 行化 . 什么是 对象流 ? 能够输 入输出 对象 的流 . 两者什 么关系 ? 将串行 化的对 象通 过对象 输入 输出流 写入 文件或 传送到 其它 地方 .
6.9 对象 流 ■
■ ■ ■ ■ ■ ■ ■ ■ ■ ■
347
一个相 关的例 子 : 从一个源 读入 一个简 单的 对象 import java.net;import java.io public class GetString { public String getStringFromUrl(URL inURL) { InputStream in; try { in =inURL.openStream(); }catch(IOException ioe) {System.out.printlin(“URL error;”+ioe); return null; } return getString(in); } 通过 url 得到 一个字 符串
348
6.9 对象流 ■
■ ■ ■ ■ ■ ■ ■
public String getStringFromSocket(Socket inSocket) { inputStream in; try{ in=inSocket.getInputStreamSream(); }catch(IOEception ioe) { System.out.println(“Socket error:”+ioe); return null; } return getString(in); } 通过 socket 得到 一个 字符串
6.9 对象流
349
public String getString(inputStream inStream) { String readString = new String(); DataInputStream in =new DataInputSream(inStream); char inChar; try{ while(true) { inChar=in.readByte(); readString=readString+inChar; } }catch(EOFException eof) { System.out.println(readString);} }catch(IOException ioe) { { System.out.println(“error:”+ieo);} return readString; }
350
6.9 对象流 ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
下面的 对象能 读吗 ? Class testObject { int x; int y; float angle; String name; public testObject(int x,int y,float angle, String name); { this.x=x;this.y;this.angle;this.name=name;} } 这仍然 是一个 简单 的对象
6.9 对象流
351
对象 流是怎 样工 作的 ? 允许 可串行 化的 对象在 流中 传输 1. 只有 实现 serializable 接口 的类才 能被 串行 化 public class Student implements Serializable { int id;String name; int age; String department; public Student(int id, String name,int age, String department) { this.id=id; this.name=name; this.age=age; this.department =departmernt; }
6.9 对象流 ■
■ ■ ■ ■ ■ ■
2. 构造对 象的输 入输 出流 ( 将对象保 存到 文件中 , 或者 通过网 络传 送到其 他地 方 ) 相应的 类 :ObjectInput 对象的 输出 : ObjectOutputStream 相应的 方法 :writeObject() 对象的 输入 :ObjectInputStream 相应的 方法 :readObject() 注 :jdk1.1 以上版 本支 持对象 流操 作
352
6.9 对象流
353
对象流 举例 : 将 Student 类的 一个 实例写 到文 件 中 import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class Objectser {public static void main(String args[]) Student stu=new Student(981036,“Li Ming”,16,“CSD”); {try {FileOutputStream fo=new FileOutputStream(“date.ser”); ObjectOutputStream so=new ObjectOutputStream(fo); os.writeObject(stu);so.close(); }catch(Exception e) {;}
354
6.9 对象流 im po rt ja va. io .F ile In put St rea m; im po rt ja va. io .O bje ct Inp ut Str ea m; pu bl ic cl ass O bj ect Rec ov { pu bl ic sta ti c voi d m ai n( Str ing a rg s[] ) { St ude nt st u; tr y { Fil eI np utS tre am f i=n ew Fi leI np ut Str eam (“ da te. se r”) ; Ob je ct Inp utS tr ea m s i=n ew Obj ec tIn pu tSt re am( fi ); st u=( St ud ent )si .r ea dOb jec t( ); si. clo se () ; }c atc h(E xc ep tio n e ) {S yst em .o ut. pri nt ln (e) ;} Sy ste m.o ut .p rin tln (“ ID: ”+ st u.i d+ “na me :”+
355
6.10 流的分类 ■
InputStream 和 OutputStream 是所有 输入输 出流的 祖先 , 它们是 一个 抽象类 .System.in 和 System.out 是它们 的子 类
InputStream
PushbackInputStream
FileInputStream PipedIntputStream FilterInputStream ByteArrayInputStream SequencedInputStream StringBufferInputStream
DataInputStream BufferedInputStream LineNumberInputStream
356
6.10 流的分类 FileOutputStream DataOutputStream OutputStream
PipeOutputStream
BufferedOutputStream
FilterOutputStream
PrintStream
ByteArrayOutputStream
InputStream 中的 基本方 法包 括 : ■ read, available, mark, skip, reset, markSuppposed, close ■ OutputStream 中的基 本方法 包括 : write, flush, close ■
357
6.11 小结 ■ ■
■
■
文件
在 Java 中有 数据传 输的 地方都 用到 I/O 流 ( 通常是 文件 , 网络 , 内存 和标准 输入 输出 等) InputStream 和 OutputStream 是所 有 I/O 流 的祖先 ( 只有 RandomAccessFile 类是 一个例 外 ),read 和 write 是它们 最基本 的方 法 , 读 写单位 是字节 . 在众多 的流对 象中 , 并不 是每一 种都 单独使 用 , 其中 过滤 流的子 类在 数据送 出去 之前做 必要的 处理 . 目
文件输 入流
缓冲输 入流
行号输 入流
数据输 入流
的
358
6.11 小结 ■
■
■
■
File, File(Input/Output)Stream, RandomAccessFile 是处 理本地 文件 的类 Data(Input/Output)Stream 是一个 过滤流 的 子类 , 借此可 以读写 各种 基本数 据 , 在文 件 和网络 中经常 使用 . 如 : readByte, writeBoolean 等 . Buffered(Input/Output)Stream 的作 用是在 数 据送到 目的之 前先 缓存 , 达到一 定数 量时再 送到目 的 , 已减少阻 塞次 数 . Piped(Input/Output)Stream 适合与 一个处 理 的输出 作为另 一个 处理的 输入 的情况
359
作业 作业 : 将键盘 上输入 的一 串字符 写到 文本文 件中
第 7章
多 线程
北京大 学计算机 系 代亚非
第 7章 ■ ■ ■ ■ ■
7.1 7.2 7.3 7.4 7.5
多线 程
多线 程基本 概念 创建 线程的 方式 线程 的挂起 与唤 醒 多线 程问题 小结
361
362
7.1 多线程 基本概念 文件
各种系 统资源 输入输 出装置
文件
各种系 统资源 输入输 出装置
数据区 段
数据区 段
程序区 段
程序区 段
只有一 个地方在 执行
传统的进 程
同时有 数个地方 在执行
多线程的 任务
7.1 多线程基本 概念 ■ ■
■ ■
363
多线程 的优势 : 减轻编 写交互 频繁 、涉及 面多 的程序 的困 难. 程序的 吞吐量 会得 到改善 . 由多个 处理器 的系 统 , 可以 并发 运行不 同 的线程 .( 否则 , 任何时刻 只有 一个线 程在 运行 )
7.1 多线程基本 概念 ■ ■
■
线程与 进程的 区别 : 多个进 程的内 部数 据和状 态都 是完全 独 立的 , 而多线 程是共 享一 块内存 空间 和一 组系统 资源 , 有可能 互相影 响 . 线程本 身的数 据通 常只有 寄存 器数据 , 以及一 个程序 执行 时使用 的堆 栈,所 以 线程的 切换比 进程 切换的 负担 要小。
364
7.1 多线程基本 概念 ■
对线程 的综合 支持 是 Java 技术 的一个 重 要特色 . 它提供 了 thread 类、 监视器 和条 件变量 的技术 .
■
虽然 Macintosh,Windows NT,Windows 9 等 操作系 统支持 多线 程 , 但若 要用 C 或 C++ 编写多 线程程 序是 十分困 难的 ,因为 它们 对数据 同步的 支持 不充分 .
365
7.2 创建线 程的方式 1. public class mythread extends Applet implements Runnable ( 小应用或 已经 是某个 类的 子类时 ) 2. 继承类 Thread public class mythread extends Thread 3. 上述两 种方法 中都 可用类 Thread 产生 线 程的对 象 Thread newthread; 4. 创建并 启动线 程 newthread=new Thread(this); newthread.start();
366
7.2 创建线程的 方式 ■
■
■
■ ■
■
367
5. run 方法 是运行 线程 的主体 , 启动 线程时 , 由 java 直接 调用 public void run() 6. 停止 线程 , 由小应 用程序 的 stop 调用 线程 的 stop newthread.stop() 7 sleep 方法的作 用 , 暂停线 程的执 行 , 让其 它线程 得到机 会 ,sleep 要丢出 异常 , 必须 抓 住. Try{sleep(100)}catch(InterruptedException e){} 例 : 小应 用程序 中不 用 Runnable 接口 仍然 可以使 用线程 ( 不调 用主类 的方 法和调 用主 类的方 法 )
7.2 创建线程的 方式
368
import java.applet.*; public class thread extends Applet { mythread t1=new mythread(); public init() { t1.start();} class mythread extends Thread { public void run() { for (int i=0;i<4;i++) System.out.println( “”+i); { try{sleep(400); } catch(InteruptedException e){ } } }
public class mainclass extends Applet 7.2 创建线程的 方式 { C t1=new C(this); public void init() { t1.start();} public void paint(Graphics g) { g.drawString("Hello,java",10,50);}} class C extends Thread { mainclass a; C(mainclass b) { a=b; } public void run() { while(true){ a.repaint(); try{sleep(400);} catch(InterruptedException e){} }}
369
7.2 创建线程的 方式
370
8. 其它 常用的 方法 isAlive : 判断线 程目 前是否 正在 执行状 态中 if(newthread.isAlive()) newthread.stop(); resume: 要求被 暂停得 线程 继续执 行 suspend: 暂停线程 的执 行 join: 等待线程 执行 完毕 thatThread.join(); 被等待 的那个 线程 不结束 , 当前线 程就一 直等 待 . yield: 将执行 的权力 交给 其它线 程 , 自己到 队列的 最后等 待 .
7.2 创建线程的 方式
371
9. 线程 的优先 权 ■ 某一时 刻只有 一个 线程在 执行 , 调度策 略为 固定优 先级调 度 . newthread.setPriority(Thread.MIN_PRIORITY) ■ 级别有 :MIN-PRIORITY ■ NOM_PRIORITY ■ MAX-PRIORITY 10. 自私 的线程 : 有很 高的优 先权 的线程 , 不 主动睡 眠或让 出处 理器控 制权 .
372
7.2 创建线程的 方式 11. 线程的 状态 yield()
new Thread() New Thread
start()
stop()
suspend() sleep() wait()
. . Runnable . stop() or run()exit Dead
Not Runnable resume() stop()
7.2 创建线程的 方式 ■
■
373
当一个 线程执 行完 所有语 句后 就自动 终止 ,调用 线程的 stop() 方法, 也可以 强制 终止 线程。 如果希 望线程 正常 终止, 可采 用标记 来使 线程中 的 run () 方法退 出。
7.2 创建线程的 方式 public class Xyz implements Runnable { private boolean timeToQuit=false ; public void run () { while (! timeToQuit ) {…..} //clean up before run () ends ; } public void stopRunning() { timeToQuit=true;} }
374
7.2 创建线程的 方式 ■ ■ ■
public class ControlThread { private Runnable r=new Xyz(); private Thread t=new Thread(r);
■
public void startThread() { t.start(); }
■ ■ ■
publi void stopThread() { r.stopRunning();}
■ ■ ■
}
375
7.3 线程的挂起 与唤醒 ■ ■ ■ ■
■
暂停线 程的执 行等 待条件 满足 再执行 . 下面的 例子显 示线 程的挂 起和 唤醒 小应用 程序第 一次 开始时 , 线程 被启动 浏览器 改变页 面时 , 小应用 程序 的 stop() 方法被 调用 , 线程被 挂起 . 浏览器 回到原 来的 页面时 , 线程 被唤醒 .
376
7.3 线程的 挂起与唤醒
377
public void start() { if (mythread==null) {mythread=new Thread(); mythread.start();} else { mythread.resume();} } public void run() { while(true){ try{sleep(100);} catch(InterruptedException e) {}} } public void stop() { mythread.suspend(); }.
7.4 多线程问题 --- 执行的顺序
378
多个线 程运行 时 , 调度策 略为固 定优 先级 调度 . 级别相 同时 , 由操作 系统按 时间 片 来分配 ■ 下面给 出的例 子中 , 共运行 三个 线程 , 它 们做同 样的事 , 每次打 印循环 次数 和自 己的序 列号 , 运行结 果表明 , 它们 并不 是 连续运 行的 . ■ 在上例 中如果 给某 个线程 赋予 较高的 优 先权 , 则发现 这个进 程垄 断控制 权 thread.setPriority(Thread.MAX_PRIORITY) ■ thread\multithread.class--f1.bat ■ thread\Priority.class---f2.bat ■
// 多个进 程运行 时执 行顺序 是交 叉的 379 7.3 多线程 问题 Thread class multithread extends { int threadNum; public static void main(String args[]) { multithread array[]=new multithread[3]; for (int i=0;i<3;i++) array[i]=new multithread(i); for (int i=0;i<3;i++) array[i].start(); } multithread(int SerialNum) { super(); threadNum=SerialNum; } public void run() { for(int j=0;j<5;j++) System.out.println(“<"+j+"> +MySerialNum); System.out.println("thread "+threadNum+ "bye.");}}
7.4 多线程 问题 --- 如何写多线 程 1. 分别 定义不 同的 线程类 , 在各自 的 run 方法中 定义线 程的 工作 class mythread1 extends Thread { public void run{….} } class mythread2 extends Thread { public void run{….} } 2. 在主类中 实例 化各线 程类 , 并启 动线程 . public class demo extends Applet { public void init() { mythread t1=new mythread1(); mythread t2=new mythread2(); t1.start(); t2.start();} }
380
7.4 多线程问题 --- 如何写多线程
381
: 将窗口 分为上 下两 个区 , 分别运 行 两个线 程 , 一个在 上面的 区域 中显示 由右 向左游 动的 字符串 , 另一 个在下 面的 区域 从左向 右游 动的字 符串 . ■方法一 : 一个线 程 , 在 paint 方法 中使用 两个输 出字 符串的 语句 ■练习
public void paint(Graphics g) { if y1<0 y1=200 else y1=y1-10; if y2>200 y2=0 else y2=y2+10; g.drawString(“hello, Java!”,20,y1,); g.drawString(“hello, Java!”,40,y2,); }
7.4 多线程问题 --- 如何写多线程 ■
■
382
方法二 : 定义两 个类 , 运行各 自的线 程 , 各 自有自 己的 paint() 方法 . 注意 : 两个 小应用 程序 必须是 panel 类或者 是 canvas 类 , 将小 应用的 区域 分成两 块 , 否 则不能 运行 paint 语句 .
7.4 多线程 问题 --- 线程间的通 信
383
1. 线程间的 通信 可以用 管道 流 ,. 线程 1 PipedOutputStream PipedInputStream 输出流 outStream 输入流 inStream
线程 2
创建管 道流 : PipedInputStream pis=new PipedInputStream(); PipedOutputStream pos=new PipedOutputStream(pis); 或: PipedOutputStream pos=new PipedOutputStream(); PipedInputStream pis=new PipedInputStream(pos);
384
7.4 多线程 问题 --- 线程间的通 信 ■
管道流不能 直
printStream
接读写
DataInputStream
PrintStream p = new PrintStream( pos ); p.println(“hello”); DataInputStream d=new DataInputStream(pis); d.readLine(); ■ 2. 通过 一个中 间类 来传递 信息 . s s 线程 1
中间类 m
线程 2 s=m.read()
m.write(s) write()
read()
7.4 多线程 问题 -- 线程间的通信
385
管道流 可以连 接两 个线程 间的 通信 ■ 下面的 例子里 有两 个线程 在运 行 , 一个 往外 输出信 息 , 一个 读入信 息 . ■ 将一个 写线程 的输 出通过 管道 流定义 为读 线 程的输 入 . outStream = new PipedOutputStream(); inStream = new PipedInputStream(outStream); new Writer( outStream ).start(); new Reader( inStream ).start(); ■
386
7.4 多线程 问题 -- 线程间的通信 主类 Pipethread 作为参 数传给 Writer 辅类 Writer Writer( outStream ) 线 程 将数据 写 类 到输出 流
管 道 流 输入流
辅类 Reader 线 程 类 从流中 读数据
■
(thread\Pipethread.class--f3.bat)
387 public class Pipethread 7.4static 多线程 问题 -- 线程间的通信 { public void main(String args[]) { Pipethread thisPipe = new Pipethread(); ■ . thisPipe.process(); } public void process() { PipedInputStream inStream; PipedOutputStream outStream; PrintStream printOut; try{ outStream = new PipedOutputStream(); inStream = new PipedInputStream(outStream); new Writer( outStream ).start(); new Reader( inStream ).start(); }catch( IOException e ){ } } }
class Reader extends Thread 388 { private inStream;// 从中 7.4 PipedInputStream 多线程 问题 --- 线程间的通 信读数据 public Reader(PipedInputStream i) { inStream = i; } public void run() { String line; DataInputStream d; boolean reading = true; try{ d = new DataInputStream( inStream ); while( reading && d != null){ try{line = d.readLine(); if( line != null ){ System.out.println( ”Read: " + line ); } else reading = false; }catch( IOException e){ } } catch( IOException e ){ System.exit(0); } try{ Thread.sleep( 4000 );} catch( InterruptedException e ){}}}
389 class Writer extends Thread 7.4 PipedOutputStream 多线程 问题 -- 线程间的通信 { private outStream;// 将数 据输出 private ■ . String messages[ ]= { "Monday", "Tuesday ", "Wednsday", "Thursday","Friday :", "Saturday:","Sunday :"}; public Writer(PipedOutputStream o) { outStream = o; } public void run() { PrintStream p = new PrintStream( outStream ); for (int i = 0; i < messages.length; i++) { p.println(messages[ i ]); p.flush(); System.out.println("WrIte:" + messages[i] ); } p.close(); p = null;
7.3 多线程 问题 --- 资源协调
390
1. 数据的 完整性 线程 1 线程 2
取过来
加1 后送 回去
资源
变量
线程 10
withdrwal()
余额
透支
withdrwal()
7.3 多线程 问题 --- 资源协调 ■ ■ ■ ■
391
对共享 对象的 访问 必须同 步 , 叫做条 件变量 . Java 语言 允许 通过监 视器 ( 有的参 考书称 其为管 程 ) 使用 条件变 量实 现线程 同步 . 监视器 阻止两 个线 程同时 访问 同一个 条件 变量 . 它的如 同锁一 样作 用在数 据上 . 线程 1 进入 withdrawal 方法时 , 获得 监视器 ( 加锁 ); 当线程 1 的方法执 行完 毕返回 时 , 释放监 视器 ( 开锁 ), 线程 2 的 withdrawal 线程 2方 监视 能进入 .
线程 1
器
withdrawal()
392
7.3 多线程 问题 --- 资源协调 ■
■
用 synchronized 来标识 的区域 或方 法即为 监视器 监视的 部分 。 一个类 或一个 对象 由一个 监视 器 , 如果 一 个程序 内有两 个方 法使用 synchronized 标 志 , 则他 们在一 个监 视器管 理之 下 . 线程 1
read
■
监 视 器
线程 2
write
一般情 况下, 只在 方法的 层次 上使用 关键 区
7.3 多线程 问题 --- 资源协调
393
此处给 出的例 子演 示两个 线程 在同步 限制 下工作 的情 况. class Account { statics int balance=1000; // 为什 么用 static? statics int expense=0; public synchronized void withdrawl(int amount) { if (amount<=balance) { balance-=amount; expense+=amount;} else { System.out.println(“bounced: “+amount);}
7.3 多线程 问题 --- 资源协调 ■
394
2. 等待同步 数据 . 生产者
write.
共享对 象
消费者
read
可能出 现的 问题 : • 生产者 比消费 者快 时 , 消费者会 漏掉 一些数 据没有 取到 • 消费者 比生产 者快 时 , 消费者取 相同 的数据 . • notify() 和 wait () 方法用 来协调 读取 的关系 . • notify() 和 wait () 都只能 从同步 方法 中的调
7.3 多线程 问题 --- 资源协调
395
■
notify 的作用 是唤醒 正在 等待同 一个 监视 器的线 程 .
■
wait 的作 用是让 当前 线程等 待 信息版 例子 read() 方法在 读信息 之前 先等待 , 直到信息 可读 , 读完后 通知要 写的 线程 . write() 方法 在写信 息之 前先等 待 , 直到信 息被取 走 , 写完 后通 知要读 的进 程 . DemoWait.class--->f4.bat
■ ■
■
■
7.3 多线程 问题 --- 资源协调
writer aaaa aaaa aaaa aaaa aaaa bbbbb cccccccccccc cccc cccc
396
reader aaaa bbbbb cccc
aaaa bbbbb
7.3 多线程 问题 --- 资源协调 ■ ■ ■ ■ ■ ■ ■ ■ ■
397
class WaitNotifyDemo { public static void main(String[] args) { { MessageBoard m = new MessageBoard(); Reader readfrom_m = new Reader(m); Writer writeto_m=new Writer(m); readfrom_m.start(); writeto_m.start(); } }
class MessageBoard { 398 { private message; 7.3String 多线程 问题 --- 资源协调 private boolean ready = false;( 信号 灯 ) public synchronized String read() { while (ready == false) { try { wait(); } catch (InterruptedException e) { } } ready = false; notify(); // 起始 状态先 写后 读 return message; } public synchronized void write(String s) { while (ready == true) { try { wait(); } catch (InterruptedException e) { } } message = s; ready = true; notify(); }}
class Reader extends Thread 7.3 MessageBoard 多线程 问题 mBoard; --- 资源协调 { private public Reader(MessageBoard m) { mBoard = m; } public void run() { String s = " "; boolean reading = true; while( reading ){ s = mBoard.read(); System.out.println("Reader read: " + s); if( s.equals("logoff") ) reading = false; } System.out.println("Finished: 10 seconds..."); try{ sleep( 10000 ); } catch (InterruptedException e) { } } }
399
class Writer extends Thread { private 7.3MessageBoard 多线程 问题mBoard; --- 资源协调 private String messages[ ]= { "Monday :------------------------", “…..”, "Sunday : ----------------------"};
400
public Writer(MessageBoard m) { mBoard = m; } public void run() { { for (int i = 0; i < messages.length; i++) { mBoard.write(messages[ i ]); System.out.println("Writer wrote:" + messages[i] ); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } }
401
7.3 多线程 问题 --- 资源协调 多线成 问题 --- 资源 的协调 和锁 定 1. 死锁问 题 ■
线程 1
note
把“ pen” 给我 , 我 才能给 你“ note” 把“ note” 给我 , 我 才能给 你“ pen”
线程 2
pen
如果 你的持 有一 个锁并 试图 获取另 一个 锁时 , 就有死 锁的危 险 . 解决 死锁问 题的 方法 : 给条件变 量施 加排序
7.3 多线程 问题 ---daemon 线程 ■
什么是 daemon( 守护 )?
■
在客户 / 服务 器模式 下 , 服务器 的作用 是 等待用 户发 来请求 , 并按 请求完 成客 户的 工作 request 服务器端 客户端
daemon ■ ■ ■
守护线 程是 为其它 线程 提供服 务的 线程 守护线 程一 般应该 是一 个独立 的线 程 , 它 的 run() 方法是一 个无 限循环 . 守护线 程与 其它线 程的 区别是 , 如果 守护
402
7.4 小结
403
1. 实现线 程有两 种方 法 : ■ 实现 Ruannable 接口 ■ 继承 Thread 类 2. 在小应 用中通 常在 start 中创建 线程 3. 当新 线程被 启动 时 ,java 调用 该线程 的 run 方 法 , 它是 Thread 的核 心 . 4. 线程由 四个状 态 : 新生 , 运行 , 暂停 , 死亡 5. 线程间 的通信 方式 由三种 : 完全 共享数 据 , 通过监 视器 , 通过 join.
7.4 小结
404
6. 两个或 多个线 程竞 争资源 时 , 需要用 同步 的方法 协调资 源 . 7. 多个线 程执行 时 , 要用到 同步方 法 , 即使用 synchronized 的关 键字设 定同 步区 8. wait 和 notify 起协调 作用 9. 守护 进程的 特点 是当程 序中 制胜它 自己 时 , 会自动 中止 .
作业 ■
405
创建两 个线程 的实 例 , 分别 将一 个数组 从小 大大和 从达到 小排 列 . 输出 结果 .
第 8 章网络功能
北京 大学计 算机 系 代亚 非
第 8 章网络功能 ■ ■ ■ ■ ■ ■ ■ ■ ■
8.1 Java 与 internet 8.2 使用 URL 8.3 访问 cgi 8.4 URL 连接 8.5 Socket 8.6 internet 应用 8.7 数据 报 8.8 JDBC 8.9 小结
407
8.1 Java 与网络 ■ ■ ■
■
■
■
408
Java 语言 取得 成功的 领域 之一就 是网 络 ( 其他语 言 ) 数页 代码 ---->(Java) 一条语 句 TCP/IP( 传输控 制协 议 / 网间协 议 ) 是 internet 的主要 协议 , 定义了 计算机 和外 设进行 通信 所使用 的规则 ( 应用 层 , 传输 层 , 网络 层 , 链 路层 ). 大多数 基于 internet 的应用 程序 被看作 TCP/IP 协议 的上 一层 . 如 : ftp, http, smtp, pop3, telnet, nntp 等 IP 地址 :TCP/IP 网络中 的每台 计算 机都有 唯 一的地 址 --IP 地址 . 在 Java 中 , 有一个 用来存 储 internet 地址的 类
8.1 Java 与网络 例 : 获取 本机的 IP 地址 import java.net.*; public class getLocalHostTest { public static void main() { InetAddress myIP=null; try {myIP=InetAddress.getLocalHost();} catch{UnknowHostException e){} System.out.println(myIP); } } 创建 inetAddress 类不用 构造函 数 ( 不用 new) ■
409
8.1 Java 与网络
410
下面的 例子演 示 java 如何根 据域名 自动 到 DNS 上查找 IP 地址 ( 与 DNS 服务器 的连接 减至 一行 ) import java.net.*; public class getIP { public static void main(String args[]) { InetAddress pku=null; try{ pku= InetAddress.getByName(“www.pku.edu.cn”); }catch(UnknowHostException e) {} System.out.println(pku); } }
8.1 Java 与网络
411
■
Java 提供的网 络功 能有三 大类 : URL, Socket, Datagram.
■
URL 是三 大功能 中最 高级的 一种 , 通过 URL Java 程序可 以直接 送出 或读入 网络 上 的数据 .
■
Socket 是传统 网络程 序最 常用的 方式 , 可以 想象为 两个不 同的 程序通 过网 络的通 信信 道.
■
Datagram 是更 低级的 网络 传输方 式 , 它把 数据的 目的纪 录在 数据包 中 , 然后直 接放在
8.2 使用 URL ■
■ ■
■ ■ ■ ■ ■
412
8.2.3 通过 URL 读取 WWW 服务 器上 的数 据 将 URL 位置的 数据 转成一 个数 据流 URL url=new (http://www.pku.edu.cn/index.html” DataInputStream data=new DataInputStream(url.openStream()); 从数据 流中读 出数 据 String line=data.readLine() whileDataInputStream ( line ! =null ) URL Java 程序 line=data.readLine()
8.2 使用 URL
413
http://www.pku.edu.cn/
<...>
例 : 从给 定的位 置中 读数据 (ReadURLData.prj) connect TextField a
Frame 主类
str=a.getText()
action
URL url=new URL(str) URL url
TextArea c
Button
b=url.openStream()
line_str=b.readLine() c.appendText(line_str); DataInputStream b
public boolean action(Event evt, Object arg) { try{ 8.2 使用 URL String line; String str=textfield.getText(); url=new URL(str); data=new DataInputStream(url.openStream()); while((line=data.readLine())!=null){ textarea.appendText(line); } data.close(); }catch(MalformedURLException me){ System.out.println("Error URL"); }catch(IOException ie){ System.out.println("Error IO"); } return true; }
414
415
8.3 访问 cgi ■
起始页 上的计 数器 及 cgi 程序 (script)
欢迎来访 , 你是第
1 2 7
个来 访者 !
你是 第
个来 访者 客户端 HTML
cgi 程序名 img
服务器 端 CGI 程序
num+ +
416
8.3 访问 cgi Your name form send
Web 服务器
cgi 程序
数据 库 服务 器
reset