• 1. 第一章 Java语言概述华中科技大学IBM技术中心 2008
  • 2. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 3. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 4. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 5. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 6. Java程序相关问题——Java虚拟机Java虚拟机——在真实机器中用软件模拟实现的一种抽象的机器。(Java虚拟机规范) Java虚拟机主要由五个部分组成:指令系统、寄存器、栈、存储区、碎片回收区 解释和执行Java程序编译后产生的字节码
  • 7. Java程序相关问题——Java APIJava API是Java系统提供的预先定义好的软件组件的集合,它们提供了许多可供程序员调用的常用功能 丰富的API为程序员提供了极大的方便,但也是学习的难点 要学会使用Java API手册(The Java 2 Platform API Specification ) http://java.sun.com/j2se/1.5/docs/api/index.html
  • 8. Java程序相关问题—— Java程序的运行机制操作系统源代码可执行代码目标码编译连接运行源代码字节码编译解释执行Java解释器传统语言的运行机制Java语言的运行机制
  • 9. Java程序相关问题——Java程序类型 Java应用程序(Java Application) 是独立完整的程序 在命令行调用独立的解释器软件即可运行 主类必须有main方法,这也是程序的入口 Java小程序 Java Applet——是指在客户端运行的Java小程序,一般来说客户端是指用户所使用的浏览器 Java Servlet——是在服务器端执行的Java小程序,为了能够支持Servlet的运行,服务器端必须安装包含Java虚拟机的服务器软件,这种能够支持服务端小程序的服务器一般被称为应用服务器
  • 10. Java开发环境JDK/J2SDK(Java Developer Kit) JDK1.02 JDK1.1.x JDK1.2/J2SDK1.3/J2SDK1.4/JDK5.0(J2SDK1.5) Java集成开发环境(IDE) NetBeans JBuilder Eclipse JCreator Forte for Java Visual J++ WSAD ……
  • 11. JDK的安装与设置从http://java.sun.com/可以下载相关版 本的JDK(本课程采用J2SDK1.3以上版本) 在Windows平台上运行安装程序,以安装JDK 设置PATH(文件路径)参数。由于JDK提供的实用程序都在安装目录下的子目录bin下,为了能在任何目录下直接使用文件名调用这些程序,必须设置操作系统的文件路径参数
  • 12. 环境设置在Windows环境下,为了快速进入指定目录的命令行窗口,可在注册表中增加项目: [HKEY_CLASSES_ROOT\Directory\shell\进入命令行\command] 默认值设为: cmd /k "cd %1"
  • 13. JDK的目录结构bin目录中包含了所有JDK5.0提供的实用程序 demo目录中包含了JDK5.0自带的实例程序 inculde目录中包含了一些支持Java native方法的C\C++头文件 jre目录中包含了Java运行环境所需的所有文件,这个目录中所包含的java运行环境是JDK私有的,它只为JDK的实用程序提供支持 lib目录中包含了Java开发环境所需的库文件,它们以jar文件的形式保存 sample目录中包含的是体现JDK5.0新特性的一些例程
  • 14. JDK实用程序简介javac:Java编译器,将Java源代码编译为字节码; java:Java解释器,用来解释执行Java程序的字节码文件; appletviewer(小程序浏览器):一种执行HTML文件上的Java小程序类的Java浏览器; javadoc:根据Java源代码及其说明语句生成的HTML文档; jdb:Java调试器,可以逐行地执行程序、设置断点和检查变量; javah:产生可以调用Java过程的C过程,或建立能被Java程序调用的C过程的头文件; javap:Java反汇编器,显示编译类文件中的可访问功能和数据,同时显示字节代码含义。
  • 15. Java程序的开发过程 编辑源代码 编译源代码文件 运行程序
  • 16. Java程序的开发过程——编辑源代码一般情况下,我们可以使用系统平台下的任何文本编辑器进行源代码的编辑,在Windows平台下常用的是Window系统自带的“记事本”程序或“写字板”程序 Java源码大小写敏感 Java源码文件的扩展名:.java Java源程序文件也不能随意命名,其文件名必须与程序中主类的类名完全相同,包括大小写在内 public class MyFirstJavaApp { public static void main(String[] args) { System.out.println(“This is My First Java Application!”); } }
  • 17. Java程序的开发过程——编译源代码使用JDK实用程序javac对源代码文件进行编译 C:\MyJava>javac MyFirstJavaApp.java 如果系统提示符再次出现并且没有任何消息产生,那么编译便成功了 如果有系统报错消息产生,则表示程序编译出错,程序员必须阅读报错信息,并根据这些信息对程序进行修改 程序成功编译后,在与源代码文件同一目录下会生成一个新的文件,其文件名与源代码文件名相同,扩展名为“.class”。这个文件就是源代码文件编译产生的程序字节码文件 MyFirstJava.class
  • 18. Java程序的开发过程——运行程序 要执行一个Java程序非常简单,只需在字节码文件所在目录下输入下列命令就可以了: java 字节码文件名
  • 19. Question?
  • 20. 第2章 面向对象的编程概念华中科技大学IBM技术中心 2006
  • 21. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 22. 面向对象 vs. 面向过程面向对象(OOP)——Object-Oriented Programming 用类class封装数据以及与数据相关的操作 用类的继承性来实现类的重用性 多态性 面向“对象”,由对象提供服务 面向过程(POP)——Procedure-Oriented Programming 以功能为组织单元 通过数据结构来描述具体的问题 数据在功能(函数)之间以参数的形式被传送
  • 23. 现实世界中的对象现实世界是由对象构成的 现实世界中任何实体都可以看作是对象 现实世界中的对象有两个共同特征: 状态 行为
  • 24. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 25. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 26. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 27. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 28. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 29. 消息的性质同一对象可接收不同形式的多个消息,产生不同的响应 同一个消息可以发给不同的对象,所做出的响应可以截然不同 发送方不需要知道接受方如何对请求予以响应的
  • 30. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 31. 实例(Instance)定义:特定类所描述的一个具体对象
  • 32. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 33. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 34. 单重继承与多重继承单重继承:一个子类只有一个唯一确定的父类 单重继承所构成的类的关系结构是一棵树 多重继承:一个子类可以有多个不同的父类 多重继承所构成的类的关系结构是一个格 Java语言仅支持单重继承
  • 35. 继承的作用使软件系统具有开放性 更好地进行抽象与分类 实现代码的复用 提高可维护性
  • 36. 类型(Type)在面向数值的编程中,类型通常用作数据的表示。在Java这样的强类型语言中,在编译期,每一个变量和表达式都有一个类型与之相对应 Java中的类型:基本类型、类、接口
  • 37. 接口(Interface)接口和类一样也是一种类型,也同样包含一些方法的定义。但与类不同的是:接口中所定义的所有方法都是抽象方法(即没有实现的方法)。 接口中所定义的方法由实现(implement)该接口的类来实现,一个类可以同时实现多个接口 接口机制使Java的面向对象编程变得更加灵活。解决了单重继承带来的问题 接口定义了对象的行为模型,相当于一个协议。实现接口的各个类负责实现接口所定义的行为。虽然实现细节各不相同,但对用户来说是一样的行为。
  • 38. 面向对象的示例本例中包含很多对象:点、窗口、颜色、点击事件…… 代码:ClickMeApp.java , ClickMe.java,Spot.java
  • 39. Spot类public class Spot { //instance variables private int size; public int x, y; //constructor public Spot() { x = -1; y = -1; size = 1; } //methods for access to the size instance variable public void setSize(int newSize) { if (newSize >= 0) { size = newSize; } } public int getSize() { return size; } }
  • 40. Spot对象private Spot spot = null; ... spot = new Spot();
  • 41. 示例中的消息g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, getWidth() - 1, getHeight() - 1);
  • 42. 示例中的继承和接口public class ClickMe extends JComponent implements MouseListener { ... } public class ClickMe extends JComponent implements MouseListener { ... //Methods required by the MouseListener interface. public void mousePressed(MouseEvent event) { if (spot == null) { spot = new Spot(); spot.setSize(RADIUS); } spot.x = event.getX(); spot.y = event.getY(); repaint(); } public void mouseClicked(MouseEvent event) {} public void mouseReleased(MouseEvent event) {} public void mouseEntered(MouseEvent event) {} public void mouseExited(MouseEvent event) {} } }
  • 43. 欢迎提问Question !
  • 44. 第三章 Java语言基础华中科技大学IBM技术中心
  • 45. 变量(Variable) 对象将它的状态存储在变量中 定义:  变量是一个由标识符命名的数据项 变量名必须是一个合法的标识符 --一个以字母开头的无限制的Unicode字符序列。 变量的声明: 类型 名称[ = 初始值]; int i; double pi = 3.1415926; String name;
  • 46. 数据类型 每个变量都必须有一个数据类型. 一个变量的数据类型决定了它能容纳的值和在它上面可以进行什么操作。 Java编程语言有两大类数据类型: 原始类型(primitive) 引用类(reference)
  • 47. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 48. 原始类型变量包含单个值,其大小和格式与它的类型匹配:数字、字符或布尔值。 Java语言没有unsigned类型 0xFFFF和0xFF谁大? Java语言必须强制类型转换 float f = 0.1; boolean b = 1; 原始类型
  • 49. 引用类型数组,类和接口就是引用数据类型.与原始类型变量的值不同的是,引用类型变量的值是对应变量代表的一个值或一组值的引用(也就是其地址) 在其他语言里引用被称为指针或者内存地址。Java不支持显示地使用地址,而是使用变量的名称代替。
  • 50. 变量的引用 通过变量名引用变量的值 简单名称:由单个标识符组成的名称 限定名称:通过类名或对象名引用改类或对象中的成员变量 System.out.println(i+spot.x);
  • 51. 作用范围 变量的作用范围是可以通过简单名称引用该变量的程序区域 作用范围也决定了系统为该变量创建和释放内存的时间
  • 52. 例子int i = 10; if ( i> 0) { int i = 20; System.out.println(“The value of i = ” + i); } System.out.println(“The value of i = ” + i);
  • 53. 最终变量 你可以在任意范围里将一个变量定义为最终变量(final) 最终变量的值一经初始化就不能改变 类似于C语言中的常量(const)final int aFinalVar = 0; final int blankfinal; . . . blankfinal = 0;
  • 54. 操作符、表达式、语句和块自学!
  • 55. 第四章 对象基础和简单数据对象华中科技大学IBM技术中心
  • 56. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 57. 对象的生命周期
  • 58. CreateObjectDeompublic class CreateObjectDemo { public static void main(String[] args) { //创建一个Point对象和两个Rectangle对象 Point origin_one = new Point(23, 94); Rectangle rect_one = new Rectangle(origin_one, 100, 200); Rectangle rect_two = new Rectangle(50, 100); // 显示rect_one的宽、高以及面积 System.out.println("Width of rect_one: " + rect_one.width); System.out.println("Height of rect_one: " + rect_one.height); System.out.println("Area of rect_one: " + rect_one.area()); rect_two.origin = origin_one; //设置rect_two的位置 // 显示rect_two的位置 System.out.println("X Position of rect_two: " + rect_two.origin.x); System.out.println("Y Position of rect_two: " + rect_two.origin.y); // 移动rect_two并且显示它的新位置 rect_two.move(40, 72); System.out.println("X Position of rect_two: " + rect_two.origin.x); System.out.println("Y Position of rect_two: " + rect_two.origin.y); } }
  • 59. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 60. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 61. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 62. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 63. 对象创建的实例public class Point { public int x = 0; public int y = 0; public Point(int x, int y){ this.x = x; this.y = y; } } Point origin_one = new Point(23, 94);
  • 64. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 65. 构造器的重载(Overload)public class Rectangle { public int width = 0; public int height = 0; public Point origin; public Rectangle() { origin = new Point(0, 0); } public Rectangle(Point p) { origin = p; } public Rectangle(int w, int h) { this(new Point(0, 0), w, h); } public Rectangle(Point p, int w, int h) { origin = p; width = w; height = h; } ……. }一个类可以包含多个构造器,这种情况成为构造器的重载 同一个类中的多个构造器通过参数的数目及类型的不同来区分
  • 66. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 67. 实例成员与类成员实例成员包括实例变量与实例方法 实例成员依赖于实例存在 同一个类的不同实例都拥有一份实例变量的拷贝,对某个实例的实例变量的操作不影响到其它实例 实例变量遵循对象的生命周期,随着对象的创建而创建,随着对象的消亡而消亡 必须通过实例的引用来调用实例方法 类成员包括类变量与类方法 类成员不依赖于实例存在 同一个类的不同实例共享同一个类变量,对类变量的改变会影响到所有实例 类变量的生存期不依赖于对象,其它类可以不用通过创建该类的实例,直接通过类名访问它们。同样,类方法也可以直接通过类名访问。
  • 68. 实例成员与类成员class ABCD { char data; static int share_data; } class Demo { ABCD a,b,c,d; … //实例化 }
  • 69. 实例变量的引用简单名称 当实例变量处在作用域内(即对象的类的代码内) 的时候 限定名称 objectReference.variableName 当实例变量处在作用域外时使用限定名称 System.out.println("Width of rect_one: " + rect_one.width); System.out.println("Height of rect_one: " + rect_one.height); int height=new Rectangle().height;
  • 70. 关于变量访问的说明建议不要通过其它对象或类直接操作对象的变量,可能引起无效值 理想情况下,类会提供一些方法,其他对象可以通过他们检查或修改变量,确保值有效,而且如果变量的类型和名称发生了变化,不会影响它的使用者 在某些情况下,可以允许对对象变量的直接访问,以使类更小更简单,也可使变量适用于更广泛范围; JAVA编程语言提供了一个访问控制机制,通过这种机制,类可以决定那些其它的类可以直接访问它的变量(第五章中介绍)。
  • 71. 调用对象的方法使用限定名称来调用对象的方法 objectReference.methodName(argumentList); 或者 objectReference.methodName();   System.out.println("Area of rect_one: " + rect_one.area()); rect_two.move(40, 72); int areaOfRectangle = new Rectangle(100, 50).area();
  • 72. 关于方法调用方法被声明为public,就可以被任何其它的类所访问。有时,类需要限制对它的方法的访问 类可以使用与控制变量访问相同的机制来对它的方法进行访问控制(第五章中介绍)
  • 73. 对象的清除JAVA运行时环境在当对象不再被使用的时候清除它们,这个过程就是所谓的“垃圾收集”(garbage collection) Java的垃圾收集器自动扫描对象的动态内存区,对被引用的对象加标记,然后把没有引用的对象作为垃圾收集起来并释放。 垃圾收集器作为一个线程运行。当系统的内存用尽或程序中调用System.gc()要求进行垃圾收集时,垃圾收集线程与系统同步运行。否则垃圾收集器在系统空闲时异步地执行。
  • 74. 无用对象的判定当某个对象不在被任何引用变量引用时,该对象是无用对象,将被清除。一般有如下两种情况:引用变量超出了作用域 { StringBuffer s = newStringBuffer(“thisisatest”); …… } // 超出对象作用域 ……引用变量引用了其它对象或引用了空对象 StringBuffer s = new StringBuffer(“test1”); …… s = new StringBuffer(“test2”); // 引用了新的对象 …… s = null; // 引用为空
  • 75. finalize()方法在对对象进行垃圾收集前,Java运行时系统会自动调用对象的finalize()方法来释放系统资源。 某些情况下,程序员可能需要实现该方法来释放不由垃圾收集器所控制的资源。但这种情况非常少见 finalize()方法是在Object中有缺省实现,在用户自定义的类中,它可以被覆盖,但一般在最后要调用父类的finalize()方法来清除对象所使用的所有资源
  • 76. 问题一下列程序的运行结果?public class SomethingIsWrong { public static void main(String[] args) { Rectangle myRect; myRect.width = 40; myRect.height = 50; System.out.println("myRect's area is " + myRect.area()); } }
  • 77. 问题二现有一个Point和Rectangle对象,代码执行后有多少引用指向它们?有没有对象需要垃圾收集?Point point = new Point(2,4); Rectangle rectangle = new Rectangle(point, 20, 20); point = null;
  • 78. 字符和字符串Java API提供了三个处理字符数据的类: Character:这个类的实例可以容纳单一的字符数值。该类还定义了一些简洁的方法来操作或者检查单一字符数据。 String:这个类用于处理由多个字符组成的不可变数据。 StringBuffer:这个类用于存储和操作由多个字符组成的可变数据。
  • 79. 字符类(Character)字符类的对象包含单个字符值 当需要使用对象时,可以用字符对象替代原始的char类型的变量
  • 80. 字符类——构造器和方法Character(char)-Character类唯一的构造器,它创建一个字符对象,其中包含由参数提供的值,一旦创建了Character对象,它包含的值就不能改变。 compareTo(Character)-这个实例方法比较两个字符对象包含的值,这个方法返回一个整数值,表示当前对象中的值是大于、等于还是小于参数所包含的值
  • 81. 字符类——构造器和方法equals(Object)-这个实例方法比较当前对象包含的值与参数对象包含的值,如果两个对象包含的值相等,那么这个方法返回true toString()-这个实例方法将此对象转换为字符串 charValue()-这个实例方法以原始char值的形式返回此字符对象包含的值 isUpperCase()-这个实例方法判断一个原始char值是否是大写字母
  • 82. 字符类——例程public class CharacterDemo { public static void main(String args[]) { Character a = new Character('a'); Character a2 = new Character('a'); Character b = new Character('b'); int difference = a.compareTo(b); if (difference == 0) { System.out.println("a is equal to b."); } else if (difference < 0) { System.out.println("a is less than b."); } else if (difference > 0) { System.out.println("a is greater than b."); } System.out.println("a is "+ ((a.equals(a2)) ? "equal" : "not equal")+ " to a2."); System.out.println("The character " + a.toString() + " is " + (Character.isUpperCase(a.charValue()) ? "upper" : "lower")+ "case."); } }程序的输出: a is less than b. a is equal to a2. The character a is lowercase.
  • 83. 字符类——类方法
  • 84. 问题Character a = new Character('a'); Character b = new Character('a');下列boolean表达式的值是true还是false? (1)a.compareTo(b)==0 (2)a.equals(b) (3)a==b
  • 85. 字符串和字符串缓冲区Java平台提供两个类String和StringBuffer,它们用于存储和操作字符串-由多个字符组成的字符数据。 String类用于其值不能改变的字符串; StringBuffer类用于被修改的字符串,通常用来动态的构造字符数据。 字符串是常量,比字符串缓冲区更高效,而且字符串可以被共享。
  • 86. 字符串(String)使用字符串常量时,需要创建String对象,和其它对象不同,String对象可以通过简单赋值语句创建: String name = “Petter”; 此外,也可根据String类的构造函数创建String对象: String name = new String(“Petter”); 对于程序任何位置出现的双引号标记的字符串,系统都会自动创建一个String对象。 可通过String对象的方法对字符串进行操作
  • 87. 字符串——构造器
  • 88. 字符串的不可变性?String类用于其值不能改变的字符串 观察下列程序:public class StringTest{ public static void main(String[] args){ String s="abc"; s=s+“defg"; System.out.println(s); } }程序运行结果是abc还是abcdefg?
  • 89. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 90. 字符串缓冲区(StringBuffer)String对象表示的是不可更改的字符串对象,如果需要修改String对象所表示的内容,必须重新创建一个对象: String str = “Petter”; str = str + “ & Bob” + “ & Tom”; 当修改操作频繁,或字符串的值很大时,会额外分配大量内存 因此,Java语言引入了一个StringBuffer类,用来表示内容可以扩充和修改字符串对象
  • 91. StringBuffer——构造器必须使用new操作符创建字符串缓冲区String s = "Dot saw I was Tod"; StringBuffer dest = new StringBuffer(s);
  • 92. 访问器方法用于获取关于对象的信息的方法被称为访问器方法。 字符串和字符串缓冲区都可以使用的一个访问器方法就是length方法。 length方法返回字符串和字符串缓冲区中包含的字符数。String palindrome = "Dot saw I was Tod"; int len = palindrome.length();
  • 93. 容量在StringBuffer类中还有一个capacity()方法,它返回分配给这个字符串缓冲区的容量,而不是使用量。使用量会改变,但是容量始终是不变的。
  • 94. 通过索引得到字符charAt()访问器方法,通过索引从字符串或者字符串缓冲区得到字符,索引值从零开始。 String anotherPalindrome = "Niagara. O roar again!"; char aChar = anotherPalindrome.charAt(9);
  • 95. substring方法如果要从字符串或者字符串缓冲区得到多个字符,可以使用substring方法。 String substring(int) String substring(int,int) String anotherPalindrome = "Niagara. O roar again!"; String roar = anotherPalindrome.substring(11, 15);
  • 96. searchstring类提供两个访问器方法,返回特定的字符或者子字符串在字符串中的位置。 indexOf()方法从字符串的开头查找; lastindexOf()方法从字符串的末尾查找; stringBuffer类不支持indexOf()和lastindexOf()方法。
  • 97. search
  • 98. search examplepublic class Filename { private String fullPath; private char pathSeparator, extensionSeparator; public Filename(String str, char sep, char ext) { fullPath = str; pathSeparator = sep; extensionSeparator = ext; } public String extension() { int dot = fullPath.lastIndexOf(extensionSeparator); return fullPath.substring(dot + 1); } public String filename() { int dot = fullPath.lastIndexOf(extensionSeparator); int sep = fullPath.lastIndexOf(pathSeparator); return fullPath.substring(sep + 1, dot); } public String path() { int sep = fullPath.lastIndexOf(pathSeparator); return fullPath.substring(0, sep); } }
  • 99. search examplepublic class FilenameDemo { public static void main(String[] args) { Filename myHomePage = new Filename("/home/mem/index.html",'/', '.'); System.out.println("Extension = " + myHomePage.extension()); System.out.println("Filename = " + myHomePage.filename()); System.out.println("Path = " + myHomePage.path()); } }程序输出: Extension = html Filename = index Path = /home/mem
  • 100. 比较字符串和字符串缓冲区
  • 101. 操作字符串
  • 102. 修改字符串缓冲区
  • 103. 数字类Number类及其子类主要用于处理数字 Number类的对象包含了原始类型的数值并且提供了一些有用的变量和方法,用于对数值进行处理
  • 104. 类型包装器类(Type-Wrapper class)数字类、Boolean、Character和void类统称为类型包装器类 在需要对象的地方,可将原始类型的值存储在类型包装器对象中 这些类定义了一些有用的变量,提供关于数据类型的一般信息 这些类还定义了一些有用的方法,用于将值转换为其他类型、转换为字符串等等 这些类用于反射,反射这种java机制允许程序收集关于JVM中任何对象或类的信息 此外,BigInteger和BigDecimal还扩展了原始数据类型
  • 105. 例程public class NumberDemo { public static void main(String args[]) { Float floatOne = new Float(14.78f - 13.78f); Float floatTwo = Float.valueOf("1.0"); Double doubleOne = new Double(1.0); int difference = floatOne.compareTo(floatTwo); if (difference == 0) { System.out.println("floatOne is equal to floatTwo."); } else if (difference < 0) { System.out.println("floatOne is less than floatTwo."); } else if (difference > 0) { System.out.println("floatOne is greater than floatTwo."); } System.out.println("floatOne is “ +((floatOne.equals(doubleOne)) ? "equal" : "not equal") + " to doubleOne."); } } floatOne is equal to oneAgain. floatOne is not equal to doubleOne.
  • 106. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 107. 数组数组是一个固定长度的结构,它存储多个相同类型的值 数组直接被JAVA语言所支持,所以没有一个数组类 数组的长度在数组创建的时候就已经确定。 数组元素就是数组中的一个数值,可以通过数组中的位置来访问它。
  • 108. 创建数组声明一个引用变量来引用一个数组 格式:type[] 引用变量名 type 引用变量名[] (允许但不推荐) 数组变量的声明并不创建数组 创建一个数组 使用new操作符显示地创建数组 格式:new elementType[arraySize] 数组初始化器 可以使用简写的语法创建并初始化数组: type[] 引用变量名 = { 数组元素值…};
  • 109. 使用数组访问数组元素 引用变量名(数组名)[index] 得到数组大小 引用变量名(数组名).length
  • 110. 例程public class ArrayDemo { public static void main(String[] args) { int[] anArray; anArray = new int[10]; for (int i = 0; i < anArray.length; i++) { anArray[i] = i; System.out.print(anArray[i] + " "); } System.out.println(); } }
  • 111. 对象数组数组元素可以是基本类型也可以是引用类型 当数组元素是引用类型时(也即数组元素为对象时需要注意:数组元素也必须要被创建和初始化Integer[] anArray = new Integer[5]; for (int i = 0; i < anArray.length; i++){ System.out.println(anArray[i]); }
  • 112. 数组的数组数组的数组可以看作是“数组引用”的数组 与对象数组一样,必须显示地在数组中创建子数组 子数组的长度并不相同 例:int[ ][ ] aMatrix = new int[4][ ]; …… aMatrix[1] = new int[5]; aMatrix[2] = new int[10];
  • 113. 复制数组public static void arraycopy(Object source, int srcIndex, Object dest, int destIndex, int length)
  • 114. 例程public class ArrayCopyDemo { public static void main(String[] args) { char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' }; char[] copyTo = new char[7]; System.arraycopy(copyFrom, 2, copyTo, 0, 7); System.out.println(new String(copyTo)); } }
  • 115. 问题public class WhatHappens { public static void main(String[] args) { StringBuffer[] stringBuffers = new StringBuffer[10]; for (int i = 0; i < stringBuffers.length; i ++){ stringBuffers[i].append("StringBuffer at index " + i); } } }
  • 116. 欢迎提问Question !
  • 117. 第六章 接口和包华中科技大学IBM技术中心
  • 118. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 119. Java接口的引入Java语言只支持单重继承,它的程序中的类的层次结构是树状结构,在处理复杂问题时单重继承显得力不从心。 为了使Java程序的类层次结构更加合理,更符合实际问题的需要,我们把用于完成特定功能的若干属性组织成相对独立的属性集合,这种属性的集合就是接口。
  • 120. Java接口定义定义:接口是一个有名称的方法定义和常量定义的集合,但没有方法的实现。 接口定义了一个行为协议,类层次结构中任何地方的任何类都可以实现. 接口是由常量和抽象方法组成的特殊类: 接口中的属性都是用final修饰的常量 接口中的方法都是用abstract修饰的没有方法体的抽象方法。
  • 121. Java语言的接口接口功能的真正实现是由实现接口的各个类来定义接口中各个抽象方法的具体方法体。 Java语言通过接口实现了类间的多重继承功能。
  • 122. Java接口实现多重继承单一继承指明了子类和父类的层次关系和各自 的行为。 多重继承是指一个类有多个父类,这使得类的 层次关系不清楚。 接口则把方法的定义同类的层次区分开来,通 过接口可以在运行中动态地定位所调用的方 法,同时一个类可以实现多个接口,使得接口 提供了比多重继承更简单、更灵活的功能。
  • 123. 接口 vs 抽象类接口不可以实现任何方法,而抽象类可以; 类可以实现多个接口,但父类仅只有一个; 接口和继承无关,不是类层次结构的一部分。无关的类可以实现相同接口。
  • 124. 定义接口
  • 125. 完整的接口定义规范
  • 126. 接口定义接口包括接口声明和接口体两部分: [public] interface 接口名 [extends 父接口名列表] { [public][static][final] 类型 变量名 = 常量值; [public][abstract][native] 返回值类型 方法名(参数列表) [throws 异常列表]; }public interface MyInterface { int MAXSIZE = 1024; public abstract myMethod(String name); }
  • 127. 接口定义的说明声明接口的关键字interface引导着所定义的接口名字(符合Java标识符规定); 声明接口也需要给出访问控制符; 接口具有继承性,通过关键字extends声明该新接口是某父接口的派生接口;一个接口可以有多个父接口,它们之间用逗号分隔,形成父接口列表。
  • 128. 接口体的说明接口体的定义有两个部分: 对接口中属性的声明 对接口中方法的声明; 系统默认:接口中的所有属性都是public, static和final (公共,静态和最终); 系统默认:接口中的所有方法都是public和 abstract (公共和抽象); 接口中方法的方法体可用Java语言书写,也可用其它语言书写(加native修饰)。
  • 129. 实例定义一个股票监视器。一旦股票价格变化,立即通知观察者watcher。 Watcher是一个接口,它只有一个方法,valueChanged知道股票变化的类必须实现此方法。从而必须实现StockWatcher接口 不仅仅是StockMointer的超类,其它类只要实现此接口,就可以享受股票价格变化通知服务。public class StockMonitor { public void watchStock(StockWatcher watcher, String tickerSymbol, double delta) { } }
  • 130. 实现接口具体地实现接口所规定的功能, 需要某个类为接口中的所有抽象方法编写实在的方法体。 在类的声明(定义)中用implements关键字说明该类将要实现哪些接口; 如果实现某个接口的类不是abstract的抽象类,则在类的定义部分必须为所有抽象方法定义具体方法体,方法头部分应该与接口中的定义完全一致;
  • 131. 实现接口如果实现某接口的类是abstract的抽象类,则在类的定义部分可以不具体实现接口中的所有方法; 一个类在实现某个接口的抽象方法时,必须使用完全相同的方法声明。 接口的抽象方法访问修饰符为public,所以,类在实现方法时必须使用修饰符public,否则,系统将警告;因为缩小了接口中定义的方法的访问控制范围。
  • 132. 实例public class StockApplet extends Applet implements StockWatcher { ... public void valueChanged(String tickerSymbol, double newValue) { if (tickerSymbol.equals(sunTicker)) { ... } else if (tickerSymbol.equals(oracleTicker)) { ... } else if (tickerSymbol.equals(ciscoTicker)) { ... }}}
  • 133. 接口功能不能简单扩大例如:要加个报股价的方法在接口里,此时所有实现它的类不能正常工作。public interface StockWatcher { final String sunTicker = "SUNW"; final String oracleTicker = "ORCL"; final String ciscoTicker = "CSCO"; void valueChanged(String tickerSymbol, double newValue); void currentValue(String tickerSymbol, double newValue); }
  • 134. 用继承来扩大接口如果需要增加接口的功能,可以利用继承来实现:public interface StockTracker extends StockWatcher { void currentValue(String tickerSymbol, double newValue); }
  • 135. 问题实现java.util.Iterator接口的类必须实现哪些方法? Next, hasnext and remove 下面的接口有什么错误?public interface SomethingIsWrong { public void aMethod(int aValue) { System.out.println("Hi Mom"); } }
  • 136. 问题如何更正上面接口的错误? 下面的接口是正确的吗?public interface Marker { }
  • 137. Java语言的包引入的原因: 容易找到和使用类 避免名称冲突 控制访问 定义:包是一个相关的类和接口的集合,它可以提供访问保护和名称空间管理。
  • 138. Java语言的包Java平台中的类和接口是各种包的成员,这些类和接口是按照功能绑定的; 例如:基本的类在java.lang中; 再例如:用于输入和输出的类在java.io中。
  • 139. Java语言的包包是一种松散的类的集合,通常把需要在一起工作的类(互相访问)放入一个包。 在Java语言程序设计中,通常需要定义许多类;就像利用 “文件夹”把许多文件组织在一起,使硬盘管理的文件更清晰、更有条理一样;Java利用“包”把一些需要在一起操作的类组织在一起,以便程序员更好地管理操作这些类。
  • 140. 无名包系统自动建立“无名包”,也就是默认包或缺省包 在缺省情况下,系统会为每一个(.java)源文件创建一个无名(no name)包,这个源文件中定义的所有类都隶属于这个无名包, 它们之间可以相互引用非private(私有)的域或方法; 无名包中的类不能被其它包中的类所引用或复用。
  • 141. 无名包缺省包一般只用于临时程序或测试程序. 建议在实际系统开发中,为每个类指定有名的包。 Java使用文件系统来存储包,包的名称必须和程序文件所在目录名完全一样(大小写敏感)。 如果定义了一个多级结构的包,其结构也必须和文件系统的目录结构完全一致。
  • 142. 有名包创建有名包的语句格式为 package <包名>; 语句功能:该语句将创建一个具有指定名字的包,该包将把当前.java文件中的所有类集合到这个包内。 创建有名包,应该先创建一个子文件夹(同包名)以便存放当前.java文件和对应的.class文件。
  • 143. 有名包例如:package cardclasses; 该语句是将当前类置于包cardclassess中,需要在当前文件夹下创建一个名为cardclasses的子文件夹。 再例如:package cardsystem.cardclasses; 该语句将当前类置于cardsystem.cardclasses中,需要在当前文件夹下创建子文件cardsystem并在 cardsystem下再创建的子文件cardclasses,当前类存放在这个文件夹里。
  • 144. 使用包成员只有公共的包成员可以从定义它们的包外访问,要从包外访问公共的包成员,必须采用以下的方法: 用成员的限定名引用; 导入包成员; 导入成员所属的整个包。
  • 145. 使用包成员使用包名作为类名前缀 : java.util.Vector vc = new java.util.Vector() 加载需要使用的类 import java.util.Vector; …… Vector vc = new Vector();
  • 146. 使用包成员加载整个包 import java.util.*; …… Vector vc = new Vector(); 消除名称的二义性 使用成员的限定名; 使用环境变量 classpath set classpath=…… javac –classpath …… MyClass.java java –classpath …… MyClass
  • 147. 使用包成员在使用import语句的时候,可以使用通配符一次导入一个包中的所有类,如: import java.util.*; 这样,我们在使用java.util包中的任何类时,就可以直接使用简单类名。需要注意的是,import语句要么导入一个类,要么导入一个完整包。不能使用通配符标记包的子集或多个包,下面三条语句均无法通过编译: import java.applet.A*; import java.*.*; import java.*.io;
  • 148. 使用包成员为了简化代码,Java语言规定在以下情况时无需使用import语句导入包: 使用缺省包中的类 使用java.lang包中的类 使用和当前类在同一个包中的其他类
  • 149. 管理源代码文件将类或者接口的源代码放在一个文本文件中,文件名为类或者接口的简单名; 将源代码文件放在一个目录中,目录名反映的是类或者接口所属的包的名称。 例如:
  • 150. 管理源代码文件包成员的限定名称与文件的路径是对应的,它们的对应关系为:
  • 151. 管理类文件与源代码文件一样,字节码文件也可以通过包来进行管理; 字节码文件不必和源代码文件位与相同的目录中,可以单独管理;这样做的目的可以隐藏源代码文件。
  • 152. 类路径定义:类路径是一个目录或zip文件的有序列表,用于搜索类文件。 类路径中列出的每个目录都是包含包目录的顶层目录,编译器和解释器可以根据类的包名称和类名从顶层目录开始构造路径的其余部分。 例如:上图所示的目录结构的类路径项目包含classes,但是不包含com或者com以下的任何目录,编译器和解释器用.class文件的完整包名构造它的路径名。
  • 153. 问题假设你已经写了一些类,并且需要将这些类放进三个包中,如下所示: 为了将这些类放到正确的包中,需要在每个源代码中增加什么代码?
  • 154. 问题In Client.java add: package mygame.client; In Server.java add: package mygame.server;: In Utilities.java add: package mygame.shared;
  • 155. 问题为了遵守“管理源代码文件和类文件”所述的目录结构,需要在开发目录下创建一些子目录,并且将源代码文件放到正确的子目录中,必须创建哪些子目录?各个源代码文件应该放在哪个子目录中?In mygame/client/ place: Client.java In mygame/server/ place: Server.java In mygame/shared/ place: Utilities.java
  • 156. 欢迎提问Question !
  • 157. 第7章 异常处理华中科技大学IBM技术中心
  • 158. 为什么要异常处理?对于任何语言的程序设计而言,错误的发生总是不可避免的 为了加强程序的健壮性,程序设计时,必须充分考虑错误发生的可能性,并建立相应的处理机制。
  • 159. 什么是异常?异常(Exception)又称为例外,是指在程序运行过程中发生的非正常事件,这些事件的发生会影响程序的正常执行。如: 进行数学中“无意义”的运算,例如除数为零、对负数求对数平方根等 对数组进行操作时,超出了数组的最大下标 程序所需进行的I/O操作不能正常执行,如所需访问的文件不存在 内存耗尽无法进行类的实例化 JVM崩溃
  • 160. 异常对象在Java语言中,我们用异常对象来表示不同的异常。 所谓Java异常对象就是一个存放着相关错误信息的对象,如果方法运行时产生了异常,该方法就可以抛出一个异常对象 为了表示不同种类的异常,Java语言中定义了许多异常类。
  • 161. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 162. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 163. 例 程public class ExampleOfException { String[] lines = {"The first line", "The second line","The last line"}; public static void main (String[] args) { ExampleOfException eoe = new ExampleOfException(); eoe.methodA(); System.out.println("Program finished."); } void methodA() { methodB(); } void methodB() { methodC(); } void methodC() { for (int i=0; i<4; i++) System.out.println (lines[i]); } } The first line The second line The last line Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 at ExampleOfException.methodC(ExampleOfException.java:16) at ExampleOfException.methodB(ExampleOfException.java:12) at ExampleOfException.methodA(ExampleOfException.java:9) at ExampleOfException.main(ExampleOfException.java:6)
  • 164. Java中的异常类在Java语言中,任何的异常对象都是Throwable类的直接子类或间接子类的实例。Java的类库已经提供了一些常见的异常类,如果这些异常类不能够满足要求,用户也可以创建自己的异常类。
  • 165. Exception类 Exception的子类表示了不同类型的异常,例如RuntimeException表示运行时异常,而IOException表示I/O问题引起的异常。 这些子类也可以被继承以对不同类型的异常进行细分,如RuntimeException还可细分为NullPointerException、ArithmeticException等;IOException还可细分为FileNotFoundException、EOFException等。
  • 166. 常见的异常类ArithmeticException ArrayIndexOutOfBandsException IOException FileNotFoundException NullPointerException NumberFormatException
  • 167. Error类 Error类表示Java运行时产生的系统内部错误或资源耗尽等严重错误。 这种错误通常是程序无法控制和解决的,如果发生这种错误,通常的做法是通知用户并中止程序的执行。
  • 168. 常见的错误类NoClassDefFoundError OutOfMemoryError VirtualMachineError
  • 169. 必检异常与非必检异常RuntimeException类及其子类被称为“运行时异常” 一般发生在JRE内部 也称“非必检异常” 如NullPointerException 其他异常被成为“非运行时异常” 一般发生在JRE外部 也称“必检异常” 如IOException
  • 170. 异常处理的一般步骤异常抛出 异常捕获 异常处理
  • 171. 抛出异常方法中需要抛出异常时,可使用throw语句实现,具体步骤应该是: 选择合适的异常类; 创建该类的一个对象; 使用throw语句抛出该对象。
  • 172. 抛出异常例如,某方法readFile()对文件进行读操作,根据前面章节的介绍可以知道:当进行I/O操作时,可能会产生I/O异常。所以,在方法readFile中如果读文件操作不成功,则应抛出I/O异常。如下列程序片断所示:readFile() throws IOException{ … if (读文件不成功) throw new IOExcepion(); }
  • 173. 抛出异常如果一个方法可能抛出多个必检异常,那么必须在方法的声明部分一一列出,多个异常间使用逗号进行分隔: Class MyClass { … public myMethod(String s) throws IOException, MalformedURLException { … } … }
  • 174. 抛出异常一个方法必须通过throws语句在方法的声明部分说明它可能抛出而并未捕获的所有的“必检异常”,如果没有这么做,将不能通过编译。 值得注意的是:如果在子类中覆盖了父类的某一方法,那么该子类方法不可以比被其覆盖的父类方法抛出更多的异常(但可以更少)。所以,如果被覆盖父类的方法没有抛出任何的“必检异常”,那么子类方法绝不可能抛出“必检异常”。
  • 175. 抛出异常在下面的例子里,对于父类SuperClass而言,类SubClassA是正确的子类,而SubClassB则是错误的。 class SuperClass{ public superMethod() throws EOFException { … } } class SubClassA extends SuperClass{ //正确 public superMethod() { … } } class SubClassB extends SuperClass{ //错误 public superMethod() throws FileNotFoundException{ … } }
  • 176. 异常的捕获要捕获一个异常,程序员只需要在程序中设置一个try/catch块,其格式如下: try{ 抛出异常的代码 }catch (某Exception类型 e){ 处理该异常类型的代码 }catch (某Exception类型 e){ 处理该异常类型的代码 }
  • 177. 异常的捕获当try块中的某条代码抛出异常时:首先,自该语句的下一条语句起的所有try块中的剩余语句将被跳过不予执行;其次,程序执行catch子句进行异常捕获,异常捕获的目的是进行异常类型的匹配,并执行与所抛出的异常类型相对应的catch子句中的异常处理代码。
  • 178. 异常的捕获需要注意的是:如果try块中没有任何的异常抛出,则所有的catch子句将会被跳过;如果try块中所抛出的异常对象类型与所有的catch子句中的所声明的异常类型都不匹配,则方法会立即中止,并将该异常对象继续抛出,沿调用堆栈传递。
  • 179. examplepublic class ExampleOfException { String[] lines = {"The first line", "The second line","The last line"}; public static void main (String[] args) { ExampleOfException eoe = new ExampleOfException(); eoe.methodA(); System.out.println("Program finished."); } ... void methodC() { for (int i=0; i<4; i++) { try { System.out.println (lines[i]); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Re-setting Index Value"); } } } }
  • 180. example上面的例子中可能会产生数组越界异常,所以将其置于try块中,并在catch子句中对ArrayIndexOutOfBoundsException类型的异常进行捕获,并进行处理。 如果try块中可能抛出多个类型的异常,程序员可以使用多个catch子句对这些异常进行捕获,每种异常类型对应一个单独的catch子句。 需要注意的是,这些catch子句是顺序执行的。这意味着,异常对象总是被第一个catch子句首先捕获,如果类型不匹配,才会执行下一个catch子句。读者可以试着分析下面的程序片断,看看有什么样的问题存在。
  • 181. 问题Java运行系统从上到下分别对每个catch语句处理的例外类型进行检测,直到类型匹配为止; catch语句的排列顺序应该是从子类到父类try { … }catch(Exception e) { … }catch(IOException e) { … }catch(ArrayIndexOutOfBoundsException e) { … }
  • 182. finally当一个方法的某条语句抛出异常后,该方法剩余的语句将无法继续执行。这种情况下,方法往往无法将其占用的资源进行释放。 解决方法: 在每个catch子句的异常处理代码中也加上资源释放的代码,但这种方法非常麻烦; Java语言的异常处理机制中提供了一个更好的方案-程序员可以使用finally子句来统一进行资源释放之类的工作。
  • 183. finallyfinally子句的一般格式: try{ 抛出异常的代码 }catch (某Exception类型 e){ 处理该异常类型的代码 } … }catch (某Exception类型 e){ 处理该异常类型的代码 }finally{ 最后一定会被执行的代码 }
  • 184. finally不论try块中的代码是否抛出异常及异常是否被捕获,finally子句中的代码一定会被执行: 如果try块中没有抛出任何异常,当try块中的代码执行结束后,finally中的代码将会被执行; 如果try块中抛出了一个异常且该异常被catch正常捕获,那么try块中自抛出异常的代码之后的所有代码将会被跳过,程序接着执行与抛出异常类型匹配的catch子句中的代码,最后执行finally子句中的代码。 如果try块中抛出了一个不能被任何catch子句捕获(匹配)的异常,try块中剩下的代码将会被跳过,程序接着执行finally子句中的代码,未被捕获的异常对象继续抛出,沿调用堆栈顺序传递。
  • 185. 问题当调用上述方法m()时,try块中包含方法的return语句,返回值为1。然而,实际调用该方法后产生的返回值为0。这是因为在方法实际返回并结束前,finally子句中的内容无论如何要被执行,所以finally子句中的return语句使得该方法最终实际返回值为0。 public int m(){ try { return 1; }finally{ return 0; } }
  • 186. examplepublic class TryCatchFinally{ static void Proc( int sel ){ System.out.println("----- In Situation"+sel+" -----"); try{ if( sel==0 ){ System.out.println("no Exception caught"); return; }else if( sel==1 ){ int i=0; int j=4/i; }else if( sel==2 ){ int iArray[]=new int[4]; iArray[10]=3; }
  • 187. example }catch( ArithmeticException e ){ System.out.println("Catch "+e); }catch( ArrayIndexOutOfBoundsException e ){ System.out.println("Catch "+e.getMessage()); }catch( Exception e ){ System.out.println("Will not be executed"); }finally{ System.out.println("in Proc finally"); } }  public static void main( String args[] ){ Proc( 0 ); Proc( 1 ); Proc( 2 ); } }程序运行结果: ----- In Situation0 ----- no Exception caught in Proc finally ----- In Situation1 ----- Catch java.lang.ArithmeticException: / by zero in Proc finally ----- In Situation2 ----- Catch 10 in Proc finally
  • 188. 声明异常一个方法不处理它产生的异常,而是沿着调用堆栈向上传递,由调用它的方法来处理这些异常,则需要声明异常。 声明异常的方法: returnType methodName([paramlist]) throws exceptionList 例如: void compute(int x) throws ArithmeticException{ … }
  • 189. examplepublic class ThrowsException1{ static void Proc(int sel) throws 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; } }
  • 190. example public static void main(String args[]){ try{ Proc(0); Proc(1); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("Catch "+e); }finally{ System.out.println("in Proc finally"); } } }程序运行结果: ----- In Situation0 ----- no Exception caught ----- In Situation1 ----- Catch java.lang.ArrayIndexOutOfBoundsException:10 in Proc finally
  • 191. 创建自己的异常类Java语言中允许用户定义自己的异常类,这些用户自定义异常类必须是Throwable的直接子类或间接子类。 根据Java异常类的继承关系,用户最好将自己的异常类定义为Exception的子类,而不要将其定义为RuntimeException的子类。因为对于RuntimeException的子类而言,即使调用者不进行处理,编译程序也不会报错。将自定义异常类定义为Exception的子类,可以确保调用者对其进行处理。
  • 192. exampleclass MyException extends Exception{ private int detail; MyException( int a ){ detail = a; } public String toString( ){ return "MyException "+detail; } }
  • 193. examplepublic class ExceptionDemo{ static void compute(int a) throws MyException { System.out.println("called compute("+a+")"); if( a>10 ) throw new MyException(a); System.out.println("normal exit"); } public static void main( String args[] ){ try{ compute( 1 ); compute( 20 ); } catch( MyException e ){ System.out.println("Caught "+e); } } }程序运行结果: called compute(1) normal exit called compute(20) Caught MyException 20
  • 194. 异常的优点将错误处理代码与“常规”代码分离; 例7.7.1 将错误沿调用堆栈传递; 可以由感兴趣的方法来处理异常 对错误类型进行分组和区分。
  • 195. 说明的问题方法也可以不对异常进行捕获而直接将其抛出,并在方法声明中进行说明,那么对方法产生的异常到底是应该直接进行捕获还是应该将其进行传递呢? 一般来说,对于方法的最终调用者而言,他必须捕获并处理该方法抛出的异常。而对于抛出异常的方法而言,应该对方法可能产生的异常进行区分,尽量避免一些异常的产生,捕获并处理那些你知道如何处理的异常,而对那些你不知道方法的调用者会如何处理的异常,最好将它们留给方法的调用者进行处理,这样会增加程序的灵活性。
  • 196. 说明的问题需要特别指出的是,虽然异常处理机制为程序员提供了非常大的方便,但是作为一个好的程序员要尽量避免异常的过度使用。这是因为:异常对象的实例化和其后续处理工作是非常消耗资源的,过度的使用异常会明显影响程序的执行速度。所以,在使用异常处理时应该仔细考虑,只对有必要的异常情况使用异常,而不可以将异常泛化。
  • 197. 两段代码的比较代码1: try { int n = InputReader.inputInteger(请输入一个整数"); if (n<100 || n>1) throw new NumberFormatException(); }catch (NumberFormatException e) { System.out.println("输入范围错误!"); } 代码2: int n = InputReader.inputInteger(请输入一个整数"); if (n<100 || n>1) System.out.println("输入范围错误!");代码1采用了异常处理方式;代码2则通过对用户输入的分析避免了异常的使用,提高了代码效率。
  • 198. 问题下面的代码合法吗? try { ... } finally { ... }下面的代码可以捕获何种异常?使用这种异常处理器有什么问题? catch (Exception e) { ... }
  • 199. 问题下面的处理器可以捕获什么异常? } catch (Exception e) { ... } catch (ArithmeticException a) { ... } 这个异常处理器中有错误吗?此代码能否被编译?
  • 200. 问题public static void cat(File named) { RandomAccessFile input = null; String line = null; try { input = new RandomAccessFile(named, “r”); while ((line = input.readLine()) != null { System.out.println(line); } return; } finally { if (input != null) { input.close(); } } }
  • 201. 第八章 线程华中科技大学IBM技术中心
  • 202. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 203. 什么是线程线程是程序内的一个单一的顺序控制流程,也被称为“轻型进程(lightweight process)” 或“执行上下文(execution context )” 线程用于分隔任务 线程类似于传统的顺序程序,都有一个执行的起点,经过一系列指令后到达终点。线程在执行过程中的任何时刻只能有一个执行点
  • 204. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 205. 线程的作用 线程真正的神奇之处并不在于它处理顺序任务流程的作用,而是在于多个线程可以同时运行,并且在一个程序内执行不同的任务 演示排序程序
  • 206. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 207. 继承Thread类在构造函数中调用父类的构造函数 参考Thread类的构造函数 在run方法中实现任务处理功能 创建线程对象后,通过调用start()方法启动线程
  • 208. 继承Thread类class PrintThread extends Thread { private int sleepTime; public PrintThread( String name ) { super( name ); sleepTime = (int) ( Math.random() * 5000 ); System.out.println( "Name: " + getName() + "; sleep: " + sleepTime ); } public void run() { try { System.out.println( getName() + " going to sleep" ); Thread.sleep( sleepTime ); } catch ( InterruptedException ie ) { System.err.println( ie.toString() ); } System.out.println( getName() + " done sleeping" ); } }
  • 209. 执行线程任务public class ThreadTester { public static void main( String args[] ) { PrintThread thread1, thread2, thread3, thread4; thread1 = new PrintThread( "thread1" ); thread2 = new PrintThread( "thread2" ); thread3 = new PrintThread( "thread3" ); thread4 = new PrintThread( "thread4" ); System.out.println( "\nStarting threads" ); thread1.start(); thread2.start(); thread3.start(); thread4.start(); System.out.println( "Threads started\n" ); } }
  • 210. 实现Runnable接口实现run方法,在该方法中实现任务处理功能 参考Runnable接口定义 创建实现Runnable接口的类对象 利用Thread类的构造函数创建线程对象 public Thread(Runnable target) 通过调用线程对象的start()方法启动线程
  • 211. 实现Runnable接口class PrintRunnable implements Runnable { private int name; private int sleepTime; public PrintRunnable( String name ) { this.name = name; sleepTime = (int) ( Math.random() * 5000 ); System.out.println( "Name: " + name + "; sleep: " + sleepTime ); } public void run() { try { System.out.println( name + " going to sleep" ); Thread.sleep( sleepTime ); } catch ( InterruptedException ie ) { System.err.println( ie.toString() ); } System.out.println( name + " done sleeping" ); } }
  • 212. 执行线程任务public class RunnableTester { public static void main( String args[] ) { PrintRunnable thread1, thread2, thread3, thread4; thread1 = new PrintRunnable ( "thread1" ); thread2 = new PrintRunnable ( "thread2" ); thread3 = new PrintRunnable ( "thread3" ); thread4 = new PrintRunnable ( "thread4" ); System.out.println( "\nStarting threads" ); new Thread(thread1).start(); new Thread(thread2).start(); new Thread(thread3).start(); new Thread(thread4).start(); System.out.println( "Threads started\n" ); } }
  • 213. 选择合适的方式创建线程继承Thread类 简单直观 不能继承其他父类 实现Runnable接口 可继承其他父类 代码稍复杂 ClockApplet示例
  • 214. ClockApplet示例import java.applet.Applet; import java.awt.Graphics; import java.util.Date; public class ClockApplet extends Applet implements Runnable { private Thread clockThread = null; public void start() { if (clockThread ==null) { clockThread = new Thread(this); clockThread.start(); } } public void paint(Graphics g) { Date date = new Date(); g.drawString(date.toString(), 5, 10); }
  • 215. ClockApplet示例 public void run() { while (true) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e) { } } } }
  • 216. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 217. 线程状态的转换条件可运行状态和不可运行状态转换条件进入不可运行状态条件返回可运行状态条件挂起(调用suspend()方法)调用resume()方法睡眠(调用sleep()方法)sleep()方法的指定时间结束阻塞(请求I/O操作)I/O操作结束等待(调用某对象的wait()方法)调用该对象的notfiy()或notifyAll()方法
  • 218. 停止线程正常终止 run()方法运行完毕 强行中止 调用线程对象的stop()方法 创建线程对象的上级线程停止
  • 219. 线程的优先级Java线程优先级 范围从1-10,数字越高越能被优先执行 通过线程对象的setPriority()方法设置优先级 缺省优先级为5 三个常数:MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY
  • 220. 线程的调度大多数计算机只有一个CPU,因此一个时刻只有一个线程在运行,多个线程只能是“宏观上并行,微观上串行” 在有限个CPU的系统中确定多个线程的执行顺序称为线程的调度 Java语言采用了简单的“固定优先级调度算法”,高优先级的线程总是更容易得到CPU使用权。 只有当所有高优先级的线程停止或处于不可运行状态,低优先级的线程才能运行。
  • 221. 抢占式调度Java语言的“抢占式调度策略” 当一个线程正在运行时,如果有更高优先级的线程处于“可运行”状态,系统将强制暂停低优先级的线程,使高优先级的线程“抢占”低优先级线程的CPU资源
  • 222. 自私的线程线程如果不放弃CPU,其他同优先级的线程就很难得到运行 run() { while(true) { …… // yield(); } } 除非更高优先级的抢占CPU,或者……
  • 223. 时间片策略部分平台(如Windows)针对“自私线程”采用了时间片轮换策略 将CPU的运行时间划分成段,相同优先级的线程分别占用一段轮流执行 执行的顺序和轮换的时间不可预测
  • 224. 正确理解优先级和调度线程调度策略和JRE运行平台直接相关 Java本身并不直接支持时间片 不要编写“自私的”线程 在适当的时候通过yield()方法放弃CPU yield()方法使线程由运行状态变为就绪状态 yield()方法放弃CPU后,只有同优先级的线程才能得到CPU,低优先级的线程仍不能运行
  • 225. 正确理解优先级和调度在多任务环境中,如果完全依赖低优先级线程可能永远得不到运行机会,称为线程“饿死” 线程调度程序可能为低优先级线程分配CPU,以防止线程“饿死” 优先级只是用来提高多线程的调度效率,并不保证高优先级线程永远优先运行 不要依赖线程的优先级来设计对调度敏感的算法
  • 226. 正确理解优先级和调度public class PriorityTest extends Thread { public PriorityTest(String name) { super(name); } public void run() { while(true) { int i; for(int j=0; j<100000; j++) for(int k=0; k<1000; k++) i = j + k; if (getPriority()
  • 227. 正确理解优先级和调度 public static void main(String[] args) { PriorityTest test1 = new PriorityTest("Higer priority thread"); PriorityTest test2 = new PriorityTest("Lower priority thread"); test2.setPriority(4); test1.start(); test2.start(); } } 从运行结果上看,低优先级的线程也有执行的机会。
  • 228. 线程的调度当多个线程对同一个对象进行读写操作的时候,如果完全不加控制,可能会出现难以预料的结果 比较典型的是“生产者/消费者”问题 一个线程(生产者)修改数据 另一个线程(消费者)读取数据 希望生产者每次修改的数据都能被消费者读取,并且不会重复读取
  • 229. 生产者/消费者问题涉及4个对象 CubbyHole对象,用于保存生产者的修改,并能让消费者读取 Producer对象,产生0-9,存入CubbyHole对象中 Consumer对象,读取CubbyHole对象中的数据 ProdConsTester,测试运行程序
  • 230. 生产者/消费者问题CubbyHole类 public class CubbyHole { private int data; public int get() { return this.data; } public void put(int data) { this.data = data; } }
  • 231. 生产者/消费者问题Producer类 public class Producer extends Thread { private CubbyHole res; public Producer(CubbyHole res) { this.res = res; } public void run() { for (int i=0; i<10; i++) { res.put(i); System.out.println(“Producer put:” + i); try { sleep((int)(Math.random()*100)); } catch (InterruptedException e) { } } } }
  • 232. 生产者/消费者问题Consumer类 public class Consumer extends Thread { private CubbyHole res; public Consumer(CubbyHole res) { this.res = res; } public void run() { for (int i=0; i<10; i++) { System.out.println(“Consumer get:” + res.get()); try { sleep((int)(Math.random()*100)); } catch (InterruptedException e) { } } } }
  • 233. 生产者/消费者问题ProdConsTester类 public class ProdConsTest { public static void main(String[] args) { CubbyHole res = new CubbyHole(); Producer pro = new Producer(res); Consumer con = new Consumer(res); pro.start(); con.start(); } }
  • 234. 生产者/消费者问题分析运行结果可发现两个问题 生产者产生的资源可能没有被消费者获取 生产者产生的资源可能被消费者重复取得 造成这些问题的原因是两个线程在访问同一个对象时没有考虑同步的控制。 当消费者尚未取得资源时,生产者可能已经产生新的资源,使消费者错过一些资源 当生产者尚未产生新资源时,消费者再次执行get()方法,造成资源被重复获取
  • 235. 引入同步机制解决前述问题的关键是引入线程之间的同步控制逻辑 通过synchronized关键字锁定共享对象 方法名前加synchronized关键字标记 用synchronized(Object) {…}标记锁定的代码 当线程执行由synchronized关键字控制的代码时,就锁定了共享对象。其他线程如果需要操作该对象,就必须等待该线程执行完受保护的代码
  • 236. 新的CubbyHolepublic class CubbyHole { private int data; private boolean getable; public synchronized int get() { while (getable == false) { try { wait(); } catch (InterruptedException e) { } } getable = false; notifyAll(); return this.data; }
  • 237. 新的CubbyHole public synchronized void put(int data) { while (getable == true) { try { wait(); } catch (InterruptedException e) { } } this.data = data; getable = true; notifyAll(); } }
  • 238. 更新后的运行结果Producer put:0 Consumer get:0 Producer put:1 Consumer get:1 Producer put:2 Consumer get:2 Consumer get:3 Producer put:3 Producer put:4 Consumer get:4 Consumer get:5 Producer put:5 Producer put:6 Consumer get:6 Consumer get:7 Producer put:7 Producer put:8 Consumer get:8 Producer put:9 Consumer get:9
  • 239. 线程的死锁synchronized关键字可以解决多线程同步问题,但如果处理不当,可能产生新的问题——死锁 当多个线程分别占用某个资源,并等待其他线程释放该资源时,可能产生死锁 synchronized a() { … b(); } synchronized b() { … a(); }
  • 240. 线程的死锁任何程序员在处理并发线程竞争资源的时候,都必须仔细考虑如何避免死锁 不要设计功能过于复杂,执行时间过长的线程 不要设计过多线程 编写可以检测死锁的代码
  • 241. 线程的分组线程组可以将多个线程集中在一个对象中,并同时操作这些线程(比如全部挂起或杀死) 所有的Java线程都是某个线程组的一员。当Java应用程序开始执行时,虚拟机会创建一个名为main的线程组 如果程序没有显示地创建其他线程组并将线程设置其中,则所有的线程都是main线程组的成员
  • 242. 创建线程组可利用ThreadGroup类创建线程组对象 ThreadGroup myGroup = new ThreadGroup(“my group”); Thread thread1 = new Thread(myGroup, “thread one”); Thread thread2 = new Thread(myGroup, “thread two”);
  • 243. 使用线程组使用线程组对象操作多个线程: public int activeCount() 返回线程组中活动线程的估计数 public final void stop() 停止线程组中的所有线程 public final void suspend() 挂起线程组中的所有线程 public final void resume() 唤醒线程组中所有被挂起的线程 public final void setMaxPriority(int pri) 设置线程组的最大优先级,组中的线程优先级不得高于该值
  • 244. 欢迎提问Question !
  • 245. 第9章 I/O:读和写华中科技大学IBM技术中心
  • 246. I/O与流I/O是程序设计中的重要问题,大部分的应用程序都需要I/O操作,比如从键盘获得用户输入、在屏幕输出运行结果、对磁盘文件进行读写等等。应用程序只有通过I/O操作才能实现与用户的交互及数据的处理及存储 在Java语言中,将不同类型的I/O抽象为流。所谓“流(stream)”,可以看作是数据在文件或程序之间的传递
  • 247. 输入流和输出流 一般来说,流有两种基本形式:输入流和输出流,根据程序是作为数据流的目的端还是源端来划分。程序首先要打开一个流,才能与数据文件进行通信。 通过输入流,程序可以从数据文件读取数据,但不可向输入流中写入数据;反之,通过输出流,程序可以向数据文件中写入数据。程序与其他设备间的I/O也可以使用流,这时可将设备看作是一个数据文件。
  • 248. Java I/O流类的组织模式
  • 249. java.io在Java开发环境中,主要是由包java.io中提供的一系列的类和接口来实现输入/输出处理。而标准输入/输出处理则是由包java.lang中提供的类来处理的,这些类又都是从包java.io中的类继承而来的。 I/O类提供了低层次和高层次的界面。每一种介质都有一对与之相关联的输入输出类,它们提供低层次的面向数据序列(字符、字节)的界面。与介质相关的各个类都分别是输入输出抽象流类的子类,它们通常具有与介质相关的构造器及方法。 I/O抽象类为所有与介质相关的具体输入输出类提供了一个统一的界面。反过来各个具体的与介质相关的输入输出类也扩展了抽象类,通过它们可以实现在具体介质上的输入输出操作
  • 250. I/O操作的一般步骤 构造一个与介质相关的I/O对象,以提供一种低层次的方法将数据输入或输出到相应的介质; 将与介质相关的对象强制类型转换为它的父类(即抽象I/O类),并利用该对象构造一个流对象。这样便建立起了流类对象与介质相关对象的关联; 这时就可利用流对象的I/O方法进行相应介质上的数据读写。
  • 251. 字节流类
  • 252. InputStream类InputStream类定义了一套所有字节输入流所需的方法 方法描述read()将数据读入流中skip()跳过流中的若干字节available()返回当前流中的可用字节mark()在流中标记一个位置reset()返回到流中的标记位置markSupported()返回一个boolean值,描述流是否支持标记和复位close()关闭流
  • 253. OutputStream类OutputStream类定义了一套所有字节输出流所需的方法。 方法描述write()写数据到流flush()强制将被缓冲的内容写到输出close()关闭流
  • 254. 字符流类
  • 255. Reader与Writer类Reader类的相关方法: void close() void mark(int readAheadLimit) boolean markSupported() int read() int read(char[] cbuf) int read(char[] cbuf, int off, int len) boolean ready() void reset() long skip(long n) Writer类的相关方法: void close() void flush() void write(char[] cbuf) void write(char[] cbuf, int off, int len) void write(int c) void write(String str) void write(String str, int off, int len)
  • 256. 流的使用(1)I/O类型流作用内存CharArrayReader CharArrayWriter ByteArrayInputStream ByteArrayOutputStream用来从内存读取数据或向内存写入数据StringReader StringWriter StringBufferInputStream从内存里的某个String或StringBuffer读 字符或字节管道PipedReader PipedWriter PipedInputStream PipedOutputStream实现一个输入、输出管道。管道可用于 一个线程的输出连接到另一个线程的输入
  • 257. 流的使用(2)文件FileReader FileWriter FileInputStream FileOutputStream用于对本机文件系统上的一个 件行读写联结N/A SequenceInputStream将多个输入流联结成为一个输 入流对象串行化N/A ObjectInputStream ObjectOutputStream将对象串行化数据转换N/A  DataInputStream DataOutputStream以一种与机器无关的格式读写 原始数据类型
  • 258. 流的使用(3)计数LineNumberReader LineNumberInputStream在读取时记录行数预览PushbackReader PushbackInputStream带有“回推(pushback)”缓冲区的输入流打印PrintWriter PrintStream包含便捷的打印方法的流。
  • 259. 流的使用(4)缓冲BufferedReader BufferedWriter BufferedInputStream BufferedOutputStream缓冲流,用于在读写时进行数据缓冲过滤FilterReader FilterWriter FilterInputStream FilterOutputStream过滤流的抽象类接口。数据读写时对 数据进行过滤在字节和 字符之间 转换InputStreamReader OutputStreamWriter字节流和字符类间的转换桥梁
  • 260. 文件流要对本机文件系统上的文件进行读写,需要使用文件流。Java的文件流类包括字符流的FileReader、FileWriter和字节流的FileInputStream、FileOutputStream。文件流对象的构造需要提供文件名作为参数,也即可以通过文件名来创建文件流。这里的所谓文件名可以是字符串、File对象或FileDescriptor对象。
  • 261. 例程import java.io.*; class Copy{ private void copy(InputStream in, OutputStream out) throws IOException { byte[] buf = new byte[4096]; int len = in.read(buf); while (len != -1) { out.write(buf, 0, len); len = in.read(buf); } } public void cat(String fsrc, String fdest) { try { InputStream in = new FileInputStream(fsrc); OutputStream out = new FileOutputStream(fdest, true); copy(in, out); out.close(); in.close(); }catch (IOException ex) { System.err.println(ex);} } }
  • 262. 例程-cont.public class UseCopy{ public static void main(String[] args){ Copy c=new Copy(); c.cat(“in.dat”,”out.dat”); } }
  • 263. 内存流为了支持内存上的输入输出,java.io包内提供了一组相关的类: 字节流类——ByteArrayInputStream ByteArrayOutputStream StringBufferInputStream 字符流类——CharArrayReader CharArrayWriter StringReader StringWriter
  • 264. 例程import java.io.*; public class ByteArrayOutputStreamTest {      public static void main(String[] args) { try{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); for (int i = 0; i < 1000; i++){ ps.println(i + " ABCDEFGHIJKLMNOPQRSTUVWXYZ"); } long start = System.currentTimeMillis(); FileOutputStream fos =  new FileOutputStream("ByteArrayOutputStreamTest"); baos.writeTo(fos); fos.close(); long stop = System.currentTimeMillis(); System.out.println("time elapsed (milliseconds) = " + (stop - start)); }catch (FileNotFoundException fnfe) {  System.out.println(fnfe.getMessage()); }catch (IOException ioe) {  System.out.println(ioe.getMessage());  } }
  • 265. 管道流 管道是用来把一个线程的输出连接到另一个线程的输入。管道输入流作为一个通信管道的接收端,管道输出流则作为发送端。管道流必须是输入输出并用,也就是说在使用管道前,两者必须进行连接。
  • 266. 为什么要用到管道流?当某个程序的输出作为另外一个程序的输入时,如果没有管道,就必须为程序提供一个存放中间结果的位置,前一个程序将输出数据写入该位置,而后一个程序再从该位置读出这些数据,这样的做法无疑是低效率的。 通过管道,可以连接程序的输出和输入,直接将前一程序的输出作为后一程序的输入,提高了程序效率。
  • 267. 管道流的连接方式java.io中为字符类型和字节类型各提供了一对输入输出管道流类:PipedReader/ PipedWriter和PipedInputStream/PipedOutputStream。 管道流的连接方式有两种,以PipedInputStream/PipedOutputStream为例: 在构造方法中进行连接:PipedInputStream(PipedOutputStream pos); PipedOutputStream(PipedInputStream pis); 通过各自的connect()方法连接: 在类PipedInputStream中,connect(PipedOutputStream pos); 在类PipedOutputStream中,connect(PipedInputStream pis);
  • 268. 例程class PipedExample { public static void main(String args[]) throws IOException{ byte dataA = 123, dataB= 321; PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis); System.out.println("PipedInputStream"); try{ pos.write(dataA); pos.write(dataB); System.out.println((byte)pis.read()); System.out.println((byte)pis.read()); }finally{ pis.close(); pos.close(); } } }
  • 269. 过滤器流在某些情况下,对于由程序写入或读取的数据,需要在写入或读取之前对其进行处理或者过滤 总的来说,过滤器的作用是对相关输入输出流中的数据进行处理,而对于程序而言,这些过滤器是透明的。
  • 270. 过滤器流类 类型类作用字符FilterInputStream FilterOutputStream字节类型的过滤器类的抽象父类BufferedInputStream BufferedOutputStream缓冲过滤器流,用于提高输入输出效率PushBackInputStream允许将已读取的数据“压回”到流中GZIPInputStream GZIPOutputStream ZipInputStream ZipOutputStream对数据进行zip格式或gzip格式的压缩FilterReader FilterWriter字符类型过滤器类的抽象父类BufferedReader BufferedWriter缓冲过滤器流,用于提高输入输出效率PushBackReader允许将已读取的数据“压回”到流中LineNumberReader用计数器统计从输入中读取的数据行数
  • 271. 例程import java.io.*; public class ReadLineTest { public static void main(String[] args) { try { BufferedReader br = new BufferedReader(new FileReader(args[0])); String line = null; int i = 0; while((line = br.readLine()) != null) { i++; System.out.println(i + ": " + line); } br.close(); }catch(Exception e) { e.printStackTrace(); } } }
  • 272. 对象的串行化所谓对象串行化是指读写对象的过程,其关键之处在于以串行的流的形式来表示结构化的对象。为了实现完整对象的输入输出,java.io包中提供了两个类:ObjectOutputStream和ObjectInputStream。这两个流类与其他的字节流类的功能类似,其特殊之处在于通过它们可以读写对象。对象的串行化通常在下面两个方式下使用: 远程方法调用(RMI)——在远程方法调用时,需要在客户机与服务器之间传递各种对象。 对象持久性保存——允许对象在创建它们的程序的生命周期结束后仍然存在保存,供以后的程序调用。
  • 273. Serializable接口 并非所有对象都是可串行化的,如果要对某对象进行串行化,该对象的类必须实现Serializable接口 Serializable接口是一个空接口,也就是说,它不包含任何方法的声明,该接口的作用只是表明这个类的对象可以被串行化
  • 274. 随机文件处理使用流的形式对文件进行读写必须顺序进行,也就是说这些文件流的数据必须按先后次序进行处理。在对某些顺序存储访问介质,例如磁带等进行访问时,这样的文件流方式非常有用 随机文件存取提供了一种更灵活的文件读写方式,它允许对文件的内容进行非顺序的访问。在这里,“随机”是指所存取的数据不需要与以前存取过的历史数据有任何的关系。使用随即文件存取方式可以在打开一个文件后同时进行读写操作,并且可以移动文件指针使其指向文件中的任何位置
  • 275. 随机存取文件的结构在文件内部,文件被分成固定长度的数据块(记录)。从概念上来说,文件可以看作是一个记录数组。文件指针的移动是以记录为单位的。
  • 276. 文件类 FileFile类的核心概念是封装用户文件系统中的某个文件或目录,它包含许多用于执行文件常规操作的方法以及检查、访问、删除、创建、更改指定的文件或目录 File类的构造函数有三个,分别根据文件名、文件路径与文件名、文件对象(目录)与文件名创建实例: public File(String path) public File(String path,String name) public File(File dir,String name)
  • 277. RandomAccessFile类RandomAccessFile类的构造函数使用了两个参数,第一个参数表示要操作的文件,可以使用字符串类型的文件名也可以使用一个文件对象;第二个字符串类型的参数mode表示了对文件的操作方式:mode为 ”r” 时表示可以从文件读取;mode 为 ”rw” 时表示既可以从文件读取也可以向文件写入 RandomAccessFile类通过实现DataInput和DataOutPut的方法来实现文件数据的读写,这些方法允许使用二进制编码形式将基本的Java类型写入或读出文件。在RandomAccessFile类中还提供了一些操作文件指针的方法,如通过seek方法可以将文件指针移动到其参数所制定的位置。
  • 278. 例程import java.io.*; public class FileTest {   public static void main(String[] args) throws IOException {          RandomAccessFile raf = new RandomAccessFile("foo.txt", "rw");   try {              Writer out =  new OutputStreamWriter(new FileOutputStream(raf.getFD()), "UTF-8");   out.write("Hello World!!");              out.flush();               raf.seek(6);               out.write("Java");          out.flush();          }finally {              raf.close();          }  }
  • 279. 第十章 图形用户界面华中科技大学IBM技术中心
  • 280. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 281. 图形用户界面基本元素图形用户界面(GUI) 可以使程序提供独特的视觉效果 提高软件易用性 使用鼠标和键盘操作 $javahome$/demo/jfc/SwingSet2
  • 282. 图形用户界面基本元素常见的图形界面元素 基本组件 文本框、按钮、输入框 单选/多选按钮、下拉框/复选框 …… 容器 可放置基本组件的组件 窗体、面板、框架 所有的组件都必须存在于容器之中 顶层容器Container
  • 283. AWT和SwingAWT-Abstract Window Toolkit 图形界面是平台相关的 AWT是重量级的,依赖本地代码实现 不同平台外观有差异 Swing-轻量级纯Java的图形库 基于AWT,更丰富,功能更强大 不同平台外观一致 牺牲了性能 SWT
  • 284. 常用的图形组件AWT java.awt.* Label、Button、List、TextField… Frame、Panel、Container Swing javax.swing.* JLabel、JButton、Jlist、JTextField… JFrame、JPanel 不要在容器中混合使用AWT和Swing组件
  • 285. 常用的图形组件组件类名描述JLabel不可编辑的文本行(可带图标)JTextField可编辑的文本行JButton按钮JCheckBox复选框JRadioButton单选框JComboBox下拉框JPanel面板JFrame框架 更多组件可参考javax.swing.*
  • 286. 图形组件测试import java.awt.*; import javax.swing.*; public class GUITest extends JFrame { private JLabel label; private JButton button; private JCheckBox checkbox; private JRadioButton rbutton; private JTextField textfield; private JComboBox cbox; private JList list;
  • 287. 图形组件测试 public GUITest() { super("GUI Test"); Container container = getContentPane(); container.setLayout(new FlowLayout()); label = new JLabel("Im JLabel"); button = new JButton("Im JButton"); rbutton = new JRadioButton("Im JRadioButton"); textfield = new JTextField(10); textfield.setText("Im JTextField"); checkbox = new JCheckBox("Im JCheckBox"); cbox = new JComboBox(); cbox.addItem("JComboBox item 1"); cbox.addItem("JComboBox item 2"); list = new JList(); String[] data = {"JList data 1","JList data 2", "JList data 3"}; list.setListData(data);
  • 288. 图形组件测试 container.add(label); container.add(button); container.add(checkbox); container.add(rbutton); container.add(textfield); container.add(cbox); container.add(list); setSize(300,200); setVisible(true); } public static void main(String[] args) { GUITest test = new GUITest(); test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
  • 289. 图形组件测试运行结果
  • 290. 事件驱动图形界面程序是通过事件来驱动的 当用户对图形组件进行操作时产生事件 如鼠标点击按钮、在输入框中输入文字等 事件对象用于记录事件详细内容 java.awt.AWTEvent
  • 291. 事件处理模型事件处理模型中的三要素 事件源对象 即产生事件的图形组件如按钮、文本框等 事件对象 记录事件的对象,由系统产生 事件监听对象 捕获并处理事件的对象 程序员的工作 将事件监听对象注册到事件源对象 编写处理事件的代码
  • 292. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 293. HUST & IBM Computer Tech. Center华中科技大学IBM技术中心
  • 294. 事件处理示例import java.awt.*; import java.awt.event.*; import javax.swing.*; public class EventTest extends JFrame { private JButton button; public EventTest() { super("Event Test"); Container container = getContentPane(); button = new JButton("Click Me"); EventHandler handler = new EventHandler(); container.add(button); setSize(200,100); setVisible(true); button.addActionListener(handler); }
  • 295. 事件处理示例 class EventHandler implements ActionListener { public void actionPerformed(ActionEvent event) { ((JButton)event.getSource()).setText("Im Clicked"); } } public static void main(String[] args) { EventTest app = new EventTest(); app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
  • 296. 常见的事件类和监听接口不同的事件源根据用户的操作可能产生不同的事件对象,并由相应的事件监听对象处理事件源产生的事件需要实现的监听接口JButtonItemEventItemListenerJCheckBoxJRadioButtonJList
  • 297. 鼠标事件类和监听接口所有的图形组件都能产生鼠标事件 java.awt.event.MouseEvent 处理不同的鼠标操作应实现不同的接口 鼠标点击、鼠标进入组件、鼠标离开组件 实现MouseListener接口 鼠标在组件中移动和拖动 实现MouseMotionListener 查看Java API文档,实现这些接口应该定义哪些方法?
  • 298. 事件适配器由JavaAPI提供的实现了相应事件监听接口的抽象类,可直接使用而无需定义额外的事件处理类,从而简化事件处理代码 addMouseListener(new MouseAdapter() { mouseClicked(MouseEvent event){ // … } });
  • 299. 界面布局设计图形界面时,程序员应该考虑组件在容器中的位置、大小和组件之间的排列方式 如果没有使用布局管理器,程序员需要确定每个组件的大小和在容器中的坐标: JButton btn = new JButton(“Ok”); btn.setBounds(10, 20, 60, 20); add(btn); 当窗口大小改变时,组件不会自动调整位置和大小
  • 300. 布局管理器Java使用布局管理器简化组件布局工作 决定图形组件的排列形式 实现接口java.awt.LayoutManager 使用布局管理器的好处 当程序窗口尺寸改变时,布局管理器能自动调整组件的位置和大小
  • 301. 常用的界面布局形式常用的布局管理器 FlowLayout BorderLayout BoxLayout CardLayout GridLayout GridBagLayout 通过容器组件的setLayout()方法设置容器中的组件排列形式,如: setLayout(new FlowLayout());
  • 302. FlowLayout最简单的界面布局方式,从左至右、从上至下按顺序依次摆放组件: setLayout(new FlowLayout()); add(button1); add(button2); add(button3); add(button4); add(button5);
  • 303. BorderLayout按东南西北中五个区域摆放组件,通常作为窗口主框架 setLayout(new BorderLayout()); add(“North”, button1); add(“West”, button2); add(“East”, button3); add(“South”, button4); add(“Center”, button5);
  • 304. GridLayout各组件占用相等的格空间 setLayout(new GridLayout(3, 2)); add(button1); add(button2); add(button3); add(button4); add(button5);
  • 305. GridBagLayout最复杂、最灵活的布局方式,将容器空间划分成网格,每个组件可占用多个网格。通常还需要使用GridBagConstraints对象设置组件占用的格数和方位。加入组件前,需要调用布局管理器对象的setConstraints()方法设置组件的显示约束。
  • 306. 欢迎提问Question !
  • 307. 华中科技大学IBM Java培训