• 1. Java程序设计 Programming in Java安徽大学计算机科学与技术学院 段 震 mailto: ycduan@gmail.com1
  • 2. 引用声明本课件部分内容引自雍俊海于Java程序设计教程. 北京: 清华大学出版社, 2007中所提供的课件2
  • 3. 课程选用教材雍俊海. Java程序设计教程. (第二版) 北京: 清华大学出版社, 2007.3
  • 4. 参考资料Bruce Eckel Thinking in Java Cay Horstmann Core Java 2 Volume 1 – Fundamentals Kathy Sierra Head First Java 林信良 JAVA JDK6 学习笔记 张孝祥 Java就业培训教程 孙卫琴 JAVA面向对象编程 SUN Java API Document ……Java中的MSDN4
  • 5. 教学内容第01章 绪论 第02章 结构化程序设计 第03章 面向对象程序设计 第04章 数组、字符串、向量与哈希表 第05章 泛型、枚举与for语句的简化写法 第06章 异常处理、递归和单体程序设计方法 第07章 文件与数据流5
  • 6. 教学内容第08章 Swing图形用户界面程序设计 第09章 小应用程序(Applet) (有兴趣可自学) 第10章 编程规范和程序调试(务必自学) 第11章 多线程程序设计 第12章 网络程序设计(自学) 第13章 多媒体与图形学程序设计(有兴趣可自学) 第14章 数据库程序设计6
  • 7. 第 1 章 绪论Java简介 开发环境的建立 简单Java程序的编写 Java程序的工作原理7
  • 8. 1.1 Java历史简介SUN公司 1) 1991: Oak 用于智能消费型电子产品的语言 James Gosling 市场需求发展没有预料的快,差一点就要取消 2) 1993: 网络的发展, 挽救了这个项目 为网页增加了“动态的内容”,即动态网页设计 3) 1994: Oak应用于网络, 称为Java 4) 1995: Java正式公布Stanford University Network8
  • 9. JDK版本的名称版本号名称中文名发布日期 JDK 1.1.4Sparkler宝石1997-09-12JDK 1.1.5Pumpkin南瓜1997-12-13JDK 1.1.6Abigail阿比盖尔--女子名1998-04-24JDK 1.1.7Brutus布鲁图--古罗马政治家和将军1998-09-28JDK 1.1.8Chelsea切尔西--城市名1999-04-08J2SE 1.2Playground运动场1998-12-04J2SE 1.2.1none无1999-03-30J2SE 1.2.2Cricket蟋蟀1999-07-08J2SE 1.3Kestrel美洲红隼2000-05-08J2SE 1.4.0Merlin灰背隼2002-02-13J2SE 1.4.1grasshopper蚱蜢2002-09-16J2SE 1.4.2Mantis螳螂2003-06-26J2SE5.0 (1.5.0)Tiger老虎已发布J2SE 6.0 (1.6.0)Mustang野马已发布9
  • 10. Java产品分类J2SE:Java2 Platform, Standard Edition J2SE是Java2的标准版,即桌面版本,用于开发普通桌面应用程序。 J2EE:Java2 Technology, Enterprise Edition J2EE是Java2的企业版,主要用于进行企业级的团体合作开发,Internet和服务器级程序的开发。 J2ME:Java2 Micro Edition   主要用于手机、PDA等移动通讯设备、嵌入式设备或消费性电器的开发。10
  • 11. Java现状Java现在常用来: 1) 开发大规模的商业运用软件 2) 增强网络服务的功能 3) 开发智能消费型电子产品的应用软件 (例如手机)11
  • 12. 1.2 为什么采用Java语言(特点)Java语言白皮书 A simple, object-oriented, distributed, interpreted, robust, secure, architecture-neutral, portable, high-performance, multi-threaded, dynamic language.12
  • 13. 为什么采用Java语言 —— 特点简单性:Java的语法比 C/C++简单 网络特性 面向对象 平台无关性/可移植性 Write Once, Run Anywhere(?) 鲁棒性 安全性 多线程性 解释性13
  • 14. Java与C++的比较Java使用了类似C++的语法,而去除了C++中的复杂内容,以实现其简单、鲁棒、安全、可移植等特性,具体如下: 全局变量 无条件转移指令goto 指针 内存管理 数据类型的一致性14
  • 15. 1.3 建立Java开发环境的步骤1) 下载J2SE安装程序 2) 运行J2SE安装程序,安装J2SE 3) 设置环境变量: 运行路径(path) 类路径(classpath) 4)下载J2SE的在线帮助文档15
  • 16. (1)下载与(2)安装指南http://java.sun.com 例如, 安装: JavaTM 2 SDK, Standard Edition 选择所需的版本 选择对应的操作系统16
  • 17. 编译器及一些工具演示程序用于本地方法的文件Java运行时环境文件库文件安装完成后的JDK目录结构一些示例程序17
  • 18. bin目录中的几个主要程序Javac Java Appletviewer Javadoc Jdb Javah Javap18
  • 19. (3)设置环境变量 假设 Java SDK 安装在 C:\j2sdk 设置: path=%path%;C:\j2sdk\bin classpath= . ; C:\j2sdk\lib19
  • 20. 20
  • 21. (4)下载J2SE的在线帮助文档下载 Java 2 SDK在线帮助文档 From: Sun http://java.sun.com/ Sun 中国技术社区 http://developers.sun.com.cn/21
  • 22. 1.4.1 开发Java程序的基本流程使用文本编辑器(Notepad, Editplus, UltraEdit,…) 编写Java源程序,并命名为 xxx.java 点击“开始”->“运行”,cmd,进入dos状态,进入Java源程序所在目录 编译源程序javac xxx.java ,得到字节码文件(.class文件) 运行程序java xxx ,由java解释器解释执行22
  • 23. 两种类型的Java程序应用程序(Application) 小应用程序(Applet)23
  • 24. 例 1: J_HelloJava (应用程序)public class J_HelloJava { public static void main(String args[ ]) { System.out.println("Java语言,您好!"); System.out.println("我将成为优秀的Java程序员!"); } // 方法main结束 } // 类J_HelloJava结束24
  • 25. 例 1: J_HelloJava (应用程序)// /////////////////////////////////////////////////////////////////// // 功能描述: // 在控制台窗口中输出: // “Java语言,您好!” 和 // "我将成为优秀的Java程序员!" // ///////////////////////////////////////////////////////////////////25
  • 26. 编译 & 执行J_HelloJava.javajavacJ_HelloJava.classjava输出26
  • 27. 程序分析类定义 Java程序的基本组成部分是类(class),如本例中的J_HelloJava类。 一个源文件中最多只能有一个public类。 main()方法 Java Application程序的入口是main()方法。它有固定的书写格式: public static void main(String[] args){ …… }27
  • 28. 例 2 (略): J_HelloApplet.javaApplet 小应用程序 Applet 子类的实例 java.applet.Applet 、javax.swing.JApplet 运行方式 包含小应用程序的HTML文件被打开 运行方法 appletviewer (小应用程序的测试工具) 网页浏览 (IE和Netscape等)28
  • 29. 例 2 : J_HelloApplet.java// //////////////////////////////////////////////////////// // 在一个网页上显示: // "小应用程序,您好!" // ////////////////////////////////////////////////////////29
  • 30. 通过文本编辑器 (如: UltraEdit) 创建并编写Java源文件// 文件名: J_HelloJava.java; 开发者: 雍俊海 import java.awt.Graphics; import javax.swing.JApplet; public class J_HelloApplet extends JApplet { public void paint(Graphics g) { g.clearRect(0, 0, getWidth( ), getHeight( )); // 清除背景 g.drawString("小应用程序,您好!", 10, 20); } // 方法paint结束 } // 类J_HelloApplet结束30
  • 31. 通过文本编辑器 (如: UltraEdit) 创建并编写HTML文件 简单招呼小应用程序例程 31
  • 32. 编译源文件 &运行小应用程序J_HelloApplet.javajavacJ_HelloApplet.classappletviewer/IE32
  • 33. 1.4.2 Java程序的工作原理Java程序Java APIsJava虚拟机计算机系统33
  • 34. 1.4.2 Java程序的工作原理34
  • 35. 安全性字节码的运行要经过三步: 加载代码:由class loader 完成; 校验代码:由bytecode verifier 完成; 执行代码:由 runtime interpreter完成。35
  • 36. 开发工具介绍1、JCreator (教学使用) JCreator 是一个Java程序开发工具,也是一个Java集成开发环境(IDE)。 JCreator的设计接近Windows界面风格,用户对它的界面比较熟悉。其最大特点是与我们机器中所装的JDK完美结合,是其它任何一款IDE所不能比拟的。 JCreator是一种初学者很容易上手的java开发工具,缺点是只能进行简单的程序开发,不能进行企业J2EE的开发应用。 Xinox Software公司的JCreator,分为为LE和Pro版本。LE版本功能上受到一些限制,是免费版本。Pro版本功能较全,是共享软件。36
  • 37. 开发工具介绍2、Eclipse 号称未来能进行任何语言开发的IDE集大成者。 Eclipse是一个开放源代码的项目,任何人都可以下载Eclipse的源代码,并且在此基础上开发自己的功能插件。 可以无限扩展,而且有着统一的外观,操作和系统资源管理,这也正是Eclipse的潜力所在。37
  • 38. 38
  • 39. 开发工具介绍3、NetBeans 4、JBuilder 5、……39
  • 40. 第2章 结构化程序设计标识符和关键字 数据类型、直接量和变量 运算符 控制结构 结构化程序设计40
  • 41. 2.1.1 Java中的标识符标识符可以用来标识变量名、类名、类中的方法名和文件名等. 标识符组成: (1) 字母, (2)数字, (3)下划线“_” 和 (4)美元符号“$”; 首字符必须是(1) 字母, (2)下划线“_” 和 (3)美元符号“$”; 所有标识符是区分大小写的; 除去关键字、false、true和null;41
  • 42. 问: 是/不是 标识符?myVariable 9pins MYVARIABLE i a+c testing1-2-3_myvariable java¨ My Variable $myvariable _9pins It's 猫Eg:判断一个字符是否可以做Java标识符的起始字符或后继字符42
  • 43. public class J_Identifier { public static void main(String args[ ]) { char c = '猫'; if (Character.isJavaIdentifierStart(c)) System.out.println("字符\'"+c+"\'可以做标识符的首字符"); else System.out.println("字符\'"+c+"\'不可以做标识符的首字符"); if (Character.isJavaIdentifierPart(c)) System.out.println("字符\'"+c +"\'可以做标识符除首字符外的组成字符"); else System.out.println("字符\'"+c +"\'不可以做标识符除首字符外的组成字符"); } // 方法main结束 } // 类J_Identifier结束J_Identifier.java43
  • 44. 2.1.2 Java关键字具有特殊含义的字符序列 例如: public、 static和class等 具有特殊用途,不能作为变量名、方法名和类名44
  • 45. Java关键字(50个)45
  • 46. 2.2 Java中的数据类型数据类型基本类型引用类型字符类型(char) 布尔类型(boolean)类、枚举(enum)、接口(interface)数组注解(annotation)浮点类型 (float, double)整数类型 (byte, short, int, long)数值类型46
  • 47. 基本数据类型基本类型大小 类型取值 boolean1字节8位true,falsebyte1字节8位有符号整数 -128 ~ + 127 char2字节16位Unicode字符 Unicode 0 ~ Unicode 216-1 short2字节16位有符号整数 -32768 (-215) ~ +32767 (+215-1)int4字节32位有符号整数 -2147483648 (-231 ) ~ +2147483647 (231-1) long8字节64位有符号整数 -263 ~ + 263-1float4字节32位浮点数1.4E-45 ~ 3.4E+38 , -1.4E-45 ~ -3.4E+38 double8字节64位浮点数4.9E-324 ~ 1.7E+308, -4.9E-324 ~ -1.7E+308 47
  • 48. Java直接量Java直接量包括基本数据类型直接量、字符串(String)直接量和null 布尔(boolean)直接量只有两个:true 和 false ‘c’, ‘\u0061’, ‘\u0051’ 和 ‘\u005a’ 是char直接量. 34是int直接量 1.5, 45.6, 76.4E8和-32.0是double直接量 34L是long直接量 1.5F, 45.6f, 76.4E8F和-32.0F是float直接量 “Hello World!”是String直接量 null是引用数据类型的直接量48
  • 49. 字符直接量可采用如下四种表示方法 整数直接量 单引号括起来的单个字符 ‘A’ ‘人’ 单引号括起来的Unicode字符 ‘\u0061’ 单引号括起来的转义字符 ‘\r’ ‘\n’ ‘\t’ 49
  • 50. 2.2.3 变量变量在计算机内部对应着一个存储单元,而且总是具有某种数据类型:基本数据类型或引用数据类型。 每个变量均具有: 名字、类型、一定大小的存储单元以及值。50
  • 51. 变量如果变量的数据类型是基本数据类型,则在变量的存储单元中存放的是具体的布尔值或数值。 如果变量的数据类型是引用数据类型,则在变量的存储单元中存放的是引用值。 引用值一般用来指向某个具体的对象。 如果引用值是null,则该引用值不指向任何对象。51
  • 52. 变量图例: int sum = 0; String s = “Hello World!”;sum0sf789a1Hello World!52
  • 53. 补充:内存管理简介堆(heap)栈(stack)数据段(data segment)代码段(code segment)堆(heap)栈(stack)数据段(data segment)堆(heap)栈(stack)代码段(code segment)数据段(data segment)堆(heap)栈(stack)代码所占空间静态变量 字符串常量New产生的空间局部变量53
  • 54. 类型转换隐式类型转换 强制类型转换 使用强制类型转换运算符( ) boolean不能与其它基本类型数据进行相互转换byte
  • 55. 2.3 Java运算符算术运算符 关系运算符 布尔逻辑运算符 位运算符 赋值类运算符 条件运算符 其他运算符55
  • 56. 1. 算术运算符算术运算符包括:+, -, *, /, ++, --, % 没有指数运算 Math.pow(2.0, 3.0); // 2.03.0 整数除法:截去余数 7 / 5 结果为 1 取模:返回余数 (可对浮点数进行运算) 7 % 5 结果为 256
  • 57. 问题?-7 / 5 = -7 % 5 = 7 % -5 = 5.5 % 1.0 =-1 -2 2 0.557
  • 58. 2. 关系运算符六个关系运算符: <、 >、<=、>=、== 和 != 例如: 1 > 2; // false 3.5 != 1; // true 51.5 >= 23.0; // true 540 <= 654; // true 24 == 3*8; // true boolean test1=(10 < 10); // test1= false;58
  • 59. 3.布尔逻辑运算符六个布尔逻辑运算符: & (逻辑与AND) | (逻辑或OR) ^ (逻辑异或XOR ) ! (逻辑非NOT) 单目运算符, 即只有一个操作数 && (条件与AND) || (条件或OR)59
  • 60. 短路规则 ( &&和|| )如果从第一个操作数可以推断出表达式结果,就不再计算第二个操作数 例如: if ((x == 2) && (y != 2)) System.out.println("两个条件都为 true."); 60
  • 61. 逻辑运算(&和| )两个操作数均会被运算 (即不采用短路规则) 用不用短路规则,副作用不同 例如: (birthday == true) | (++age >= 65)Eg: J_Boolean.java61
  • 62. 4. 位运算符位运算符包括:&、|、~、^、>>、>>>和<< >> 带符号右移 << 左移 >>>不带符号右移 移位操作是:先将整数写成二进制形式,然后按位操作,最后产生一个新的数 注意: 只用于整数62
  • 63. 5. 赋值类运算符赋值类运算符包括:=、+=、-=、*=、/=、&=、|=、%=、<<=、>>=和>>>= op1=op1 二元运算符 op2; 等价于 op1二元运算符= op2; 例如: a=a+b;等价于a+=b;63
  • 64. 6. 条件运算符条件运算符“? :”的表达式形式为“op1 ? op2 : op3” op1:布尔表达式 例如: int k= ( (i>=0) ? 1 : -1);64
  • 65. 条件运算符 public int compare(Date date) { return year > date.year ? 1 : year < date.year ? -1 : month > date.month ? 1 : month < date.month ? -1 : day > date.day ? 1 : day < date.day ? -1 : 0; }65
  • 66. 7. 其他运算符其他运算符包括:(类型)、.、[ ]、( )、instanceof和new 例如: int a=51; char c=(char)a;66
  • 67. 算符优先不同的运算符具有不同的优先顺序 可以用( )来改变优先顺序或使表达式更容易理解 例如: a + b + c / 3 (a + b + c ) / 367
  • 68. 控制结构if / else if / else while for do while switch case break continue 68
  • 69. 控制结构顺序结构 Java最基本的结构 选择结构 三种类型: if、if/else和switch 循环结构 三种类型: for、while和do/while69
  • 70. if语句if语句的格式: if (布尔表达式) 语句 或 if (布尔表达式) { 一条或多条语句 }建议采用70
  • 71. if-else语句if-else语句的格式: if (布尔表达式) 语句1或语句块1 else 语句2或语句块271
  • 72. 多分支选择结构switch语句switch (表达式){ case 值1: 语句组1 break; case 值2: 语句组2 break; … … case 值n: 语句组n break; default: 语句组(n+1) }要求属于: char, byte, short, int Character Byte Short Integer enum72
  • 73. for循环语句格式: for (表达式1;表达式2;表达式3) 语句或语句块 也可写成: 表达式1; while (表达式2 ) { 语句或语句块 表达式3; }73
  • 74. while循环语句while循环语句格式为: while (布尔表达式) 语句或语句块 当条件(布尔表达式)为true ,则不断地执行语句或语句块 “while” 循环中止条件是布尔表达式变为false 如果布尔表达式一开始就为false,则不执行循环体74
  • 75. do/while循环语句先执行,后判定条件 即循规环体至少执行1次 格式 do { 语句或语句块 } while (布尔表达式); 好的编程风格:总是以“{ }”引导循环体,即使语法上并不需要75
  • 76. break语句switch语句中的break语句:终止swtich语句的执行,跳到switch后的语句; 代码块中的break语句: 在Java中,可以为一段代码加上个标号,并用{}把这段代码括起来,这就是代码块,格式为: 标号:{ 代码段; } 程序中可用break 标号;来跳出该代码块,转到该块后的第一个语句去执行,如:76
  • 77. break语句a:{…… //标记代码块a b: {…… //标记代码块b c: {…… //标记代码块c break b; //跳出b块 …… //这段代码不会被执行 }//c结束 …… //这段代码也不会被执行 }//b结束 …… //从这里开始执行 }//a结束 77
  • 78. continue语句continue语句用来结束本轮循环,跳过循环体中下面尚未执行的语句,接着进行终止条件的判断,以决定是否继续循环。 对于for语句,在进行终止条件的判断前,还要先执行迭代语句。它的格式为: continue; 也可以用continue跳转到括号指明的外层循环中,这时的格式为 continue outerLable;78
  • 79. continue语句outer: for( int i=0; i<10; i++ ){ //外层循环 inner: for( int j=0; j<10; j++ ){ //内层循环 if( i
  • 80. break & continue J_Break.java J_ContinueLoopSingle.java J_ContinueLoopNested.java 80
  • 81. 第3章 面向对象程序设计类、域、方法和实例对象 继承性 多态性 包(package) 封装性 关键字abstract、static、final和this 接口 内部类 变量作用域范围和参数传递方式 面向对象程序设计基本思想81
  • 82. 面向对象程序设计整体介绍面向对象程序设计(OOP) 将数据(属性)和方法(行为或功能)封装到类(class)中 数据与方法常常是紧密相关的 对象(object): 类的实例对象或类本身 三个基本特性:封装性、继承性和多态性82
  • 83. 3.1 类类(class)是实例对象的模板 类的定义格式: [类修饰词] class 类名 [extends 父类名] [implements 接口名称列表] { 类体 }83
  • 84. 定义中的相关说明类修饰词:public abstract final strictfp 类名的要求 extends关键字 java.lang.Object简介 implements关键字 类体: 成员域 构造方法 成员方法84
  • 85. 类的成员域用于表示和存储类所需要的数据 [域修饰词列表] 类型 变量名[变量名列表] 域修饰词: public protected private static final transient volatile eg: int m_radius=0; private Student m_s1;85
  • 86. 与C++程序不同: 每个方法都必须隶属于某个类 方法定义的格式: [方法修饰词] 返回类型 方法名(方法的参数列表){ 方法体 } 方法修饰词: public protected private abstract static final synchronized strictfp方法定义86
  • 87. 方法定义返回类型: 返回数据的数据类型 除了构造方法,一般要求返回类型: 要么为void ,要么为某种数据类型 最多只能返回一个值 方法名: 任何一个合法的标识符 参数列表: 用逗号( , )分隔开87
  • 88. 返回控制如果没有值返回: return; // 退出该方法 或者遇到该方法的最后一个“}”,则退出该方法 如果有值返回: return 表达式; // 退出该方法 返回该表达式的值88
  • 89. 构造方法在创建新的实例对象时起作用 构造方法通常用来初始化实例对象 例如: 初始化成员域或设置工作环境 构造方法的特点: 与类同名 没有返回值 ?如果加上了返回值 可以含有多种构造方法(重载) 但必须具有不同的参数列表构造方法演变为普通成员方法89
  • 90. 默认的构造方法如果没有显式地定义类的构造方法,则系统会为该类定义一个默认的构造方法。 默认构造方法不含任何参数。 该方法首先调用其父类的不含任何参数的构造方法,然后初始化新生成的实例的各个成员域变量 默认值: 基本数值类型: 0; boolean: false; 引用数据类型: null 最好自己写构造方法 一旦在类中定义了构造方法,系统就不会再创建这个默认的不含参数的构造方法。90
  • 91. 创建类的实例对象new 构造方法名(构造方法调用参数列表) eg: 类Integer有构造方法 public Integer(int value) new Integer(11) Integer m_i=new Integer(11)91
  • 92. 实例对象的生成首先在内存中创建该实例对象 进行实例对象的初始化 带初始化的变量,进行初始化 然后调用类的构造方法完成初始化 (如果有赋值操作)将实例对象的地址写入引用该实例对象的变量中。92
  • 93. 实例对象的使用成员运算符. 变量名.成员域名 变量名.成员方法名(方法参数)93
  • 94. Java中的垃圾回收机制垃圾:不再被Java程序所用的内存 基本原理:在适当的时机自动回收不再被Java程序所用的内存 垃圾的判定 对于一个实例对象,如果没有任何引用指向该实例对象,则该实例对象所占据的内存是不再被Java程序所用的内存。94
  • 95. Java中的垃圾回收机制eg: Integer a=new Integer(11); a=null;注意分析此时的内存情况95
  • 96. Java中的垃圾回收机制JVM自定义了一套垃圾回收算法,以提高垃圾回收的效率。 一般不会立即回收 不保证回收时间 不保证回收顺序 System.gc( ) 方法 向JVM申请尽快进行垃圾回收,但不保证立刻回收。96
  • 97. Java中的垃圾回收机制protected void finalize( ) Object类中定义的方法 实例对象所占据的内存即将被回收之前,通常调用该方法。 Java不保证在回收实例对象之前一定会调用该方法Eg: J_Finalize.java97
  • 98. 98
  • 99. 补充:包装类类 Integer、Float、Boolean…等 封装了一个对应的基本类型 包装类 对应于8种基本数据类型,有8个包装类 作用? 用于需要使用class类型作为参数的场合 包装类中封装了多种实用功能,方便使用99
  • 100. 3.2 继承性继承性 – 软件重用的一种方法 根据已有的类创建新的类 采纳了旧的类的属性(域)及其行为(方法) 增加了新的能力 子类继承父类 子类增加了新的成员域或新的成员方法 有时可以理解成: (但不绝对!) 子类对象是一种特殊的父类对象100
  • 101. 实现继承的方式[类修饰词] class 类名 [extends 父类名] [implements 接口名称列表] { 类体 } 子类继承父类(及所实现接口)的成员域和成员方法 继承关系具有传递性 默认的父类 java.lang.Object101
  • 102. 继承时构造方法间的约束关系子类构造方法必须调用其直接父类的构造方法 且该调用是子类构造方法的第一条语句 调用方式 super(参数列表); 参数列表能够与父类中的某个构造方法匹配,否则出错; 未显式调用时,则自动调用父类的默认构造方法; 此时,若父类无默认构造方法,则出错。Eg: J_Teacher.java102
  • 103. 子类和父类间的类型转换子类型数据父类型数据 (隐式转换) J_Teacher tom = new J_Teacher() J_Employee a = tom; 此类转换时也可加强制转换运算符 System.out.println(((J_Employee)tom).m_workYear);103
  • 104. 子类和父类间的类型转换父类型数据子类型数据 (显式转换) J_Teacher tom = new J_Teacher() J_Employee a = tom; J_Teacher b=(J_Teacher) a; J_Employee a = new J_Employee() J_Teacher b = (J_Teacher) a;注意过程:T  E  T104
  • 105. 子类和父类间的类型转换无继承关系的类型之间,一般不能进行类型转换。 子类的实例对象同时也是父类的实例对象。 由父类构造方法创建的实例对象一般不是子类的实例对象。 105
  • 106. 关键字: instanceof运算符: instanceof 功能:判断某个引用指向的实例对象是否是某种引用类型的实例对象 例如: if (p instanceof Circle) 上面的条件为 true, 当且仅当引用p所指向的对象是类Circle(或其子类)的实例对象106
  • 107. instanceof 的常见用法先判断一个引用表达式所指向的实例对象是否是目标类型的实例对象,如果是,再进行类型转换及后续操作,避免引用类型转换的runtime error。 eg: J_Employee a = new J_Employee() J_Teacher b; if ( a instanceof J_Teacher) b=(J_Teacher) a; else b=new J_Teacher();107
  • 108. 多重继承在有些计算机语言中,允许一个类有多个直接父类。这种继承关系称为多重继承 Java不支持多重继承 Java 允许一个类有多个直接父接口(interface) 108
  • 109. 3.3 多态性优点: 代码重用 简化设计、简化代码 便于程序扩展109
  • 110. 多态性及其种类多态性: 在类的定义中出现多个构造方法 或出现多个同名的成员方法 对成员方法,还包括在子类中出现与父类型同名的方法 多态性的类型: 静态的多态性重载(overload) 动态的多态性重写 (override)/覆盖 类定义中不建议出现同名的成员域110
  • 111. 3.3.1 静态的多态性(重载)在编译时就能够被识别 针对的是同一个类内的同名方法,也包括一个类对其父类同名方法在功能上的重载。 要求同名的方法有不同的参数列表(方法签名) eg: public int square(int x){ return x * x; } public double square(double x){ return x * x; }Eg: J_Student.java111
  • 112. 识别重载方法识别标志: 参数的个数、类型、数据类型的排列顺序 返回值不能做为识别的标志 参数名不能做为识别的标志 特例:public void add(int i, double i); public void add(double i, int j); add(1.0 , 1 ); add(1 , 1.0); add(1.0 , 1.0); add(1 , 1 );TestOverload.java112
  • 113. 3.3.2 动态多态性(覆盖)在程序运行时才被识别 在子类和父类的类体中均定义了具有基本相同声明的非静态成员方法 不含static关键字 基本相同:方法名相同、参数个数相同、类型相同、且子类成员方法具有相同或更广的访问控制方式。 子类中重写父类的方法Eg: J_Teacher.java113
  • 114. 动态多态性(覆盖)作用:通过父类型的引用调用子类型的成员方法 实现条件: 存在继承关系 子类中重写了父类的成员方法 父类引用指向子类对象 只针对非静态成员方法。静态成员方法不具有动态多态性。114
  • 115. super关键字作用:动态多态性导致子类成员屏蔽了父类成员,需要考虑如何访问父类成员。 使用方式: super.父类型的成员域 super.m_workYear; super.父类型的成员方法(参数列表) super.mb_printInfo( ); super(父类构造方法的参数列表) super( );115
  • 116. this关键字作用:调用同一个类的成员域或成员方法,解决命名冲突。 使用方式: this.当前类的成员域; this.当前类的成员方法; this关键字在实际开发中的用途116
  • 117. 3.4 包可以将一组相关的类或接口封装在包(package)里,从而更好地管理已经开发的Java代码 117
  • 118. 包声明语句package 包名; package语句如果出现,应当是源程序文件中的第一条语句 包名可以是一个标识符,也可以是若干个标识符通过 . 连接而成,通常采用后者 一般形式:所在单位的Internet域名的倒序 eg: package tools; package cn.edu.ahu.cs.ailab118
  • 119. 相关的编译编译参数 javac –d 路径名 xxx.java 如果为当前路径,则路径名为 . 在指定路径根据包名生成层次目录结构 Java中的软件包以目录的形式进行管理 119
  • 120. 包的导入采用import语句导入,该语句是源程序中除包声明之外的最前面若干条语句 格式: import 包名.*; import 包名.类型名; import static 包名.类型名.静态成员方法名; Eg: import fruit.*; import fruit.Apple; import fruit.Grape;120
  • 121. 注意事项每个软件包都有一个包名,包与包之间没有嵌套关系,任何包不会包含其它包。 Eg: 有package package tools; package tools.compress; import tools.* import tools.compress.*121
  • 122. classpathclasspath由一些软件包的根路径组成,之间用 ; 隔开(windows平台) import时根据classpath中的路径进行搜索 eg: classpath= . ; c:\j2sdk\lib 122
  • 123. 实例 J_Employee.java J_Teacher.java J_University.java 123
  • 124. 备注当不采用import导入所需要的包时,可通过在程序中直接使用所用类/方法的全名。 eg: 有package tools,其中有类Calc, Note import tools.*; Calc a = new Calc(); 等同于 tools.Calc a = new tools.Calc(); 124
  • 125. Java 包Java系统提供了很多已经写好的包 数学计算、输入/输出、字符串操作 尽量利用已有的包、避免重复工作 包java.lang 基本软件包,自动导入 提供了Java程序所需要的最基本的类和接口125
  • 126. 3.5 封装性作用:使得各模块的外在表现仅仅为对一些成员域的访问方式和一些成员方法的调用方式,屏蔽具体实现方式。 Java中的封装性通过访问来控制 对类:使用类的成员,派生出子类,生成对象 对成员域:读取/改变成员域的值 对成员方法:调用成员方法 对构造方法:使用构造方法创建实例对象126
  • 127. 类(非内部类)的访问控制方式公共模式(public) 能够被所有软件包使用 默认模式(default) 只能在同一个软件包内部使用 (同包可见) 对类成员的访问首先必须能够访问类,然后由该成员的访问控制方式决定能否访问。127
  • 128. 类成员的访问控制方式成员(域或方法)的访问控制方式: 1) public 2) private 3) protected 4) default(缺省方式)128
  • 129. 成员的访问控制方式: public则该成员可以被任何类中的方法访问 表明对外开放的方式 少量(或者没有) public 域 部分 public 方法 129
  • 130. 成员的访问控制方式: private目的: 隐藏具体的实现细节 只有同一个类的成员方法才能访问私有成员 域常常是private 采用 public “get” 方法读取数据 采用 public “set”方法写数据 eg: Eclipse中提供了为指定成员变量生成Setter和Getter方法的功能130
  • 131. 成员的访问控制方式: protected介于public 和private之间 同一个包内的所有类的所有方法都能访问该成员 如果不在同一个包内的类的方法要访问该成员,则该类必须是该成员所在的类的子类131
  • 132. 成员的访问控制方式: default只有在同一个包内的类的方法才能访问该方法 132
  • 133. 类成员封装性总结133
  • 134. 3.6.1 修饰词abstractJava允许类、接口或成员方法有抽象属性 成员变量、构造方法不允许抽象属性 abstract 类 ——必须被继承 abstract方法——必须被重写 134
  • 135. 修饰词abstract抽象成员方法 [方法修饰词列表] 返回类型 方法名(参数列表); 抽象成员方法不含有方法体 即:只提供方法的头部,但不提供实现的部分,也不允许实现 eg: public abstract double getArea( );135
  • 136. 修饰词abstract抽象类 用abstract修饰的类 一般用于对多个类的特征进行归纳,提取共同特征后形成更一般的抽象类 抽象类不能被实例化 抽象类中可以包含抽象方法,为所有子类定义一个统一的接口,但并不是必须的; 一旦某个类中包含抽象方法,则这个类必须声明为抽象类136
  • 137. 修饰词abstract抽象类的子类除非声明为抽象类,否则必须实现抽象类中所声明的全部抽象方法 优点:利用动态多态性,对抽象类的引用变量进行操作,方便扩展 eg: abstract class J_Shape{ public int m_shapeID=0; public abstract double getArea(); }137
  • 138. 3.6.2 关键字static类的成员变量和成员方法可以为static属性 除内部类之外,普通类不具有静态属性 构造方法不能是静态的 静态成员变量 public static int countT; 静态成员方法 public static void main(String[] args)Eg: J_Book.java138
  • 139. 各类访问和调用方式非静态方法中访问非静态成员变量 成员变量名 this.成员变量名 非静态方法中访问静态成员变量 成员变量名 this.成员变量名 类名.成员变量名教材P88-P89描述有误,需更正139
  • 140. 各类访问和调用方式非静态方法中调用非静态成员方法 成员方法名 this.成员方法名 非静态方法中调用静态成员方法 成员方法名 this.成员方法名 类名.成员方法名 140
  • 141. 各类访问和调用方式静态方法中访问非静态成员变量/方法 不允许直接访问 先创建实例对象,通过该对象进行访问 静态方法中访问静态成员变量 成员变量名 类名.成员变量名 静态方法中调用静态成员方法 成员方法名 类名.成员方法名141
  • 142. 3.6.3 关键字final可以修饰的对象: final 域:不能修改 public static final double PI=……; final 方法:不能重写 final 类:不能继承 public final class System 要求:不能同时具有abstract属性142
  • 143. 关键字final对具有final属性的成员变量 同时具有static属性:必须定义时赋值 public static final double PI=……; 不具有static属性:定义或构造方法中赋值 public final double PI; 构造方法中赋值143
  • 144. 3.7 接口(interface)类抽象类成员方法的属性为public abstract成员变量的属性为public static final引入关键字interface只包含成员方法和成员变量接口abstract144
  • 145. 接口的定义一个接口可以有多个父接口 public interface Runnable{ public abstract void run( ); } 一个.java文件中可以有多个接口,但最多只能有一个public的接口 习惯上,将每个接口定义在一个.java文件中[类修饰词] class 类名 [extends 父类名][接口修饰词]interface接口名[extends 接口1, …,接口n]145
  • 146. 接口接口可看做一种特殊的抽象类,只包含常量和方法的定义,而没有(也不允许)变量和方法的实现。 接口中的成员变量和成员方法具有固定的属性,可省略(初学者谨慎使用) 通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系。146
  • 147. 接口的实现用implements表示一个类使用某个接口,此时将该类称为该接口的实现类 class Car implements Runnable{} class PC implements Runnable{} class Human implements Runnable{} 在类体中可以使用接口中定义的常量,而且必须实现接口中定义的所有方法 一个类可以实现多个接口 例如:class A implements B,C147
  • 148. 接口的实现interface IA{ void work(); } class Test implements IA{ public void work(){ …… } }interface IA{ void work(); } class Test implements IA{ void work(){ …… } }1.接口中的方法为public属性 2.class中的方法不加修饰词,默认为default 3.重写的方法不能有比原方法更严格的访问控制148
  • 149. 使用接口的优点任何实现该接口的类的实例都可以存储在该接口类型的变量中,通过这些变量访问类所实现的接口中的方法。Java运行时系统动态地确定该使用哪个类中的方法。 把接口作为一种数据类型可以不需要了解对象所对应的具体的类,而着重于它的交互界面。 间接实现多重继承149
  • 150. 接口的使用public interface Runnable{ public abstract void run( ); } class Car implements Runnable{…} class PC implements Runnable{…} class Human implements Runnable{}150
  • 151. 接口的使用class InterfaceTest{ public static void main(String[] args){ Runnable c=new Car (); c.run(); c=new PC(); c.run(); c=new Human(); c.run(); } }汽车开动电脑运行人跑动151
  • 152. 3.8 内部类定义在其它类内部的类称为内部类(Inner Class) 内部类所在的类称为外部类(Outer Class) 内部类有些类似于类的成员域或成员方法 实名内部类 静态实名内部类 非静态实名内部类 匿名内部类152
  • 153. 实名内部类Eg: class Outer{ int m1,m2; public void Fun1(); class Inner{ int m_data; public void Fun2(); } }153
  • 154. 匿名内部类没有类名 常常用在图形用户界面设计(GUI)中,进行各种事件处理 例如: 鼠标事件、按钮事件和键盘事件等 匿名内部类不具有类名,不能具有抽象和静态属性,不能派生子类 定义: new 父类型名(父类型构造方法参数) { 类体 }154
  • 155. 匿名内部类用于直接生成一个该匿名内部类的对象 主要使用方式: 先让其父类型的变量指向匿名内部类的实例对象 再由该变量调用被匿名内部类覆盖的成员方法J_InnerClass.java155
  • 156. 3.9.1 变量的作用域范围作用域范围:程序中能够使用该变量(域与局部变量)的范围 分类: 全局作用域范围、类作用域范围和块作用域范围156
  • 157. 同名变量的问题允许局部变量与成员变量同名 允许子类和父类的成员变量同名 通过this和super关键字进行区分 尽量避免此类使用 不允许块作用域范围出现重叠测试157
  • 158. 3.9.2 方法调用的值传递方式Java中,方法调用的参数传递方式采用值传递方式 基本数据类型传递数据值 引用数据类型传递引用值 可通过形参修改实参所指向的对象 形参也可指向新的对象 158
  • 159. 第4章 数组、字符串、向量与哈希表数组 字符串 字符串缓冲区 向量 哈希表159
  • 160. 4.1 数组Java中的数组是一种引用数据类型 数组对象包含了一系列具有相同类型的数据元素,还含有成员域length 当数组的元素仍然是数组时,构成了多维数组160
  • 161. 4.1.1 一维数组数组类型的变量,简称为数组变量,其存储单元存放的是数组对象的引用 一维数组的声明 数组元素的数据类型[ ] 变量名; 数组元素的数据类型 变量名[ ]; char[ ] a, b, c; char a[ ], b[ ], c[ ]; char a[ ], b, c?161
  • 162. 数组对象的创建一、通过new运算符 char[ ] c; c = new char[5]; char[ ] c = new char[5]; 二、通过初始化语句 char[ ] c = { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’}; 注意:声明时不必指定数组的大小162
  • 163. 数据元素的访问数组变量名[下标] 下标从0开始 当数组元素的数据类型是引用类型时,数组变量名[下标]的值是引用。在未赋值之前,其默认值为null 163
  • 164. Exampleclass Student; Student s[] = new Student[3]; s[0] = new Student(“Tom”,18,’M’); s[1] = new Student(“Jerry”,18,’F’); s[2] = new Student(“Marry”,17,’F’);分析内存的变化过程164
  • 165. 4.1.2 多维数组当数组元素的类型是数组类型时,就构成了多维数组 多维数组的声明 数组元素的数据类型[ ]…[ ] 变量名; 数组元素的数据类型 变量名[ ]…[ ]; char[ ][ ] a, b, c; char a[ ][ ], b[ ][ ], c[ ][ ]; 165
  • 166. 多维数组的创建一、直接创建多维数组对象 new 类型[ ][ ]…[ ] eg: int matrix[ ][ ] = new int[2][2];166
  • 167. 多维数组的创建二、从高维开始逐维创建数组对象 int matrix[ ][ ] = new int[2][ ]; matrix[0] = new int[2]; matrix[1] = new int[2]; 167
  • 168. 多维数组的创建int [ ] [ ] [ ] matrix3D; matrix3D = new int[3][ ][ ]; matrix3D[0] = new int[2][ ]; matrix3D[1] = new int[3][ ]; matrix3D[2] = new int[2][ ]; matrix3D[0][0] = new int[2]; matrix3D[0][1] = new int[3]; matrix3D[1][0] = new int[4]; matrix3D[1][1] = new int[5]; matrix3D[1][2] = new int[7]; matrix3D[2][0] = new int[2]; matrix3D[2][1] = new int[3];168
  • 169. 多维数组的创建三、采用数组初始化语句创建数组对象 int [ ][ ] = { {1,2} , {3,4} } 169
  • 170. 多维数组Java语言中,由于把多维数组看作是数组的数组,数组空间不是连续分配的,所以不要求多维数组每一维的大小相同。 在Java语言中,必须首先为最高维分配引用空间,然后再顺次为低维分配空间。 与一维数组相同,对于复合类型的数组,必须为每个数组元素单独分配空间。 170
  • 171. 注意事项Java允许数组的维数为: 三、四、或更大 但是,慎用高维数组 甚至三维数组在实际的应用中也比较少出现171
  • 172. 4.2 字符串字符串是字符的序列,是组织字符的基本数据结构。 Java语言中,把字符串作为对象来处理,它提供了一系列的方法对整个字符串进行操作。 类String和StringBuffer 定长字符串:String类 (效率较高) 可变字符串:StringBuffer类 (使用灵活) 是final型的,不能被继承 有多种构造方法172
  • 173. 4.2.1 StringJava中,字符串不需要任何特殊字符来界定字符串的首尾 java.lang.String 构造String对象的方法 173
  • 174. 一、通过字符串直接量String 直接量 双引号括起来的字符序列 示例: “Hello” 或 “您好" 字符串赋值 可以在声明时赋值 String c = "blue"; c是String类型的变量 "blue"是String直接量174
  • 175. 二、通过String的构造方法new String(参数); String( ) String(String value) String(char value[ ]) String(char[ ], int startIndex, int numChars) String(byte[ ], byte hiByte) String(byte[ ], byte hiByte, int startIdnex,int numChars) 175
  • 176. public class J_StringConstructors { public static void main(String args[ ]) { String s1 = null; String s2 = new String( ); String s3 = "您好!"; String s4 = new String( s3 ); System.out.println("s1: " + s1); System.out.println("s2: " + s2); System.out.println("s3: " + s3); System.out.println("s4: " + s4); } }s1不指向任何字符串对象String构造方法: 创建空字符串String构造方法: 创建新字符串字符串直接量示例176
  • 177. 三、通过String的成员方法Java中,任何一种类型的数据都可以转化成字符串类型的数据。 java.lang.String的valueOf方法 对基本数据类型: String s = String.valueOf(12); String s = String.valueOf(true);177
  • 178. 三、通过String的成员方法对引用数据类型 String s = String.valueOf(Object obj) Object类中提供了toString()方法,根据当前对象创建一个相应的字符串对象 eg:在System.out.println( )时的处理 在子类中可重写该方法,来生成自己所需要的信息178
  • 179. 三、通过String的成员方法String的实例对象生成后无法修改。因此,如果要进行相应的操作,则需要生成新对象。 各类操作方法:179
  • 180. 字符串拼接方法 concat 拼接两个字符串,并返回一个新字符串 源字符串不会被修改 s1.concat( s2 ) 返回字符串s1和s2拼接的结果 示例: String s1 = "ABC"; String s2 = "XYZ"; s1 = s1.concat(s2); // s1 = s1 + s2;180
  • 181. 字符替换s1.replace( char1, char2 ) 返回一个新的字符串,将s1中的所有char1替换成char2 源字符串没有发生变化 若s1不含char1, 则返回源字符串的引用,即s1 示例: “mesquite in your cellar”.replace(‘e’, ‘o’) 结果返回 "mosquito in your collar" “JonL”.replace(‘q’, ‘x’)结果返回“JonL” (无变化) 181
  • 182. 大小写转换s1.toUpperCase( ) 返回对应的新字符串,各个字母都是大写的 如果没有字符被修改,则返回源字符串的引用 类似方法s1.toLowerCase( )182
  • 183. 去除首尾空白符s1.trim( ) 返回新字符串,源字符串最前面和最后面的的空白符 空白符包括从”\u0000”到”\u0020”的字符,其中”\u0020”是空格 如果字符串没有被改变,则返回源字符串的引用183
  • 184. 从当前字符串中抽取子字符串方法 substring substring(int beginIndex) 返回新的字符串: 当前字符串的子串 该子串从指定的位置开始,并一直到当前字符串结束为止 substring(int beginIndex, int endIndex) 返回新的字符串: 当前字符串的子串 该子串从指定的位置(beginIndex )开始, 到指定的位置(endIndex - 1)结束184
  • 185. 四、通过运算符”+”用”+”将两个String拼接形成一个新的String String s1=“123”+”456”; 当”+”两边中有一个为String时,可调用另一个的toString()方法进行拼接 String s1=“No. “ + 1; 注意: String s1=“123” + 45 + 678; String s1=123 + 45 + “678”;185
  • 186. String类的其它成员方法方法 length( ) 返回 String 的长度 与数组不同之处: String不含有 length成员域 方法charAt(int index) 获得字符串指定位置的字符186
  • 187. 查找字符串中的字符或子串查找字符串(String)中的字符或子串 方法indexOf( ) 四种重载方法 indexOf 返回第一次找到时的下标 如果没有找到,则返回-1 示例: String name = "CoolTools"; System.out.println (name.indexOf("oo"));187
  • 188. 查找字符串中的字符或子串方法 lastIndexOf public int lastIndexOf(int ch, int fromIndex) 从指定位置往回查找,返回找到的最大的字符下标位置 即返回满足下面条件的最大值: (this.charAt(k) == ch) && (k <= fromIndex) 返回-1: 如果当前字符串不含该字符188
  • 189. 字符串比较字符串比较 字符类型的数据也是数值类型数据 比较字符串大小,实际上就是依次比较其所包含的字符的数值大小 小写字母与大小字母是不相同的189
  • 190. 字符串(String)比较方法int compareTo(String anotherString) 比较两个字符串的内容 返回: 0 : 如果字符串内容完全相同 小于0的值: 第一个不相同字符,当前字符串的字符的值小于anotherString对应的字符的值 大于0的值: 第一个不相同字符,当前字符串的字符的值大于anotherString对应的字符的值 int compareToIgnoreCase(String str) 比较两个字符串的内容,但不区分大小写190
  • 191. == 运算符(★)当用于基本数据类型时,用于判别是否相等 当用于引用数据类型时,用来判别引用是否指向相同的对象 Object的equals方法,默认采用==的标准进行两个对象的判断,但可以重载 Java中的部分类重载了equals方法,如String191
  • 192. 字符串(String)比较方法boolean equals(Object anObject) 比较当前的字符串与指定的对象 比较结果为真当且仅当给定的参数不为空,并且具有完全相同的字符序列 例如: s1.equals( "Hi" ); boolean equalsIgnoreCase(String anotherString) 判别相等,但不区分大小写 例如: 在不区分大小写情况下, “hello”与“HELLO”相等192
  • 193. 字符串其它类型charAt( ) Boolean.parseBoolean(“TURE”) Boolean.parseBoolean(null) Boolean.parseBoolean(false) Boolean.parseBoolean(“ABC”) 193
  • 194. 字符串其它类型Short.parseShort(String s) Integer.parseInteger(String s) Long.parseLong(String s) Float.parseFloat(String s) Double.parseDouble(String s) 194
  • 195. 类StringBuffer类 String 字符串(String)对象一旦创建,其内容不能再被修改 (read-only) 类 StringBuffer StringBuffer 对象的内容是可以被修改的 除了字符的长度之外,还有容量的概念 通过动态改变容量的大小,加速字符管理195
  • 196. 三种 StringBuffer构造方法buf1 = new StringBuffer(); 创建空的StringBuffer对象容量为16字符 buf2 = new StringBuffer( capacity ); 创建空的StringBuffer对象指定容量大小 buf3 = new StringBuffer( myString ); 创建含有相应字符序列的StringBuffer对象容量为myString.length() + 16 示例: StringBuffer b = new StringBuffer("hello");196
  • 197. String 和 StringBufferString 和 StringBuffer 是两种不同的类 不能用字符串(String)的实例对象调用类(StringBuffer)的成员方法 反之亦然 String  StringBuffer 构造方法 StringBuffer  String 构造方法 方法 toString()197
  • 198. StringBuffer 方法方法 length() 返回 StringBuffer 的长度 方法 capacity() 返回StringBuffer 的容量 方法 setLength(int newLength) 增加或减小 StringBuffer 的长度198
  • 199. 方法 ensureCapacity (int minimumCapacity)参见在线帮且文档阅读方法ensureCapacity的切确含义 确保StringBuffer对象的容量至少为指定的大小 如果当前容量比指定值(minimumCapacity)小,则重新分配内存 新容量大小为如下的值中较大者: 参数minimumCapacity 的值. 两倍的旧容量,再加上2. 如果minimumCapacity的值比已有容量小,则不做任何操作,直接返回199
  • 200. 处理StringBuffer内字符的方法方法 charAt(int index) 返回StringBuffer 对象中指定位置的字符 方法setCharAt(int index, char ch) 设置 StringBuffer对象中指定位置的字符 方法 getChars(int srcBegin, int srcEnd, char[ ] dst, int dstBegin) 将StringBuffer对象中指定的字符子序列,拷贝到指定的字符数组(dst) 方法 reverse( ) 将StringBuffer 对象中的字符序列按逆序方式排列200
  • 201. insert 和 delete 方法方法append 允许数值类型的值添加到StringBuffer对象中 方法insert 允许将各种数据插到StringBuffer对象的指定位置 方法 delete(int start, int end) 和 deleteCharAt(int index) 允许删除StringBuffer对象中的指定字符201
  • 202. 第6章 异常处理异常处理 递归方法 单体(Singleton)程序设计模式202
  • 203. 6.1 异常处理在程序设计的过程中,错误的产生是不可避免的,Java用面向对象的方法通过异常来处理错误。 优点:简化处理过程、使程序具有统一的处理模式,将各种异常情况集中统一处理 203
  • 204. 6.1.1 异常及其种类异常(Exception) 异常是正常程序流程所不能处理或没有处理的异常情况或异常事件,也称作例外、违例 eg: 数组的下标越界、打开不存在的文件 网络无法连接、操作数超出所要求的范围 少了所需加载的类、…… 自定义异常,要求程序处理204
  • 205. 异常产生的后果一旦引发异常,程序将突然中止,且控制将返回操作系统。 发生异常后,此前分配的所有资源都将保留原先的状态,从而导致资源漏洞。205
  • 206. 异常分类受检异常:编译时就能被Java编译器所检测到 运行时异常:只能在运行时被检测到 错误:各种致命错误,无法由程序来恢复或处理 206
  • 207. 异常的层次结构ThrowableErrorExceptionRuntimeException缺省处理或用户处理由用户捕获或 声明并处理不做处理用户自己产生的异常要处理207
  • 208. ErrorError类对象由Java虚拟机生成并抛出; Error表示”恢复不是不可能,但很困难”的情况下的一种严重问题。 Eg:内存溢出动态链接失败 Eg:虚拟机错误 通常Java程序不应该捕获这类异常,也不会抛出这种异常。208
  • 209. ExceptionException类对象由应用程序处理或抛出。 运行时异常 继承于RuntimeException。Java编译器允许程序不对它们做出处理。 非运行时异常(受检查异常) 除了运行时异常之外的其他由Exception继承来的异常类。Java编译器要求程序必须捕获或者声明抛出这种异常。209
  • 210. 异常示例1import java.io.*; class ExceptionDemo1{ public static void main( String args[ ] ){ FileInputStream fis = new FileInputStream( "text" ); int b; while( (b=fis.read())!=-1 ){ System.out.print( b ); } fis.close( ); } }210
  • 211. 编译运行结果c:\>javac ExceptionDemo1.java ExceptionDemo1.java:4: 未报告的异常 java.io.FileNotFoundException;必须对其进行捕捉或声明以便抛出 FileInputStream fis = new FileInputStream( "text" ); ^ ExceptionDemo1.java:6: 未报告的异常 java.io.IOException;必须对其进行捕捉或声明以便抛出 while( (b=fis.read())!=-1 ){ ^ ExceptionDemo1.java:9: 未报告的异常 java.io.IOException;必须对其进行捕捉或声明以便抛出 fis.close( ); ^ 3 错误 程序必须对这种异常进行处理,否则编译器会指出错误。211
  • 212. 异常示例2class ExceptionDemo2{ public static void main(String [ ] args) { int a = 0; System.out.println( 5/a ); } }212
  • 213. 编译运行结果 编译程序对这种异常不做任何处理,而直接由运行时系统来处理。c:\>javac ExceptionDemo2.java c:\>java ExceptionDemo2 Exception in thread "main" java.lang.ArithmeticException: / by zero at ExceptionDemo1.main(ExceptionDemo1.java:4) c:\>213
  • 214. 总述:异常处理机制(1)Java异常处理机制采用一个统一和相对简单的抛出和处理错误的机制。 1.如果一个方法本身能引发异常,当所调用的方法出现异常时,调用者可以捕获异常使之得到处理;也可以回避异常,这时异常将在调用的堆栈中向下传递,直到被处理。214
  • 215. 总述:异常处理机制(2)2.在Java程序的执行过程中,如果出现了异常事件,就会生成一个异常对象。 3.异常对象包含一些信息,指明异常事件的类型以及当异常发生时程序的运行状态等。 4.生成的异常对象将传递给Java运行时系统,这一异常的产生和提交过程称为抛出(throw)异常。215
  • 216. 总述:异常处理机制(3)5.当Java运行时系统得到一个异常对象时,它将会寻找处理这一异常的代码。找到能够处理这种类型的异常的方法后,运行时系统把当前异常对象交给这个方法进行处理,这一过程称为捕获(catch)异常。 6.如果Java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的Java程序也将退出。216
  • 217. 方法调用栈把异常传播给堆栈,沿着被调用的顺序往前寻找,只要找到符合该异常种类的异常处理程序,就交给这部分程序去处理Method1 Method2 Method3 Read-file callcallcallTry catch 产生异常 throwsthrowsthrows217
  • 218. 6.1.2 异常产生一、由Java虚拟机执行程序时自动发现并产生 二、程序中显式生成 throw java.lang.Throwable类型变量 eg: throw new ArithmeticException(); ArithmeticException e = new ArithmeticException(); throw e;218
  • 219. 6.1.3 异常处理Java 中可用于处理异常的两种方式: 捕获异常(自行处理):可能引发异常的语句封装在 try 块内,而处理异常的相应语句则封装在 catch 块内。 转移异常(回避异常):在方法声明中包含 throws 子句,通知调用者,如果发生了异常,必须由调用者处理。219
  • 220. 方式I:捕获异常try-catch-finally结构: try{ 常规代码 }catch( Exception1 e1 ){ ...... }catch( Exception2 e2 ){ ...... }finally{ ...... }220
  • 221. 1. try捕获异常的第一步是用try{…}选定捕获异常的范围,由try所限定的代码块中的语句在执行过程中可能会生成异常对象并抛出。221
  • 222. 2. catch在catch块中是对异常对象进行处理的代码,每个try代码块可以伴随一个或多个catch语句,用于处理try代码块中所生成的异常事件。 catch语句只需要一个形式参数,参数类型指明它能够捕获的异常类型,运行时系统通过参数值把被抛出的异常对象传递给catch块。 单个代码片段可能会引起多个错误,可提供多个 catch 块分别处理各种异常类型。222
  • 223. catch语句的顺序捕获异常的顺序和不同catch语句的顺序有关 当捕获到一个异常时,剩下的catch语句就不再进行匹配 在安排catch语句的顺序时,首先应该捕获最特殊最易出现的异常,然后再逐渐一般化。 先安排子类,再安排父类(否则编译时出错)223
  • 224. 3. finally思考:异常时,如何保证清除工作的进行? 例:fileopen->read(异常)->fileclose??? 捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。 不论在try代码块中是否发生了异常事件,finally块中的语句都会被执行。 永远被执行??? finallycatch 块finally异常没有异常try 块224
  • 225. class FinallyDemo { int no1,no2; FinallyDemo(String args[]) { try { no1 = Integer.parseInt(args[0]); no2 = Integer.parseInt(args[1]); System.out.println("相除结果为 "+no1/no2); } catch(ArithmeticException i) { System.out.println("不能除以 0"); } finally { System.out.println("Finally 已执行"); } }   public static void main(String args[]) { new FinallyDemo(args); } } 输出 结果225
  • 226. 类Throwable提供的方法getMessage()用来得到有关异常事件的信息 printStackTrace()用来跟踪异常事件发生时执行堆栈的内容。 输出方法调用的栈情况 当前的方法在栈的最顶部 方便测试/调试 J_ExceptionCatch.java226
  • 227. 方式II:转移异常如果在一个方法中生成了一个异常,但是这一方法并不确切地知道该如何对这一异常事件进行处理,这时,一个方法就应该声明抛出异常,使得异常对象可以从调用栈向后传播,直到有合适的方法捕获它为止。227
  • 228. 使用 throws声明抛出异常是在一个方法声明中的throws子句中指明的。 如果一个方法可能导致一个异常但不处理它,要求在方法声明中包含 throws 子句,通知潜在调用者,如果发生异常,由调用者处理。 一个throws子句列举了一个方法可能引发的所有异常类型。228
  • 229. 使用 throws在方法的声明处列出所有的受检异常 返回类型 方法名( 参数列表 ) throws 异常类型1, 异常类型2,… { …… } 在本方法内就可以不处理这些异常 调用该方法的方法就必须处理这些异常 示例: public static void g( ) throws Exception{ throw new Exception( ); }J_Exception.java229
  • 230. 6.1.4 自定义异常类型内置异常不可能始终足以捕获所有错误,因此需要用户自定义的异常类 用户自定义的异常类应为 Exception 类(或者Exception 类的子类)的子类 创建的任何用户自定义的异常类都可以获得 Throwable类定义的方法J_ExceptionNewExample.java230
  • 231. 第 7 章 文件与数据流输入流与输出流 随机访问文件 读写器 对象序列化 文件类 File231
  • 232. 7.1 输入流与输出流通常程序需要从外部获取/输出信息 这个“外部”范围很广,包括诸如键盘、显示器、文件、磁盘、网络、另外一个程序等 “信息”也可以是任何类型的,例如一个对象、串字符、图像、声音等 通过使用java.io包中的输入/输出流类就可以达到输入输出信息的目的。 232
  • 233. 输入流与输出流输入流 为了从信息源获取信息,程序打开一个输入流,程序可从输入流读取信息 输出流 当程序需要向目标位置写信息时,需要打开一个输出流,程序通过输出流向这个目标位置写信息233
  • 234. 输入流与输出流不论数据从哪来到哪去,也不论数据本身是何类型,读写数据的方法大体上都是一样的:读过程写过程打开一个流 读信息 关闭流打开一个流 写信息 关闭流234
  • 235. 输入流与输出流I/O流可以从以下几个方面进行分类 从流的方向划分 输入流 输出流 从流的内容划分 字节流 字符流235
  • 236. 输入流与输出流字节流(面向字节的流) 用于一般目的,以字节(byte)为基本处理单位。 包括从InputStream和OutputStream派生出来的一系列类。 字符流(面向字符的流) 专门用于字符数据,以字符为基本处理单位。 包括从Reader和Writer派生出的一系列类。 在某些场合,字符流比字节流更高效。236
  • 237. 7.1.1 InputStreamInputStream 是用来处理8位字节流的抽象基类,程序使用其子类来读取8位的字节信息 提供了输入处理的基本接口,并且部分实现了其中的某些方法 System.in:标准输入 (从键盘) J_Echo.java237
  • 238. InputStream基本方法 abstract int read() :读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。 int read(byte[] b) :将数据读入字节数组,并返回实际读取的字节数。若返回-1,表示读到了输入流的末尾。 void close() :关闭输入流,释放和这个流相关的系统资源。238
  • 239. FileInputStream用来进行文件输入处理,由它所提供的方法可以打开本地主机上的文件,并进行顺序的读。 public FileInputStream(String name) throws FileNotFoundException 创建文件对应的输入流对象,获得系统资源 对文件进行读操作 调用close方法关闭文件,释放资源J_EchoFile.java239
  • 240. 7.1.2 OutputStreamOutputStream 是用来处理8位字节流的抽象基类,程序使用其子类来写入8位的字节信息 提供了输出处理的基本接口,并且部分实现了其中的某些方法 System.out:标准输出 (从屏幕) System.err:标准错误输出 (从屏幕) J_Write.java240
  • 241. OutputStream基本方法 abstract void write(int b) :往输出流中写入一个字节。 void write(byte[] b) :往输出流中写入数组b中的所有字节。 void close() :关闭输出流,释放和这个流相关的系统资源。 void flush() :刷新输出流,强制缓冲区中的输出字节被写出241
  • 242. FileOutputStream用来进行文件输出处理,由它所提供的方法可以打开本地主机上的文件,并进行顺序的写。 public FileOutputStream(String name) throws FileNotFoundException 创建文件对应的输出流对象,获得系统资源 对文件进行写操作 调用close方法关闭文件,释放资源J_WriteFile.java242
  • 243. 补充:过滤流过滤流在读/写数据的同时可以对数据进行处理。 类FilterInputStream和FilterOutputStream分别作为所有过滤输入流和输出流的父类。243
  • 244. 补充:过滤流为使用过滤流,首先必须把过滤流连接到某个输入/输出流上。 通常通过在构造方法的参数中指定所要连接的输入/输出流来实现。 例如: FilterInputStream(InputStream in) FilterOutputStream(OutputStream out)244
  • 245. 7.1.3 PrintStreamOutputStream FilterOutputStream PrintStream 特性: 包含可以用来直接输出多种类型数据的不同成员方法 大部分方法不抛出异常----“吃掉”(traps)所有的异常 可选择是否自动强制输出(flush)245
  • 246. PrintStream构造方法: public PrintStream(OutputStream out) public PrintStream(OutputStream out, boolean autoFlush) public PrintStream(String filename) throws … 其它方法 append() print() //多种重载方法 println() //多种重载方法 format() printf()J_PrintStream.java246
  • 247. 7.1.4 数据输入/输出流DataInputStream/ DataOutputStream可以用与机器无关的格式读取各种类型的数据 两个类一般配合使用 DataInputStream byte readByte() long readLong() double readDouble() String readUTF() DataOutputStream void writeByte(byte) void writeLong(long) void writeDouble(double) void writeUTF(String)J_Data.java247
  • 248. 接口DataInput, DataOutput接口DataInput中定义的方法主要包括从流中读取基本类型的数据、读取一行数据、或者读取指定长度的字节数。如:readBoolean( )、readInt( )、readLine( )、readUTF( )等。 接口DataOutput中定义的方法主要是向流中写入基本类型的数据、或者写入一定长度的字节数组。如:writeChar( )、writeDouble( )、write( )、writeUTF等。248
  • 249. 7.1.5 缓冲输入/输出流输入/输出(I/O)的缓存机制: 提高输入/输出(I/O)性能的一种方法 输入/输出(I/O)往往很慢,常常是计算机处理事务的瓶颈 一次输入/输出大量数据比分成很多次输入/输出要快很多 将输出数据暂时放在内存中的某个位置(称为缓存) 整个缓存写到指定位置(如硬盘) 类 java.io.BufferedInputStream 和类 java.io.BufferedOutputStream 是带缓存的输入/输出流249
  • 250. 带缓存的数据流构造方法: public BufferedInputStream(InputStream in) public BufferedInputStream(InputStream in, int size) public BufferedOutputStream(OutputStream out) public BufferedOutputStream(OutputStream out, int size) 最佳缓存大小高度依赖于机器平台以及输入/输出的数据大小J_BufferedInputStream.java250
  • 251. 7.2 随机访问文件目的:能够对同一文件交替进行读写,且位置可指定 public class RandomAccessFile extends Object implements DataInput, DataOutput 在生成一个RandomAccessFile对象时,要指明文件对象或文件名,以及访问模式: RandomAccessFile(File file,String mode) RandomAccessFile(String name,String mode)访问模式包括:”r”, “rw”等251
  • 252. 随机访问文件Eg: File f=new File(“readFile.txt”); RandomAccessFile rafR=new RandomAccessFile(f,”r”); RandomAccessFile rafRW=new RandomAccessFile(“readFile.txt”,”rw”); 252
  • 253. 随机访问文件除了通常的读写操作隐式地移动指针外,具有显式移动文件指针的操作 void seek(long pos )//移动文件指针到指定的位置,pos的单位为字节 long getFilePointer( )//得到当前的文件指针 int skipBytes( int n )//使文件指针向前移动指定的n个字节 long length( )//返回当前文件长度253
  • 254. 随机访问文件read read基本数据类型 readBoolean()、readInt()、…… String readLine( ) write write基本数据类型 writeByte()、writeDouble()、……J_RandomAccessFile.java254
  • 255. 7.3 读写器(字符流)字节流字符流InputStreamReaderOutputStreamWriterFileInputStreamFileReaderFileOuputStreamFileWriterBufferedInputStreamBufferedReaderBufferedOutputStreamBufferedWriterPrintStreamPrintWriter255
  • 256. 7.3.1 Reader/Writer均为抽象类,提供了一系列用于字符流处理的接口,不能生成这两个类的实例,只能通过使用由它们派生出来的子类对象来处理字符流。256
  • 257. ReaderReader类是处理所有字符流输入类的父类。 public int read() public int read(char cbuf[]) public abstract int read(char cbuf[], int off, int len) public abstract void close()257
  • 258. WriterWriter类是处理所有字符流输出类的父类。 public void write(int c) public void write(char cbuf[]) public void write(String str) public Writer append(char c) public void flush() public abstract void close()258
  • 259. 7.3.2 FileReader/FileWriterpublic FileReader(String name) public FileWriter(String name) public FileWriter(String name, boolean append)J_FileReaderWriter.java259
  • 260. 7.3.3 带缓存的读写器目的:用于增强读写性能 public BufferedReader(Reader in) public BufferedReader(Reader in, int sz) public BufferedWriter(Writer out) public BufferedWriter(Writer out, int sz) eg: BufferedReader br=new BufferedReader(new FileReader(“1.txt”)); 260
  • 261. 带缓存的读写器读入/写出字符 除了Reader和Writer中提供的基本的读写方法外,增加对整行字符的处理。 public String readLine() throws IOException; public void newLine() throws IOException;261
  • 262. LineNumberReader是BufferedReader的子类,带有行号信息 public LineNumberReader(Reader in) public LineNumberReader(Reader in, int sz) public void setLineNumber(int lineNumber) public int getLineNumber( )J_BufferedReaderWriter.java262
  • 263. PrintWriter是Writer的子类 java.lang.Object java.lang.Object | | +--java.io.Writer +--java.io.OutputStream | | +--java.io.PrintWriter +--java.io.FilterOutputStream | +--java.io.PrintStream 用于处理文本数据而不是字节数据 该类的大部分方法不抛出异常 实现了PrintStream的所有print方法,可直接输出多种类型数据7.3.4 PrintWriter263
  • 264. PrintWriter构造方法: public PrintWriter(Writer out) public PrintWriter(OutputStream out) public PrintWriter(String filename) throws … 其它方法 append() write() //多种重载方法 print() //多种重载方法 println() //多种重载方法 format() printf()J_PrintWriter.java264
  • 265. 7.3.5 InputStreamReader OutputStreamReaderjava.io包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介 生成流对象 public InputStreamReader(InputStream in) public OutputStreamWriter(OutputStream out) 读入和写出字符: 基本同Reader和Writer。 关闭流: public void close() 265
  • 266. 控制台窗口读入数据1.通过类InputStreamReader的构造方法,将字节流转换为字符流 2.通过BufferedReader的构造方法进一步转换为带缓存的读取器 3.通过BufferedReader的readLine读取数据(内容为String) 4.通过包装类的parse系列方法将String转换为所需的类型J_ReadData.java266
  • 267. 补充:Console下的数据读入BufferedReader DataInputStream (obsolete) Scanner (JDK 1.5+)ReadNum.java267
  • 268. 7.4 对象序列化(串行化)对象记录自己的状态以便将来再生的能力,叫作对象的持续性(persistence) 对象通过写出描述自己状态的数值来记录自己,称为对象的序列化(Serialization) 在java.io包中,接口Serializable用来作为实现对象序列化的工具,只有实现了Serializable 的类的对象才可以被串行化。 Serializable接口没有任何方法。当一个类声明要实现Serializable接口时,只是表明该类参加序列化协议,而不需要实现任何方法268
  • 269. 对象序列化ObjectOutputStream用于对象输出 ObjectInputStream用于对象输入 构造方法: public ObjectOutputStream(OutputStream out) public ObjectInputStream(InputStream in) 重要方法: public final void writeObject(Object obj) public final Object readObject(Object obj) 对象序列化例程 7.4269
  • 270. 对象序列化中的两个问题序列化能保存的元素 只能保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量,而且序列化保存的只是变量的值,对于变量的任何修饰符,都不能保存。 transient关键字 对于某些类型的对象,其状态是瞬时的,这样的对象无法保存其状态。对于这些字段,我们必须用transient关键字标明270
  • 271. 对象序列化public class J_SerialData implements Serializable { static final long serialVersionUID = 123456L; int m_id = 111; public void mb_output( ) { System.out.println("序号是: " + m_id); } // 方法mb_output结束 }如果不定义serialVersionUID成员域,则系统会自动生成一个序列号(采用哈希码)271
  • 272. 7.5 文件类 java.io.File Java把目录简单的处理为一种特殊的文件 一个File类的对象表示磁盘上的文件或目录,提供文件与路径的各种有用信息 并不打开文件或处理文件内容 File类提供了与平台无关的方法来对磁盘上的文件或目录进行操作 Example: File f1 = new File ("C:\\Javatest\\test2.txt"); File f2 = new File("C:\\Javatest","test2.txt");272
  • 273. 类File中的方法public boolean exists() public boolean isFile() public boolean isDirectory() public boolean canRead() public boolean canWrite() public boolean canExecute() public boolean isHidden() public boolean isAbsolute() public String getAbsolutePath() public File getAbsoluteFile() public long lastModified()273
  • 274. 类File中的方法public long length() public String getName() public String getPath() public String getParent() public String[] list() public File[] listFiles() public boolean renameTo(File dest) public boolean delete() public boolean mkdir() public boolean mkdirs()274
  • 275. 第 8 章 Swing图形用户界面程序设计基本GUI组件 布局管理器 事件处理模型 菜单、表格、MDI275
  • 276. 早期版本的AWT组件在java.awt包里,包括Button、Checkbox、Scrollbar等,都是Component类的子类 大部分含有native code,所以随操作系统平台的不同会显示出不同的样子,而不能进行更改,是重量级组件(heavyweight components) 没有弹性、缺乏效率276
  • 277. 较新的Swing组件在javax.swing包中,其名称都是在原来AWT组件名称前加上J,例如JButton、JCheckBox、JScrollbar等,都是JComponent类的子类 Java1.2推出,架构在 AWT 之上,是AWT的扩展而不是取代 完全是由java语言编写的,其外观和功能不依赖于任何由宿主平台的窗口系统所提供的代码,是轻量级组件(lightweight components) 可提供更丰富的视觉感受,被越来越多地使用 某些Swing组件也是重量级的,外观和功能受到本地窗口系统的限制277
  • 278. 8.1 组件和容器组件和容器是Swing图形用户界面的组成部分 在Swing图形用户界面程序设计中,要求按照一定的布局方式将组件和容器添加到给定的容器中,形成图形界面 再通过事件处理的方式实现在图形界面上的人机交互278
  • 279. JComponent 组件类的层次结构 java.lang.Object | +--java.awt.Component | +--java.awt.Container | +--javax.swing.JComponent JComponent——大多数Swing组件类父类8.1.1 整体介绍279
  • 280. 通常将javax.swing包里的Swing组件归为三个层次 顶层容器 中间层容器 原子组件 容器本身也是一种组件Swing的组件和容器层次280
  • 281. 顶层容器Swing提供三个顶层容器的类 JFrame 实现单个主窗口 JDialog 实现一个二级窗口(对话框) JApplet 在浏览器窗口中实现一个applet显示区域 必须和操作系统打交道,所以都是重量级组件 从继承结构上来看,它们分别是从原来AWT组件的Frame、Dialog和Applet类继承而来 每个使用Swing组件的Java程序都必须至少有一个顶层容器,别的组件都必须放在这个顶层容器上才能显现出来 281
  • 282. 中间层容器其存在的目的仅仅是为了容纳别的组件 分为两类 一般用途的 JPanel JScrollPane JSplitPane JTabbedPane JToolBar 特殊用途的 JInternalFrame JRootPane282
  • 283. 原子组件通常是在图形用户界面中和用户进行交互的组件 基本功能是和用户交互信息,而不像前两种组件那样是用来容纳别的组件的 根据功能的不同,可被分为三类 显示不可编辑信息的JLabel、JProgressBar、JToolTip 有控制功能、可以用来输入信息的JButton、JCheckBox、JRadioButton、JComboBox、JList、JMenu、JSlider、JSpinner、JTexComponent等 能提供格式化的信息并允许用户选择的JColorChooser、JFileChooser、JTable、JTree283
  • 284. 8.1.2 JFrame和JLabelJFrame是顶层容器 利用JLabel可以在图形用户界面上显示一个字符串或一幅图J_LabelFrame.java284
  • 285. JFrame该窗体有一个基本的结构:窗体北面是一个很窄的矩形区域,称为菜单条区域,用来放置菜单条。菜单条区域下面的区域用来放置窗体的内容面板 JMenuBar ContentPane285
  • 286. 对例程的分析顶层容器框架(JFrame)的构造 public JFrame() public JFrame(String title) 框架属性的设置 public void setDefaultCloseOperation (int operation) public void setSize(int width,int height) public void setVisible(boolean b) 在框架属性设置完毕并添加完所需的组件之后再调用该方法286
  • 287. 对例程的分析为顶层容器添加组件 顶层容器不能直接添加组件,必须获得顶级容器的内容面板contentPane,只有通过它才能加入其它组件 public Container getContentPane() 为contentPane设置布局方式 public void setLayout(LayoutManager l) FlowLayeout(流布局管理器) public FLowLayout(int align)287
  • 288. 对例程的分析向contendPane中加入组件 public Component add(Component comp) 标签的创建 public JLabel(String text) public JLabel(Icon icon) public JLabel(String text, Icon icon, …)288
  • 289. 对例程的分析标签的操作 public void setText() public void setIcon() public void setHorizontalAlignment(…) public void setHorizontalTextPosition(…) public void setVerticalAlignment(…) public void setVerticalTextPositon(…) public void setToolTipText(String text) 289
  • 290. 8.1.3 JDialog和JOptionPane对话框通常用于设计具有依赖关系的窗口 通常在已有窗口基础上创建对话框 父窗口 子窗口 JDialog的构造方法 public JDialog(Dialog owner, String title, boolean modal) public JDialog(Frame owner, String title, boolean modal)290
  • 291. 模式/无模式对话框模式对话框 当模式对话框处于激活状态时,只让程序响应对话框内部的事件,程序不能再激活它所依赖的窗口或组件,而且它将堵塞当前线程的执行,直到该对话框消失不可见 无模式对话框 无模式对话框处于激活状态时,程序仍能激活它所依赖的窗口或组件,它也不堵塞线程的执行J_FrameDialog.java291
  • 292. 对例程的分析JDialog的方法 public void setSize(int width,int height) public void setVisible(boolean b) public Container getContentPane() 组件的添加 调用Container c的如下方法: setLayout(LayoutManager lmr) add(component)292
  • 293. JOptionPane提供一些现成的常用模式对话框 静态成员方法 void showMessageDialog(…) int showConfirmDialog(…) String showInputDialog(…) Object showInputDialog(…)J_DialogMode.java293
  • 294. 8.1.4 JTextField/JPasswordFieldJTextField 专门用来建立文本框,用户可以在文本框输入单行的文本 JPasswordField 可以建立一个密码框对象J_Text.java294
  • 295. 对例程的分析JTextField的创建 public JTextField() public JTextField(String text) public JTextField(int columns) public JTextField(String text,int columns) JPasswordField的创建 public JPasswordField() public JPasswordField(String text) public JPasswordField(int columns) public JPasswordField(String text,int columns)295
  • 296. 对例程的分析可使用的方法 public void setText(String text) public String getText() public void setEditable(boolean b) (以下方法JPasswordField中可用) public void setEchoChar(char c) public char getEchoChar() public char[ ] getPassword() 296
  • 297. 8.1.5 JButton/JCheckBox/JRadioButton均为触击式组件,单击时触发特定的事件 J_Button.java297
  • 298. 按钮类的层次结构javax.swing.JComponentjavax.swing.AbstractButtonjavax.swing.JButtonjavax.swing. JToggleButtonjavax.swing.JCheckBoxjavax.swing.JRadioButton298
  • 299. 8.1.7 面板(JPanel)一种中间容器 可以添加各种组件(包括面板组件) 面板(JPanel)的大小由它所包含的组件决定 当组件个数增加,面板(JPanel)也会随之而增大 作用: 将用户界面的组件进行分组 形成较合理的组件布局方式 用作Swing图形用户界面的画板J_SlideAndPanel.java299
  • 300. 8.2 布局管理器用来控制组件在容器中的布局方式 应当尽量利用已有的基本布局方式 布局管理器处理组件布局的大部分细节 使用布局管理器可以更容易地进行布局,而且当改变窗口大小时,它还会自动更新版面来配合窗口的大小,不需要担心版面会因此混乱300
  • 301. 8.2.1.1 FlowLayout是一种最基本的布局管理器 是JPanel的默认布局方式 在容器中,从左到右依次放置GUI组件 当组件排到容器一行的末尾时,则从下一行开始接着排列组件 每行组件的对齐方式可以是: 左对齐、中间(默认对齐方式)和右对齐301
  • 302. 类FlowLayout 方法构造函数: FlowLayout(); FlowLayout(int align ); FlowLayout(int align, int hgap, int vgap ); 缺省的对齐方式居中对齐 默认的组件横纵间隔都是5个像素 Align :对齐方式 Hgap: 水平间隔 Vgap: 垂直间隔 setAlignment( position_CONSTANT ) FlowLayout.LEFT FlowLayout.CENTER FlowLayout.RIGHT302
  • 303. 8.2.1.2 GridLayout布局管理器GridLayout按行与列将容器等分成网格 每个组件占用具有相同宽度和高度的网格 添加组件占用网格的顺序: 从上到下,从左到右 当一行满了,则继续到下一行,仍然是从左到右J_GridLayout.java303
  • 304. 8.2.2 BorderLayout是容器JFrame和JApplet的默认布局方式 BorderLayout把容器分成5个区域:North,South,East,West和Center,每个区域最多只能放置一个组件。 容器的大小变化时,组件的相对位置不变,大小发生变化。 如果四周没有组件,则由中间的组件来填充;如果中间没有组件,则空着。304
  • 305. BorderLayoutJ_BorderLayout.java305
  • 306. 8.2.3 BoxLayoutBoxLayout将组件放在单一的行或列中 和FlowLayout不同的是,它可以考虑到组件的对齐方式,最大、最小、优选尺寸306
  • 307. 8.2.4 GridBagLayoutGridBagLayout把组件放置在网格中,这一点类似于GridLayout,但它的优点在于不仅能设置组件摆放的位置,还能设置该组件占多少行/列。这是一种非常灵活的布局管理器307
  • 308. 8.2.5 CardLayoutCardLayout的布局方式有点象码“扑克牌” 一个组件放置在另一个组件的上面,所以每次一般只能看到一个组件 它经常由一个复选框控制这个区域显示哪一组组件,可通过组合框像选择卡片一样选择某一种布局308
  • 309. 8.2.6 布局管理器嵌套实际上是容器的嵌套,被嵌套的容器可以具有不同的布局管理器 在嵌套的布局管理器中 JPanel 通常起到了“桥”的作用J_FlowBoxLayout.java309
  • 310. 8.3 事件处理模型GUI是由事件(event)驱动的 当用户与GUI交互可以产生事件(events) 一些常见的交互方式 移动鼠标 用鼠标点击按钮 在文本框中输入数据 关闭窗口等 ……310
  • 311. 事件处理模型Hierarchical model(JDK 1.0) 事件传递机制 Delegation model(JDK 1.1之后) 授权处理机制 事件的处理,由事件的来源(source)对象,委任给一个或多个事件监听者(Event Listener)来处理。 311
  • 312. 事件处理模型两个律师“监听”他的不同行为他“授权”给不同的律师 处理不同的事件刑事事件民事事件处理事件312
  • 313. 事件处理机制主要涉及三种对象 事件源(An event source) 事件对象(An event object) 事件监听器(event listener(s)) 事件监听器A事件监听器B事件对象事件对象事件源 (例如: 按钮)313
  • 314. 事件处理机制事件源 可供用户进行交互的GUI组件 事件对象 封装了包含所发生的各种事件的有效信息 例如按钮被按下就是一个要被处理的事件,当用户按下按钮时,就会产生一个事件对象。事件对象中包含事件的相关信息和事件源。 事件监听器 接受事件对象,并处理事件对象。314
  • 315. 事件处理三者关系组件(事件源)事件处理器外部作用事件监听器注册生成事件对象传入 事件处理器315
  • 316. AWT 事件类型事件类说明事件源ActionEvent 通常按下按钮,双击列表项或选中一个菜单项时,就会生成此事件。 Button、List、MenuItem、TextField AdjustmentEvent 操纵滚动条时会生成此事件。 Scrollbar ComponentEvent 当一个组件移动、隐藏、调整大小或成为可见时会生成此事件。Component ItemEvent 单击复选框或列表项时,或者当一个选择框或一个可选菜单的项被选择或取消时生成此事件。 Checkbox、CheckboxMenuItem、Choice、List FocusEvent 组件获得或失去键盘焦点时会生成此事件。 Component316
  • 317. AWT 事件类型事件类说明事件源KeyEvent 接收到键盘输入时会生成此事件。 Component MouseEvent 拖动、移动、单击、按下或释放鼠标或在鼠标进入或退出一个组件时,会生成此事件。 Component ContainerEvent 将组件添加至容器或从中删除时会生成此事件。Container TextEvent 在文本区或文本域的文本改变时会生成此事件 。TextField、TextArea WindowEvent 当一个窗口激活、关闭、失效、恢复、最小化、打开或退出时会生成此事件。 Window 317
  • 318. 事件体系结构FocusEventAWTEventActionEventAdjustmentEventComponentEventTextEventItemEventContainerEventInputEventWindowEventPaintEventKeyEventMouseEventEventObject318
  • 319. EventObject类java.util.EventObject类 EventObject是所有事件对象的基类,所有的事件类都是由它派生出来的。 public class EventObject implements Serializable { protected transient Object source; public EventObject(Object source); public Object getSource(); public String toString(); }319
  • 320. 事件处理的一般方法对于某种类型的事件XXXEvent,要想接收并处理这类事件,必须定义相应的事件监听器类,该类需要实现针对特定事件的特定接口XXXListener; 如果事件源在产生事件后需要进行处理,必须注册相应于该类事件的监听器,使用addXXXListener(XXXListener)方法来注册监听器。320
  • 321. ActionEventActionEvent是最常用到的事件 对应的接口ActionListener 该接口中的方法只有一个:actionPerformed(ActionEvent e) J_Button1.javaJ_Button2.java321
  • 322. MouseEventMouseEvent对应的接口MouseListener public interface MouseListener extends EventListener { 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) ; }322
  • 323. MouseMotionEventMouseEvent对应的接口MouseMotionListener public interface MouseMotionListener extends EventListener { public void mouseDragged(MouseEvent e); public void mouseMoved(MouseEvent e); }J_Draw.java+J_Panel.java323
  • 324. 事件适配器适配器(adapter)是实现XXXListener接口的抽象类。 通过adapter类来实现监听可以缩短程序代码,直接通过继承/内部类来实现处理方法。 但当需要多种监听器或该类已经有父类的时候,就不能通过适配器来实现事件监听。324
  • 325. 事件适配器java.awt.event包中定义的事件适配器类:ComponentAdapterContainerAdapterFocusAdapterMouseAdapterWindowAdapterKeyAdapterMouseMotionAdapterContainerListenerFocusListenerMouseListenerWindowListenerKeyListenerMouseMotionListenerComponentListener事件适配器类事件监听器接口325
  • 326. 鼠标适配器MouseAdapter鼠标事件适配器类 public abstract class MouseAdapter implements MouseListener { 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) {} } JDK1.6之后的定义有变化326
  • 327. KeyEventKeyEvent相对应的接口KeyListener : public interface KeyListener extends EventListener { public void keyPressed(KeyEvent e); public void keyReleased(KeyEvent e); public void keyTyped(KeyEvent e); } 327
  • 328. FocusEventFocusEvent相对应的接口FocusListener : public interface FocusListener extends EventListener { public void focusGained(FocusEvent e); public void focusLost(FocusEvent e); }J_KeyBoard.java328
  • 329. 监听接口的实现方式总结1.定义专门的外部类实现监听接口 OuterCounter.java 2.用内部类实现监听接口 ButtonCounter.java,ButtonCounter2.java 3.将容器类自身实现监听接口 FrameCounter.java 4.采用事件适配器 AdapterCounter.java 5.一个组件注册多个监听者 ManyEars.java329
  • 330. 第 11 章 多线程程序设计编写线程程序 线程的生命周期 多线程的同步处理 多线程的同步问题330
  • 331. Java多线程一个线程是一个程序内部的顺序控制流。 Java从语言级上支持多线程,其所有类都是在多线程的思想下定义的。331
  • 332. 线程和进程每个进程都有独立的代码和数据空间(进程上下文),进程切换的开销大。 线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。 多进程:在操作系统中,能同时运行多个任务(程序)。 多线程:在同一应用程序中,有多个顺序流同时执行。332
  • 333. 线程的概念模型虚拟的CPU,封装在java.lang.Thread类中 CPU所执行的代码,传递给Thread类。 CPU所处理的数据,传递给Thread类。333
  • 334. 线程体Java的线程是通过java.lang.Thread类来实现的。 一个Thread类的对象代表了一个Java解释器中真正的线程。 每个线程都是通过某个特定对象的方法run( )来完成其操作的,方法run( )称为线程体。注意:并未强调是Thread对象334
  • 335. 11.1 编写线程程序构造线程体的2种方法 定义一个线程类,它继承类Thread,并重写其中的方法run( ) 提供一个接口Runnable的实现类作为线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体run( )335
  • 336. 11.1.1 通过类Thread的子类构造线程类Thread的每个实例对象就是Java程序的一个线程 线程程序所执行的代码 public void run( ) 启动线程 public void start( ) 注意: 线程的运行不是直接调用方法run()J_Thread.java336
  • 337. 11.1.2 通过接口Runnable构造线程分析:第一种方法的局限性 引入Runnable接口 重写该接口中的run()方法 public class A extends B implements Runnable { // ... public void run( ) { // ... } }337
  • 338. 通过接口Runnable构造线程若类A为实现接口Runnable的类,构造和启动线程的方法: A a = new A( ); Thread t = new Thread(a); t.start( ); J_ThreadRunnable.java338
  • 339. 两种方法的比较直接继承Thread类 不能再从其他类继承; 编写简单,可以直接操纵线程 使用Runnable接口 可以将CPU,代码和数据分开,形成清晰的模型; 可以从其他类继承; 保持程序风格的一致性。339
  • 340. 11.2 线程的生命周期340
  • 341. 线程的优先级线程的优先级用数字来表示,范围从1到10,即Thread.MIN_PRIORITY到Thread.MAX_PRIORITY。一个线程的缺省优先级是5,即Thread.NORM_PRIORITY。 int getPriority(); void setPriority(int newPriority); 341
  • 342. 线程的优先级线程调度的具体方式与系统有关 并不是在所有系统中运行Java程序时都采用时间片策略调度线程,所以一个线程在空闲时应该主动放弃CPU,以使其他同优先级和低优先级的线程得到执行。 不同系统中对优先级的分级不同,所以尽量采用Java中提供的常量来定义优先级。342
  • 343. 11.3 多线程的同步处理临界资源问题 class stack{ int idx=0; char[ ] data = new char[6]; public void push(char c){ data[idx] = c; idx++; }public char pop(){ idx--; return data[idx]; } }343
  • 344. 多线程的同步处理在Java 语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。 关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。344
  • 345. 多线程的同步处理 public void push(char c){ synchronized(this){ data[idx]=c; idx++; } } public char pop(){ synchronized(this){ idx--; return data[idx]; } }345
  • 346. 多线程的同步处理synchronized除了放在对象前面限制一段代码的执行外,还可以放在方法声明中,表示整个方法为同步方法。 public synchronized void push(char c){ … } 如果synchronized用在类声明中,则表明该类中的所有方法都是synchronized的。346
  • 347. 多线程的同步处理在已经持有锁的情况下(只能出现在syschronized范围内): wait:释放已持有的锁,进入wait队列 notify:唤醒wait队列中第一个线程,并将其移入锁申请队列。 notifyAll:唤醒wait队列中所有线程,并将其移入锁申请队列。 347
  • 348. The End348