1、Java 程序设计实用教程(第 4 版)习题解答与实验指导叶核亚 编著2013 年 11 月目录“Java 程序设计” 课程教学要求 1第 1 章 Java 概述 3第 2 章 Java 语言基础 5第 3 章 类的封装、继承和多态 22第 4 章 接口、内部类和 Java API 基础 38第 5 章 异常处理 43第 6 章 图形用户界面 45第 7 章 多线程 50第 8 章 输入/输出流和文件操作 52- 1 -“Java 程序设计”课程教学要求1. 课程性质、目的和任务程序设计是高等学校计算机学科及电子信息学科各专业本科的核心专业基础课程,是培养学生软件设计能力的重要课程。在计算机学
2、科的本科教学中,起着非常重要的作用。“Java 程序设计”是计算机科学与技术专业本科的专业基础限选课,开设本课程的目的是:进行程序设计和面向对象方法的基础训练;使用 Java 编程技术,设计解决操作系统、网络通信、数据库等多种实际问题的应用程序。本课程通过全面、系统地介绍 Java 语言的基础知识、运行机制、多种编程方法和技术,使学生理解和掌握面向对象的程序设计方法,理解和掌握网络程序的特点和设计方法,建立起牢固扎实的理论基础,培养综合应用程序的设计能力。本课程的先修课程包括:C/C+程序设计 I、C/C+程序设计 II、数据结构、操作系统、计算机网络、数据库原理等。2. 教学基本要求本课程的
3、基本要求如下。 了解 Java 语言特点,理解 Java Application 应用程序的运行原理和方法。掌握在JDK 环境中编译和运行程序的操作,熟悉在 MyEclipse 集成开发环境中,编辑、编译、运行和调试程序的操作。 掌握 Java 语言中语句、数组、引用类型等基本语法成分的使用方法,通过类、接口、内嵌类型、包、异常处理等机制表达和实现面向对象程序设计思想。 掌握 Java 的多种实用技术,包括图形用户界面、多线程、文件操作和流、使用URL 和 Socket 进行网络通信等。 熟悉 Java JDBC 数据库应用的设计方法。 熟悉基于 JSP 的 Web 应用设计方法。重点:面向对
4、象概念,图形用户界面,线程,流与文件操作,Socket 通信。难点:继承和多态,线程同步,流与文件操作,Socket 通信,JDBC,JSP。3. 学时分配本课程学时为 64 学时,其中讲课 48 学时,实验 16 学时。学时分配见下表。章节(或内容) 讲课 实验 合计Java 概述 2 2Java 语言基础 4 4类的封装、继承和多态 6 2 8接口、内部类和 Java API 基础 4 2 6- 2 -异常处理 2 2图形用户界面 6 2 8多线程 4 2 6输入/输出流和文件操作 6 2 8网络通信 6 2 8数据库应用 2 2 4Web 应用 4 2 6综合应用设计 2 2合 计 48
5、 16 644. 实验教学目标与基本要求“Java 程序设计”是理论与实践相结合的课程,不仅要求学生掌握基础知识,理解基本原理,更要在实践环节中培养软件设计的基本技能。实践性环节是巩固所学理论知识、积累程序设计经验的必不可少的重要环节,是提高程序设计能力和计算机操作技能的有力保障。实验和课程设计等都是加强程序设计训练所必需的实践环节。课程实验要求是,熟练使用一种 Java 开发环境(如 MyEclipse) ,掌握编译、运行和调试 Java 程序的操作,针对不同情况进行软件测试,完善程序并提高程序性能。实验类型有验证和设计两种。验证型实验的要求是,仿制已有例题,验证面向对象程序设计的理论和方法
6、,理解基本原理;设计型实验的要求是,应用图形用户界面、线程、Applet、文件操作和流、网络通信、数据库应用等章的知识点,掌握解决这些实际应用问题的软件设计方法,设计具有一定规模、较复杂、较综合并解决实际问题的应用程序,具备独立分析问题、解决问题的能力和综合应用程序的设计能力。本课程安排的上机实验学时为 16 时,课内开设的 8 个实验说明如下。项 目 内 容 实验时数实验 1 Java 语言基础和面向对象概念训练 2实验 2 接口和实现接口的类,异常处理 2实验 3 图形用户界面 2实验 4 线程设计,线程互斥与同步 2实验 5 输入/输出流,文件操作 2实验 6 URL、TCP Socke
7、t、UDP Socket 等网络通信 2实验 7 JDBC 数据库应用设计 2实验 8 基于 JSP 的 Web 应用设计 2实验题有详细的实验训练目标、设计内容和设计要求。每次实验要求学生独立完成至少一个程序的编写和运行,写出实验报告。实验报告内容包括:题目、题意解释、题意分析、设计方案、流程描述、源程序清单、程序运行结果、程序存在问题和改进意见等。- 3 -第 1 章 Java 概述本章教学内容及要求如下: 了解 Java 语言特点,理解 Java Application 应用程序的运行原理和方法,理解由Java 虚拟机支持的程序运行机制。 掌握在 JDK 环境中编译和运行程序的操作,熟悉
8、在 MyEclipse 集成开发环境中编辑、编译、运行和调试程序的操作。重点:掌握在 JDK 和 MyEclipse 环境中编译和运行 Java Application 应用程序的操作。1.1 了解 Java1-1 Java 具有哪些适合在 Internet 环境中运行的特点?【答】跨平台特性、完全面向对象和简单性、可靠性、安全性、多线程、支持分布式网络应用等。1-2 什么是跨平台特性?Java 怎样实现跨平台特性?【答】跨平台特性是指一个应用程序能够运行于不同的操作系统平台。Java 采用虚拟机技术支持跨平台特性,不同的操作系统上运行不同版本的 Java 虚拟机。1-3 Java 源程序文件
9、编译后生成什么文件?程序的运行机制是怎样的? 【答】Java 将源程序文件(*.java)中的每个类编译生成 一个字节码文件(.class) ,由Java 虚拟机解释执行字节码文件。1-4 Java 应用程序有哪两种形式?它们的运行方式有什么不同?【答】Java 应用程序有两种:Application 和 Applet。Application 是能够独立运行的应用程序,有控制台和图形用户界面两种运行方式。Applet 是可以嵌入 Web 页面的最小应用,它不能独立运行,必须嵌入超文本(*.html )中,由浏览器中的 Java 解释器解释执行。1.2 JDK1-5 环境变量 path 和 cl
10、asspath 的作用分别是什么?【答】path 提供可执行文件(.exe)的路径;classpath 提供类文件(.class)的路径。1-6 什么是包?为什么需要包机制?【答】包(package)是类的集合。包是 Java 区别类名字空间的机制。一个包中的多个类之间不能重名,不同包中的类名则可以相同。- 4 -【习1.3】 为例1.2的Line类增加以下方法:public double length() /返回直线长度int a=start.x-end.x, b=start.y-end.y;return Math.sqrt(a*a+b*b); /Math.sqrt(x)返回 x 的平方根1
11、-7 Java 对源程序文件中的声明语句及文件其命名规则有什么要求?【答】在一个 Java 源程序文件(*.java)中,可以使用 package 语句声明包,使用import 语句导入包,之后使用 class 或 interface 声明多个类或接口。其中,声明为 public 权限的类或接口只能有一个,且文件名必须与该类名相同。1-8 程序中的错误有哪几种?分别在什么时刻被发现?【答】语法错、语义错、逻辑错。编译时能够发现语法错,运行时能够发现语义错,运行时不能发现逻辑错。- 5 -第 2 章 Java 语言基础本章教学内容及要求如下: 掌握 Java 语言的基本语法成分,包括标识符与关键
12、字、数据类型、运算符、表达式、变量声明等语言成分,掌握分支、循环等流程控制语句的语法和使用。特别注意与 C/C+的不同之处。 掌握数组类型的声明和动态内存申请,掌握以基本数据类型和类的两种方式声明和使用字符串。 掌握 Java 语言的方法声明和调用规则,掌握基本类型和引用类型作为方法参数和返回值的传递规则。 掌握 MyEclipse 程序调试技术。重点:数组的引用模型;使用静态方法,引用类型作为方法的参数和返回值。难点:位运算,二进制;递归算法。MyEclipse 程序调试技术。2.1 语言成分1. 数据类型、变量及运算2-1 Java 语言的基本数据类型有哪些?引用数据类型有哪些?【答】基本
13、数据类型有:整数类型 byte、short、int、long,浮点数类型 float、double,字符类型 char,布尔类型 boolean;引用数据类型包括数组(array) 、类(class)和接口(interface) 。2-2 与 C+语言相比, Java 语言的变量和常量声明有什么差别?【答】Java 语言没有全局变量, (成员)局部变量含义及变量声明格式与 C+相同。Java 语言没有宏替换,使用最终变量概念代替 C+中的常量和宏替换。使用 final 关键字声明最终变量,只能赋值一次,这样既增加了常量功能,又避免全局变量和宏替换的副作用。2-3 Java 语言的运算分哪些类型
14、?与 C+语言相比,运算符及运算含义有哪些变化?【答】Java 语言有算术运算、关系运算、位运算、逻辑运算、赋值运算、强制类型转换、条件运算、括号运算、点运算、new、+字符串连接运算和 instanceof 运算等,其中+字符串连接和 instanceof 运算符是 Java 新增的,此外,放弃了 C+的 sizeof 运算符。与 C+语言相比,Java 语言的语法更为严谨,将 C+中某些容易引起混淆的语法做了修订,编译时也将严格进行检查。在 Java 语言中,运算符及运算含义有变化的说明如下。 没有赋值功能的表达式不能作为语句。例如:int i=0;- 6 -i+1; /编译错“无效的赋值
15、运算” 逗号是分隔符,仅用于分隔表达式,不是运算符,不能出现在表达式中。例如:for (int i=0, j=0; i ? A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z | 修改上述程序段的 for 语句表达式如下,输出 Unicode 汉字字符表。for (char ch=u4e00; ch、=、 =0 /value%2+str 即 (char)(value%2+0) + strvalue /= 2;return str; /返
16、回字符串【答】上述算法仅当 value0 时正确;当 value0 时错误,返回 “。为了适用于负数,将上述算法修改如下。2-35 以下方法有什么错误?为什么?public static String toBinaryString(int value) /返回整数 value 的二进制字符串,除 2 取余法if (value=0) return “0“;String str=“;while (value!=0) /除 2 取余法,余数存入 str 字符串(逆序) str = value%2 + str;value /= 2;return str; 【答】上述算法试图将除 2 取余法功能扩展到
17、0 和负数,但算法错误,因为负数采用补码表示而不是原码。例如,当 value=-1 时,value%2= -1,str=“ -1“,value/2=0,循环执行一次,返回“-1“。而“-1“ 的二进制字符串是“11111111 11111111 11111111 11111111“。为了解决该问题,再修改算法如下。- 18 -2-36 以下方法有什么错误?为什么?public static String toBinaryString(int value) /返回整数 value 的二进制字符串,除 2 取余法if (value=0) return “0“;String str=“;while
18、(value!=0) /除 2 取余法,余数存入 str 字符串(逆序) str = (char)(value%2+0) + str;value /= 2;return str; 【答】上述算法错误,value=-1 时,value%2 结果为-1, (char)(value%2 +0)结果为/(0的前一字符) ,所以不行。 转换成 radix 进制字符串,2radix 162-37 以下方法有什么错误?为什么?/返回正整数 n 的 radix 进制字符串,2radix16,采用除 radix 取余法public static String toString(int value, int ra
19、dix) String str=“;while (value0) /除 radix 取余法,余数存入 str 字符串(逆序) int bit = value % radix;str = (bit0 时执行,当 value0 时,返回“ 。(2) 位运算,转换成二进制字符串 采用字符串连接运算以下声明 toBinaryString(int)方法返回一个 int 对应的 32 位,正数或 0 的高位以 0 填充。算法采用位运算,一个 int 整数即是一个由 32 位 bit 组成的无符号整数,每次获得二进- 19 -制的最高位,将其转换为数字字符,再顺序连接成字符串。算法如下。public sta
20、tic String toBinaryString(int value) /返回整数 value 的二进制字符串。采用位运算String str=“;for (int i=0x80000000; i!=0; i=1) /从高位向低位逐位获取,每右移一位,高位补0str += (value /获得各位字符return str;该算法正确,但将非 0 值算作 1,该算法不具有扩展性,不适合 8 和 16 进制。修改算法如下,每次获得二进制的个位,将其转换为数字字符,各位数字字符按反序连接成字符串。public static String toBinaryString(int value) /返回整
21、数 value 的二进制字符串String str=“;for (int i=0; i=1; /value 右移一位,高位以 0 填充,即 value 除以2return str; 由于 String 是常量字符串,字符串连接运算需要重新申请数组空间并复制原字符串,因此频繁调用字符串连接运算,效率很低。 采用字符数组为了提高效率,采用字符数组代替字符串连接运算,修改上述算法如下:public static String toBinaryString(int value) /返回整数 value 的二进制字符串char buffer = new char32; /一个 int 有 32 个二进制
22、位for (int i=buffer.length-1; i=0; i-) /循环执行 32 次,高位补 0 bufferi = (char)(value /获得个位字符存入数组。 /value 右移一位,高位以 0 填充,即 value 除以2return new String(buffer); /返回由字符数组构造的字符串其中,value 多次运行结果如下:MyInteger.toBinaryString(126)=00000000000000000000000001111110MyInteger.toBinaryString(-128)=1111111111111111111111111
23、0000000MyInteger.toBinaryString(-1)=11111111111111111111111111111111【思考题】实现以下方法。public static String toOctalString(int value) /返回整数 value 的八进制字符串public static String toHexString(int value) /返回整数 value 的十六进制字符串(3) 位运算,转换成 radix 进制字符串MyInteger 类增加声明 toString(int value, int radix)方法如下,算法实现见教材例 2.10。/返回
24、整数 value 的 radix 进制字符串,radix 取值为 2、4、8、10、16。采用位运算public static String toString(int value, int radix)调用语句如下:int value = Integer.MIN_VALUE; /整数最小值System.out.println(“MyInteger.toString(“+value+“,16)=“+MyInteger.toString(value,16);程序运行结果如下:MyInteger.toString(-2147483648,16)=80000000(4) byte 整数的二进制字符串2
25、-38 以下方法有什么错误?为什么?public class MyBytepublic static String toBinaryString(byte value) /返回 byte 整数 value 的二进制字符串String str=“;for (byte i=-128; i!=0; i=1)str += (value return str; 【答】算法错,死循环。因为,-128 的二进制为 11 10000000,i=1,高位以 1填充,i!=0 条件永远成立,死循环。Java 的整数默认是 int 类型,byte 类型只是形式上的,所有 byte 整数运算是 int 类型运算后 截
26、尾,即(byte)-128 的二进制同(int)-128,所以即使修改如下,仍然不行。 for (byte i=(byte)-128; i!=0; i=1) /不行,(byte)-128 的二进制同(int)-128所以,如下修改算法正确,只返回 8 位二进制位字符串。for (int i=0x00000080; i!=0; i=1)- 21 -实验 2 Java 程序设计基础增加实验题如下。2-39 分别采用循环和递归方法输出以下数字塔(行数可变):11 2 11 2 3 2 11 2 3 4 3 2 12-40 实现以下算法,数组作为方法的参数或返回值。public static int
27、max(int value) /返回数组元素最大值public static int min(int value) /返回数组元素最小值public static int indexOf(int value, int key) /返回 key 在 value 数组中的序号public static int randomDifferent(int n, int max) /产生 n 个 max 以内的互异随机数public static boolean isSorted(int value) /判断 value 数组是否已按升序排序public static void sort(int valu
28、e) /数组按升序排序,冒泡排序等算法public static int random(int m, int n, int max) /产生 mn 个 max 以内随机数,返回二维数组2-41 将一维数组中的元素序列输出成循环移位方阵,可指定移位方向和移动位数。例如,将7,4,8,9,1,5序列元素按右移一位方式输出的循环移位方阵如下:7 4 8 9 1 55 7 4 8 9 11 5 7 4 8 99 1 5 7 4 88 9 1 5 7 44 8 9 1 5 72-42 输出螺旋方阵。螺旋方阵将从 1 开始的自然数由方阵的最外圈向内螺旋方式地顺序排列。例如 4 阶的螺旋方阵排列形式如下:1
29、 2 3 412 13 14 511 16 15 610 9 8 72-43 找出一个二维数组的鞍点。鞍点指某数组元素的值在该行上最大、在列上最小。也可能没有鞍点。2-44 实现杨辉给出的构造任意阶幻方的算法。2-45 用递归方法求 n 个数的无重复全排列。2-46 实现以下对字符串操作方法。public static String upperFirst(String str) /将 str 中每个单词的首字母改为大写形式public static int count(String str, char ch) /返回 ch 字符在 str 字符串中出现的次数public static Stri
30、ng split(String str, char ch)- 22 -/以 ch 字符为分隔符分解 str 字符串,返回分解后的字符串数组2-47 找出两个字符串中所有共同的字符。- 23 -第 3 章 类的封装、继承和多态本章教学内容及要求如下: 掌握类的声明格式和多种封装措施,理解对象的引用模型。 掌握类的继承原则,正确使用重载和覆盖等多态概念设计可复用方法,理解运行时多态。 掌握声明抽象类和最终类的方法,理解抽象类和最终类的作用。 理解 Java 包的概念和作用,掌握 JDK 创建自定义包、声明导入包的方法;掌握在MyEclipse 集成开发环境中,通过设置编译路径引用其他项目中声明的类
31、。重点:类的封装、继承、多态和抽象性等面向对象的概念及原理,包括类的封装、继承原则,重载和覆盖等多态概念,运行时多态性。难点:继承,运行时多态。3.1 类和对象【习3.1】 交换变量与对象问题讨论。本例讨论交换两个变量值问题,说明基本类型和引用类型在作为方法形式参数时的参数传递原则。交换两个变量值是应用程序设计中经常遇到的一个问题,这个问题的关键是一个方法如何返回两个变量值。在 C+语言中可将参数设计成指针( *)或引用(x = y;y = temp;main()中调用语句如下:int i=1, j=2; swap(i, j); /i、j 是实际参数调用 swap(i, j)方法,将实际参数
32、i、j 的值传递给形式参数 x、y;在方法体中交换了x、y 的值,并未改变实际参数 i、j ,如图 3.1 所示。因此,上述 swap()方法不能实现交换两个实际参数变量值的功能。- 24 -图 3.1 基本类型的函数参数调用时传递值 以下 swap()方法不能交换两个实际参数对象所引用的实例public static void swap(Object x, Object y) Object temp=x; x=y; y=temp; 例如,调用语句如下,swap(Object x, Object y)方法只是交换了两个形式参数 x、y 的对象引用,并未改变实际参数对象 i、j 所引用的实例,执
33、行过程如图 3.2 所示。Integer i = new Integer(1);Integer j = new Integer(2);swap(i, j);1i( a ) m a i n ( ) 方 法 中 实际 参 数 i 、 j 引 用 对 象2j( c ) 交 换 形 式 参 数 x 、 y 引 用 的 对 象 ,没 有 改 变 实 际 参 数 i 、 j 引 用 的 对 象1i( b ) s w a p ( ) 方 法 中 形 式 参 数 x 、y 获 得 实 际 参 数 i 、 j 引 用 的 对 象2jxy1i2jxy图 3.2 对象作为方法参数时传递引用当对象作为方法参数时,参数
34、传递的是引用,功能同两个对象引用赋值。上述 swap(x, y)方法只在方法体内交换了两个形式参数 x、y 引用的对象,并没有改变实际参数 i、j 引用的对象。因此,上述方法不能交换两个对象所引用的实例。swap(Object x, Object y)方法相当于 C/C+下列函数功能,它交换的是作为形式参数的两个指针变量 x、y 存储的地址,即交换了 x、y 所指向的变量,但没有交换 x、y 所指向变量的值,与图 3.2 功能相同。void swap(int* x ,int* y) int *temp=x;x=y;y=temp; 能够交换两个数组元素值public static void sw
35、ap(int table, int i, int j) /交换 tablei、tablej值if (table!=null date.year+;while (n365) /按年计算 n-= date.isLeapYear() ? 366 : 365;date.year+;return date;- 28 -3.3 类的继承性3-6 Java 声明 Object 类的作用是什么?Object 类中声明了哪些方法?Object 类在 Java类层次体系中的地位是怎样的?【答】Object 类声明所有类共用的方法,方法有 equals()、toString()等。根类。3-7 new Person
36、() instanceof Object 运算结果是_,理由是_。【答】true ,任何类都是 Object 的子类,子类对象即是父类对象。【习3.9】 类的继承性问题讨论。本例讨论类的继承性,包括构造方法的继承性、私有成员的继承性和访问权限、最终变量的继承性。 父类声明。public class Personprivate final String name; /父类私有成员,最终变量private int age;public Person(String name,int age)this.name = name; /正确,最终变量只能被赋值一次this.age = age; public
37、 Person() this(null,0); public void setAge(int age) this.age = age; public String toString() return this.name+“, “+this.age+“岁“; 注意:不能声明以下方法。public void setName(String name) this.name = name; /编译错,无法为最终变量 name 再次赋值 子类没有声明构造方法时,有默认构造方法。public class Student1 extends Personpublic static void main(String args)