描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302499633丛书名: 21世纪高等学校计算机专业实用规划教材
基础篇,介绍Java的基础语法;
核心篇,介绍Java的核心技术,包括类和对象、继承和接口、数据容器等;
实践篇,通过4个大型开发案例,介绍Java的界面设计技术、流和文件、线程和网络通信、数据库访问、JavaFX等。
教材基于*的Java技术和平台,在NetBeans下介绍,包括JavaFX。
目录
第1章Java概述
1.1Java的发展过程
1.1.1Java技术的形成
1.1.2Java的成熟和发展
1.2Java技术
1.2.1Java的技术特点
1.2.2Java的相关技术
1.3Java开发平台
1.3.1JDK和IDE下载安装
1.3.2NetBeans简介
1.3.3创建Java项目
1.4Java源程序
1.4.1Java程序结构
1.4.2Java语句排列
1.5Java类库
1.5.1类库引用
1.5.2Java类库简介
1.5.3类文档
第2章Java表达式
2.1变量
2.1.1标识符
2.1.2基础数据类型
2.1.3变量声明
2.1.4常量
2.2数组
2.2.1数组和数组元素
2.2.2数组的声明
2.2.3多维数组
2.3表达式
2.3.1赋值语句
2.3.2运算符分类和运算形式
2.3.3运算优先级
2.3.4运算数据类型
2.4运算符
2.4.1算术运算
2.4.2关系运算
2.4.3逻辑运算
2.4.4位运算
第3章常用类
3.1类的引用
3.1.1类和对象
3.1.2引用类型
3.1.3类库的引用
3.2Math类
3.2.1三角函数方法
3.2.2指数函数方法
3.2.3其他函数方法
3.2.4random方法
3.3String类
3.3.1构造字符串
3.3.2获取字符串信息
3.3.3字符串连接与比较
3.3.4字符串分割与转换
3.4控制台输入输出
3.4.1控制台输入输出类
3.4.2Scanner类
3.4.3Console类
3.4.4输出方法
第4章流程控制
4.1顺序结构
4.1.1程序结构
4.1.2顺序结构
4.1.3变量作用域
4.2选择结构
4.2.1if语句
4.2.2switch语句
4.3循环结构
4.3.1for循环
4.3.2while循环
4.3.3程序重定向
4.4综合应用
4.4.1猜数游戏
4.4.2排序
4.4.3查找
第5章类和对象
5.1面向对象程序设计
5.1.1面向对象的概念
5.1.2面向对象的特性
5.2创建自己的类
5.2.1类的结构
5.2.2成员变量
5.2.3成员方法
5.2.4构造方法
5.2.5main()方法
5.3对象的创建和使用
5.3.1对象的创建
5.3.2对象的使用
5.3.3形参和实参
5.3.4this关键字
5.4实例成员与类成员
5.4.1static关键字
5.4.2实例变量和类变量
5.4.3实例方法和类方法
5.4.4静态代码块与构造代码块
5.5内部类
5.5.1内部类的概念
5.5.2成员内部类
5.5.3局部内部类
5.5.4静态内部类
5.5.5匿名内部类
第6章继承和接口
6.1继承
6.1.1类的层次结构
6.1.2类继承的实现
6.1.3super关键字
6.1.4final关键字
6.1.5Object类
6.2抽象类
6.2.1抽象类的定义
6.2.2抽象类的实现
6.2.3Number抽象类
6.3接口
6.3.1接口的定义
6.3.2接口的实现
6.3.3CharSequence接口
6.4多态
6.4.1方法的覆盖
6.4.2变量的隐藏
6.4.3instanceof关键字
6.4.4接口对象的实例化
第7章异常处理
7.1异常的基本概念
7.1.1异常的产生
7.1.2异常的处理
7.2异常类
7.2.1Throwable类
7.2.2Exception类
7.3处理异常
7.3.1捕获并处理多种异常
7.3.2异常与资源管理
7.4抛出异常
7.4.1方法体中抛出异常(throw)
7.4.2方法声明中抛出异常(throws)
7.4.3使用异常的原则
7.5编写自己的异常类
第8章数据容器
8.1泛型
8.1.1泛型的声明
8.1.2泛型的使用
8.1.3泛型环形队列的实现
8.2枚举
8.2.1声明枚举类型和枚举对象
8.2.2枚举的使用
8.3集合框架
8.3.1迭代器接口Iterable
8.3.2集合接口Collection
8.4列表
8.4.1List继承结构
8.4.2List实现类
8.4.3LinkedList测试
8.4.4Stack测试
8.5集
8.5.1Set继承结构
8.5.2Set的实现类
8.5.3Set测试
8.6队列
8.6.1Queue继承结构
8.6.2Queue的实现类
8.7映射
8.7.1Map继承结构
8.7.2Map的实现类
8.7.3Map测试
第9章设计一个计算器
9.1JFC概述
9.1.1AWT和Swing
9.1.2容器与组件
9.2容器类
9.2.1窗口
9.2.2JPanel类
9.3常用组件
9.3.1JButton
9.3.2Label
9.3.3JTextField
9.4事件处理
9.4.1事件
9.4.2事件处理
9.4.3GUI综合应用
9.5计算器的设计与实现
9.5.1计算器界面设计
9.5.2框架初始化
9.5.3事件处理程序
第10章文本编辑器设计
10.1文件
10.1.1File类
10.1.2文件顺序读写
10.1.3文件随机读写
10.2界面布局设计
10.2.1自由设计
10.2.2布局设计
10.2.3布局类型
10.2.4综合布局
10.3需要的组件
10.3.1文件选择器
10.3.2颜色选择器
10.3.3字体
10.3.4标准对话框
10.3.5打印
10.4编辑器实现
10.4.1组件表
10.4.2初始化
10.4.3事件驱动方法
第11章网络聊天室设计
11.1网络通信
11.1.1服务器(Server)和客户端(Client)
11.1.2InetAddress类
11.1.3URL
11.1.4Socket类
11.1.5ServerSocket类
11.1.6TCP通信测试
11.2多线程
11.2.1线程
11.2.2线程调度
11.2.3线程同步
11.2.4线程控制
11.3界面设计
11.3.1布局设计
11.3.2界面外观
11.3.3文本组件JTextPane
11.3.4列表组件JList
11.3.5组件列表
11.4软件设计
11.4.1软件线程
11.4.2消息处理
第12章Web应用系统设计
12.1数据库
12.1.1JDBC
12.1.2连接数据库
12.1.3数据库分析
12.1.4数据库操作
12.2JavaFX
12.2.1JavaFX简述
12.2.2JavaFX入门
12.2.3JavaFX界面设计
12.2.4JavaFX事件处理
12.3JavaFX设计案例
12.3.1数据库设计
12.3.2界面设计
12.3.3实现代码
12.3.4JavaFX部署
前言
Java程序设计技术是当前计算机程序设计中使用最广泛的程序设计语言,本书作为面向高校的本科生的教材和面向工程开发人员的参考书,全面介绍Java的程序设计技术。本书的主要特点在于其内容组织方式,在本书的12章中,将Java的全部内容分为三部分: 基础篇、核心篇和实践篇。其中前两部分按照内容组织,第三部分通过实际的开发案例组织。1) 基础篇基础篇内容包括Java的技术概括、开发平台、表达式、流程控制和基础类等内容。本书采用集成开发平台NetBeans,这相比命令行方式具有更高的开发效率。本部分的重要内容是基础数据类型、表达式和流程控制语句,在基础类一章主要介绍String类、Math类,以及JDK中的控制台输入和输出方法。2) 核心篇本部分介绍面向对象的核心技术,以及异常处理和数据容器技术。作为一门纯面向对象的程序设计语言,学习Java的类和对象、继承与接口的实现是掌握面向对象程序设计的关键,同时也是熟练使用Java类库的基础。本书强调使用Java类库,细致了解Java类库结构是实现一个工程开发必不可少的学习环节。在数据容器一章介绍了Java的各种高级数据组织方式,包括枚举、泛型、列表、集、队列和映射等内容,Java类库在数据容器方面提供了丰富和多样化的支持。3) 实践篇本部分是本书的重要特色之一,通过四个实际开发案例贯穿了Java的主要实用化内容。案例的组织方式更接近工程开发,同时相比于传统的按内容组织方式,通过案例教学也更容易理解和掌握这些内容。在Java的界面设计方面,在计算器设计、文本编辑器设计和Web应用设计中分别进行了不同的介绍,在计算器设计中介绍基本的组件和事件驱动方法,在文本编辑器中介绍了界面布局技术,在Web应用设计中介绍了JavaFX界面设计技术。在文本编辑器设计一章中重点介绍了Java的流和文件技术,并最终设计实现了一个支持多种编码标准的实用化的文本编辑器。在网络聊天室设计一章重点介绍网络通信和多线程技术,并最终设计实现了一个简易的文本信息网络聊天室软件。在Web应用系统设计中重点介绍Java的数据库技术和JavaFX,并介绍了通过工具软件JavaFX Scene Builder实现界面设计的方法,实现了在完全不需要了解JavaFX的FXML脚本语言的情况下实现界面设计,最终设计实现了一个网络课程作业提交系统软件。本书作为高校教材,如果讲授全部内容,推荐学时为64学时。如果采用48学时,推荐讲授内容为前7章和第9章。在48学时教学过程中建议实验6~7个,全部实验在NetBeans下完成,分别是表达式实验、类库实验、流程控制实验、类和对象实验、继承和接口实验、界面设计实验。本书作者多年从事Java课程教学,设计有教学测试题库和实验题库,可以实现随机抽题作业和单元测试。本书由周洪利、许宏丽、周围编写,其中周洪利编写第1、2、8、10、11、12章,许宏丽编写第3、4、9章,周围编写第5、6、7章。由于时间仓促,作者水平有限,可能存在疏漏之处。在此,诚恳期望得到各领域的专家和广大读者的批评指正。题库课程获取步骤(1) 打开手机微信“扫一扫”,扫描书后刮刮卡的权限二维码,即可获取权限。(2) 再扫描每一章末的题库二维码,即可在线做题并提交查看结果。
作者2018年5月
类(class)和对象(object)都是面向对象程序设计的最重要的概念之一,要深入了解Java程序语言,一定要先了解面向对象程序设计的概念和方法。本章开始学习Java程序中类和对象的设计和使用。学习完本章以后,你将能够: 理解类和对象的基本概念; 掌握类的声明; 掌握成员变量、成员方法、构造方法的使用; 掌握对象的创建和使用; 掌握实例成员和类成员的作用范围; 理解内部类的概念和使用。5.1面向对象程序设计随着计算机技术的发展以及所要解决问题的复杂性的不断提高,以往的“面向问题”“面向过程”的程序设计方法已经不能再适应这种发展的需求。从20世纪70年代开始,相继出现了多种面向对象的程序设计语言,并逐渐产生了面向对象的程序设计方法。5.1.1面向对象的概念面向过程是一种以事物为中心的编程思想,即分析出解决问题所需的步骤,然后用函数来逐步实现这些步骤,使用时再依次调用。面向过程的特点是以函数为中心,用函数来作为划分程序的基本单位。数据在面向过程设计中往往处于从属地位,它是一种自顶向下逐步求精的设计方法,是单入口单出口的程序结构,强调处理问题的过程。从开始起,按照程序流程,以某种顺序经过某个过程阶段,然后获得预期的结果。面向对象则是把构成问题的事务分解成各个对象,建立对象的目的不是完成一个步骤,而是为了描述某个事物在整个解决问题步骤中的行为。面向对象设计以数据为中心,类是表现数据、划分程序的基本单位,函数在面向对象设计中成为类的接口。类中定义的变量是描述这一类对象的属性,类中定义的方法是描述它们共同的行为,实现对类中数据变量的操作,利用对象间的消息传递来驱动程序的执行。类是一种抽象数据类型,定义了对象特征以及对象外观和行为的模板,是同一组对象的集合与抽象。对象也称类的一个实例,是现实中某个具体的物理实体在计算机逻辑中的映射和体现,具有所在类定义的全部属性和方法。例如,学校有很多学生,“学生”是一个类,包含了所有在学校学习的人。“李明”这位学生就是一个对象。面向对象程序设计技术的核心,是使用类来实现对某一类事物的封装和模块化以及信息隐藏,有利于提高程序的可移植性和安全性,使程序易于维护,简化了对复杂对象的管理。面向对象的方法与传统的过程方法相比,更符合人们的思维习惯,同时其可扩展性、重用性也是面向对象程序设计的优点。Java是一种面向对象的编程语言。面向对象程序设计的主要任务是设计用来解决各种实际问题的类,用这些类来创建对象,并使用对象来实现各种功能。5.1.2面向对象的特性面向对象的程序设计具有三个重要特性: 封装、继承、多态。1. 封装封装(Encapsulation),也称为数据隐藏,就是把客观事物封装成抽象的类,类可以只让可信的类或者对象操作自己的数据和方法,而对不可信的类或对象进行信息隐藏。简单地说,就是把行为和属性集中到一个统一的类中,并对使用者屏蔽其中的细节问题。例如,声明一个学生类,具有姓名、性别、所学专业等属性,具有上课、考试等行为,但使用时不需要考虑学生的专业选择的依据、上下课的路程等背后的问题。 2. 继承继承(Inheritance)也是面向对象程序设计中最重要的特性之一,继承是类之间的一种关系,可以认为是分层次的一种手段。多个类中存在相同属性和行为时,将这些内容抽取到一个的单独类中,这样多个类无须再重新定义这些属性和行为,只要继承那个类即可。多个类可以称为子类,将单独这个类称为父类或者超类。子类可以直接地访问父类中非私有的属性和行为。引入继承可以减少重复的代码量,从而提高代码和开发的效率。例如,学生类可以继承自“人”这个类,这个类具有姓名、性别等属性,学生类可以继承这些属性,不需要自己再单独声明。老师类也可以继承自“人”这个类,同样继承了这个类的姓名、性别等属性。3. 多态多态(Polymorphism)是面向对象的重要特性之一,它是具有表现多种形态的能力的特征。简单地说,就是“一个接口,多种实现”,即同一个接口,可以通过使用不同的实例来执行不同的操作。程序设计是将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来,再通过这个抽象的事物,与不同的具体事物进行对话。例如,老师类和学生类都具有上课这个行为,每个类赋予了上课的不同操作。 面向对象程序设计的三大特征如表51所示。
表51面向对象的三大特征
特征特点优势封装隐藏实现细节,对外提供公共的访问接口增强代码的可维护性继承从一个已有的类派生出新的类,子类具有父类的一般特性,以及自身特殊的特性增强代码的可复用性多态同一个实现接口,使用不同的实例而执行不同的操作增强代码的可扩展性、可维护性
5.2创建自己的类面向对象的程序设计是以类为基础,Java程序由类构成,一个Java程序包含一个或一个以上的类。5.2.1类的结构如前所述,类是对现实世界中实体的抽象,类是一组具有共同特征和行为的对象的抽象描述。因此,一个类的定义包括如下两个方面: (1) 定义属于该类对象共有的属性(属性的类型和名称,即变量); (2) 定义属于该类对象共有的行为(所能执行的操作,即方法)。类的结构包含类的声明和类体两部分,一般格式如下:
//类声明
[访问限定符] [修饰符] class 类名 [extends 父类名] [implements接口列表] {
//变量
//方法
}
对类声明的格式说明如下: 访问限定符,确定该定义类可以被哪些类使用。可用的访问限定符及含义如表52所示。
表52访问限定符
访问限定符含义public公共,可以在所有类中使用无访问限定符系统默认,可以被本类、本类所在包中的类访问protected保护,可以被本类、子类、所在包中的类访问private私有,只能在本类中访问
修饰符,确定该类如何被其他类使用。可用的类修饰符如表53所示。
表53类声明里的修饰符
修饰符含义abstract说明该类是抽象类,详见第6.2节final说明该类是最终类,详见第6.1节
class是关键字,声明类的标志,告诉编译器这是一个类。类名则是该类的名字,类名的含义应该明确,符合Java标识符使用规范。一般情况下单词首字母要大写,如果类名是由多个单词组成的,每个单词的第一个字母都要大写。 后置修饰符,说明此类和其他类的关系。类声明里的后置修饰符如表54所示。
表54类声明里的后置修饰符
修饰符含义extends后面跟父类名,说明所定义的类是该父类的子类,它将继承该父类的属性和行为。关于继承详见第6.1节implements后面跟接口名表,是接口名的一个列表说明,说明所定义的类要实现列表中的所有接口。一个类可以实现多个接口,接口名之间以逗号分隔。关于接口详见第6.3节
类体中包含类变量和方法的声明及定义,类体以定界符左花括号“{”开始,右花括号“}”结束。类的变量和方法的声明将在下面各节中进行详细的讨论。5.2.2成员变量表明类的属性的变量称为成员变量。在类体的内部、方法的外部声明,一般放在类体的开始部分。声明或定义成员变量的一般格式如下:
[访问限定符] [修饰符] 数据类型 成员变量名[=初始值];
其中: 访问限定符,用于限定成员变量被其他类中的对象访问的权限,参见表52。 修饰符,用来确定成员变量的如何使用。成员变量使用的修饰符如表55所示。
表55成员变量使用的修饰符
修饰符含义static表明声明的成员变量为静态的,静态成员变量的值可以由该类所有的对象共享。详见5.4节final表明声明的成员变量是一个最终变量即常量,一旦赋值不可修改
数据类型,可以是基础数据类型(详见第2章),也可以是类、数组等引用类型,表明了成员变量的数据类型。用以下程序来声明学生类的成员变量,主要包括姓名、性别、出生年月、学生编号、所在班级编号等。在成员变量声明中,除出生年月被声明为日期型(Date)外,其他均为字符串型。由于Date类被放在java.util类包中,所以在类定义的前边加上import语句。
行号例51Student类的部分代码1package javaobjectdemo;//本程序文件所在的包2import java.util.*; //使用Java类库3public class Student {4//以下声明成员变量5String name;6String sex;7Date brithday; //这是一个日期类的成员变量8String ID;9String classNo;10}
以上就在学生类里加入了成员变量。将自己编写的类按功能放入相应的包中,以便在其他的应用程序中引用,这是面向对象程序设计最基本的要求。可以使用package语句将编写的类放入一个指定的包中,包名应符合标识符的命名规则,包名习惯上使用小写字母来书写。该语句必须放在整个源程序第一条语句的位置(注解行和空行除外)。语句的一般格式如下:
package 包名;
本章的例题将类文件代码放入一个包javaobjectdemo中,在每个源程序文件中的开头添加一条如下语句:
packabe javaobjectdemo;
5.2.3成员方法方法是用来描述对象的行为,类的方法可分为构造方法和成员方法,本小节先介绍成员方法。方法也包含两部分:方法声明和方法体。方法定义的一般格式如下:
[访问限定符] [修饰符] 返回值类型 方法名([形参列表]) {
//变量声明
//程序代码
//return返回值代码
}
在方法声明中: 访问限定符,用于限定成员方法被其他类中的对象访问的权限,同表52。 修饰符,用于表明方法的使用方式。可用于方法的修饰符如表56所示。
表56成员方法使用的修饰符
修饰符含义abstract说明该方法是抽象方法,即没有方法体(只有“{}”引起的空体方法)。详见第6.2节final说明该方法是最终方法,即不能被覆盖,详见第6.4节static说明该方法是静态方法,可通过类名直接调用。详见第5.4节
返回值类型是合法的Java数据类型。方法可以返回值,也可不返回值,可视具体需要而定。当不需要返回值时,可用void指定,代表空值,不能省略。当有返回值时,可在方法内的程序中加上return语句用于返回值。 方法名,方法的名字,应符合Java标识符命名规范,一般首字母小写。 形参列表,方法的参数(详见第5.3节)。若没有参数时,()不能省略; 若有两个及以上参数时,用“,”号分隔各参数。说明参数时,应声明它的数据类型。 方法还可以使用throws关键字抛出异常,异常的概念详见第7章。在程序设计中,成员方法中的方法体是完成行为的操作代码。根据具体需要,有时会修改或获取对象的某个属性值,也会访问列出对象的相关属性值。下面还以学生类为例,来介绍成员方法的应用,在类中加入设置名字、获取名字和列出所有属性值这三个成员方法。
行号例52文件Student.java代码1package javaobjectdemo;2importjava.util.*;3publicclassStudent {4//以下声明成员变量5String name;6String sex;7Date birthday;//这是一个日期类的成员变量8String ID;9String classNo;10//以下声明成员方法11//取得名字的方法getName12public String getName(){//getName()方法体13return name;//返回名字14} 15//设置名字的方法setName16public void setName(String name) {//setName()方法体17this.name = name;//通过参数设置名字18}19//显示所有属性的方法displayAll20public void displayAll() {//displayAll()方法体21System.out.println(“姓名: ” name “,性别: ” sex “,生日: “22 String.format(“%tF”,birthday) “,编号: ” ID “,所在班级: ” 23classNo);24}25}
在上述的三个成员方法中,两个方法setName和displayAll方法的返回值为void,表明无返回值; 一个方法getName有返回值,返回值的数据类型为String。在显示属性方法中,出生年月的输出使用了将日期转换为字符串的转换方法String.format()。另外需要说明的是,在方法setName()中使用的关键字this,代表当前对象,this的用法详见第5.3节。可以在一个类中定义多个相同名字的方法,但每个方法需具有不同的参数和不同的代码,来实现不同的功能,称为方法的重载。当方法被调用时,Java是用参数的类型和数量来判断实际调用的方法,方法的重载是Java多态特性的表现方式之一。 5.2.4构造方法构造方法是一种特殊的成员方法,主要用于对象的初始化工作。需要严格按照构造方法的格式来编写构造方法,否则构造方法将不起作用。如果在类中没有编写构造方法,在创建对象时,系统使用默认的构造方法。构造方法的一般格式如下:
[public] 构造方法名([参数列表]){
//构造方法体
}
在上述的学生类代码中添加如下构造方法语句:
行号例53在Student.java中添加构造方法1public Student(String name) {//一个参数的构造方法2this.name = name;3}4//多个参数的构造方法5public Student(String name, String sex, Date brithday, String ID, String classNo) {6this(name);//调用Student(String name)构造方法7this.sex = sex;8this.birthday = brithday;9this.ID = ID;10this.classNo = classNo;11}
与一般的成员方法相比,构造方法具有以下特征: (1) 构造方法的名字就是类名,与类名完全一致。(2) 构造方法的访问属性默认和类的访问属性保持一致。一般声明为public或默认。如果默认,则只能在同一个包中使用。(3) 构造方法没有返回值,不能使用return语句。(4) 构造方法的调用形式特殊,在使用new创建对象时,应由编译器自动调用,详见第5.3节。(5) 可以有多个同名的构造方法,即方法的重载。类中的构造方法可以根据需要来重载多个参数列表的不同构造方法,这些重载的构造方法也可以相互调用。以学生类为例,在类中加入两个Student的构造方法,但是参数不同。在引用时根据参数来判断使用哪一个。5.2.5main()方法main()方法是一个特殊的方法,称为主方法。在Java应用程序中可以有许多类,每个类也可有许多方法,但是解释器在装入程序后首先运行的是main()方法。main()方法与其他的成员方法相比有一些自己的特点,其格式如下:
public static void main(String [] args) {
//主方法体
}
其中: 由public关键字修饰,让解释器能够访问到它。 由static关键字修饰,表明是一个静态方法、类方法,详见第5.4节。 void表明它无返回值。 带有一个字符串数组参数(String [] args),一般从装入运行程序的命令行开始传递参数。其一般格式如下:
java 程序名 参数列表
当参数列表包含多个参数时,参数之间以空格分隔,每个参数都是一个字符串。需要注意的是,如果某个实参字符串中间包含空格,应以定界符双引号将它们引起来。参考上述的学生类代码,添加如下main方法语句来使用学生类。
行号例54main方法示例1public static void main(String[] args) {2Student stu1,stu2;3stu1 = new Student(“张明”,”女”,new Date(“1/24/98″),”0001″,”设计1班”);4stu2 = new Student(“王华”,”男”,new Date(“10/30/99″),”0002″,”设计1班”);5stu1.displayAll();6stu2.setName(“李华”);//调用方法更正对象的名字7stu2.displayAll();8}
语句的解释详见第5.3节。Java程序是以类为基本单位,通过上述类的声明、成员变量、成员方法、构造方法、主方法,就构成了基本的程序架构。至此,我们简要地介绍了类的结构并完成了一个简单的学生类的定义。另外,还需要了解类和文件的关系。一个Java应用程序是由若干个类组成,这些类可以存在一个源文件中,也可以分布在多个源文件中。其中含有main方法的类称为主类,main方法是程序执行的入口,即要执行一个Java应用程序就必须从main方法开始执行。每个源文件编译后会产生若干个类的字节码文件(.class文件)。当运行一个Java应用程序时,Java虚拟机会将字节码文件加载到内存中,再由Java虚拟机解释执行。当管理一个大的应用程序时,需要将这些源文件和资源(图片、声音、数据文件等)放到不同的目录中,于是就有了包的概念,详见第1.5节。创建程序时,有时并没有创建过包,程序也可以正常执行,这是因为如果在程序中没有指定包名,系统就默认为是无名包。无名包中的类可以相互引用,但不能被其他包中的Java程序引用。对于简单的程序,使用或不使用包名也许没有影响,但对于一个复杂的应用程序来说,如果不使用包来管理类,将会给程序的开发带来很大的混乱。5.3对象的创建和使用上节定义的学生类,是从现实的“学生”类中抽象出来的模板,要处理一个具体学生的具体信息,必须按这个模板构造出一个具体的学生,这就需要创建Student类的一个实例,实例也称作对象。5.3.1对象的创建一般来说,创建对象需要以下三个步骤。(1) 声明对象。在声明对象后,系统还没有给对象分配存储空间,只是建立了空的引用,通常称之为空对象(null)。这时对象还不能使用。声明对象的一般格式如下:
类名 对象名; //声明对象
(2) 创建对象,也称为实例化对象。对象只有在创建后才能使用。创建对象的一般格式如下,其中类构造方法名就是类名,new运算符用于为对象分配存储空间,它调用构造方法,获得对象的引用(即对象在内存中的地址)。
对象名=new 类构造方法名([实参列表]); //创建对象
声明对象和创建对象也可以合并为一条语名,其格式如下。
类名 对象名 = new 类构造方法名([实参列表]); //声明和创建对象
(3) 引用对象,在创建对象之后,就可以引用对象了。引用对象的成员变量或成员方法需要对象运算符“.”。在创建对象时,某些属性没有确定的值,可以通过引用对象来修改这些属性值。
对象名.成员变量名 //引用成员变量的一般格式
对象名.成员方法名([实参列表]) //引用成员方法的一般格式
程序中定义的对象,在被创建和使用后,一旦超出了它们的作用范围(例如方法执行完成)就会被抛弃,但其所占的空间不会立即被收回。在Java中,程序员不需要考虑跟踪每个生成的对象,系统会采用自动垃圾收集的内存管理方式,通过垃圾收集器周期性地清除无用对象并释放它们所占的内存空间。垃圾收集器作为系统的一个线程运行,当内存不够用时或当程序中调用了System.gc()方法要求垃圾收集时,垃圾收集器便开始工作。Java也为每个对象提供一个撤销对象的特别方法finalize(),当一个对象被最终撤销并释放其所占内存时,是由虚拟机自动调用。5.3.2对象的使用本小节介绍两个简单的示例,以便于加深理解前边所介绍的类的声明、对象声明和创建、类和文件的关系等一些基本概念。 [例1]编写两个文件: Student.java和StudentDemo.java。其中Student.java是用来声明一个Student类,参考上节中的代码。为了说明类和文件的关系,在Student.java文件中,仅需声明类和成员变量、成员方法、构造方法,没有主方法。StudentDemo.java是用来测试Student类的功能,存在主方法,程序会从这个主方法入口进入执行,其主要作用是创建Student对象并显示对象的属性值,这个文件只有主方法,没有其他的成员变量和成员方法。两个文件在一个包中,可以互相使用。
行号例55Student类的测试类StudentDemo1package javaobjectdemo;2import java.util.*;3public class StudentDemo {4public static void main(String[] args) {5Student stu1,stu2; //声明对象6//使用构造方法创建对象stu1,stu27stu1 = new Student(“张明”,”女”,new Date(“1/24/98″),”0001″,”设计1班”);8stu2 = new Student(“王华”,”男”,new Date(“10/30/99″),”0002″,”设计1班”);9stu1.displayAll();//引用成员方法显示对象stu1的信息10stu2.setName(“李华”); //引用成员方法修改对象stu2的名字11stu2.displayAll();//引用成员方法显示对象stu2的信息12}13}
输出结果如下:
行号例55输出结果1姓名: 张明,性别: 女,生日: 19980124,编号: 0001,所在班级: 设计1班2姓名: 李华,性别: 男,生日: 19991030,编号: 0002,所在班级: 设计1班
程序第7行和第8行,通过new关键字来创建对象。使用多参数的构造方法,注意参数的数量和顺序都完全对应相应的构造方法。 程序第9行、第10行、第11行,使用对象运算符“.”来引用对象的成员方法。[例2]编写一个名为Cyclinder的类,表示圆柱,其中含有r,h两个double型的成员变量用来表示圆柱的半径和高,要求每个变量定义为private,并为其定义访问方法(getXxx)和修改方法(setXxx),从而求圆柱体积和面积。编写TestCyclinder类,用于测试Cyclinder类的使用。编写时需将两个类编写在一个文件TestCyclinder.java中。需要注意的是,两个及多个类在一个文件时,只应该有一个类可以被声明为public,文件名也和public类名一致。
行号例56Cyclinder类及测试类TestCyclinder1package javaobjectdemo;2class Cyclinder {3private final double PI = 3.14; //声明一个常量4private double r, h;5public void set_R(double a) {6r = a;7}8public void set_H(double b) {9h = b;10}11public double Volume() {//计算圆柱的体积12return (PI * r * r * h);13}14public double Area() {//计算圆柱的面积15return (2 * PI * r * r 2 * PI * r * h);16}17}18public class TestCyclinder {19public static void main(String args[]) {20Cyclinder c = new Cyclinder();//声明并创建一个对象21c.set_R(3);//引用成员方法22c.set_H(5);23System.out.println(“体积: ” c.Volume());24System.out.println(“面积: ” c.Area()); }25}
输出结果如下:
行号例56输出结果1体积: 141.299999999999982面积: 150.72
程序第2行,声明一个类Cyclinder。程序第18行声明一个类TestCyclinder,有主方法,将此类的访问限定符设置为public,文件也命名为TestCyclinder.java。 程序第20行,创建一个对象c。若类Cyclinder中没有写构造方法,则系统采用默认的无参数的构造方法。 程序第21~24行,使用对象运算符“.”来引用对象的成员方法。 程序第21和22行,通过public的成员方法来给private的成员变量赋值。在Java程序设计中,经常是先声明一个私有的变量,然后再给出这些变量的公共的getter和setter方法,如前面例子中的setName(),getName(),set_R()等。这样做的好处是实现对属性的隐藏和保护。getter/setter方法也不一定只是简单的赋值或取值,也可以作一些权限控制和处理。例如,不是每个角色都可以赋值和取值、返回的值可以是经过加密后的值,可以在getter/setter方法中通过编写程序来实现。
5.3.3形参和实参在声明和使用方法的过程中,最重要的就是使用方法的参数。当一个对象调用方法时,其参数被分配内存空间,并要求调用者向参数传递具体的值,即方法被调用时,参数变量必须有具体值。在Java程序设计中,方法中的所有参数都是“传值”的。具体来说,方法中涉及的参数分为两种: 形参和实参。1. 概念(1) 方法声明中的参数: 形式参数在方法声明中的“()”中说明的变量被称为形式参数(形参),它能自动接受方法引用传递过来的值(相当于赋值),然后在方法的执行中起作用。例如在Student类中,成员方法setName(String name)中name就是形式参数,当一个对象(stu2)引用该方法时,该方法的形参name会接受对象引用传递过来的名字。
行号例57Student类中的setName方法1public void setName(String name) { //setName()方法2this.name = name;//通过形参赋值给成员变量3}
(2) 方法引用中的参数: 实际参数在方法引用时传递给它的值称为实际参数(实参),实参可以是常量、变量、对象或表达式。例如在StudentDemo类中,使用setName成员方法时具体的数据”李华”就是实参。
行号例58StudentDemo测试类中的代码1stu1 = new Student(“张明”,”女”,new Date(“1/24/98″),”0001″,”设计1班”);2stu2 = new Student(“王华”,”男”,new Date(“10/30/99″),”0002″,”设计1班”);3stu2.setName(“李华”); //将”李华”作为实参调用成员方法
2. 参数传递方式方法引用的过程其实就是将实参的数据传递给形参,以这些数据为基础,执行方法体完成其功能。由于实参与形参按照二者的对应关系传递数据,因此在实参和形参的结合上必须要求: 实参与形参的个数一致、对应的数据类型一致、对应顺序一致。参数传递的方式有两种: 按值传递和按引用传递。(1) 按值传递方式按值传递方式,在一般情况下,如果引用语句中的实参是常量、简单数据类型的变量或可计值的基本数据类型的表达式,那么被引用的方法声明的形参一定是基本数据类型的。上面的例子都是按值传递方式来进行参数传递。(2) 引用传递方式按引用传递方式,当引用语句中的实参是对象或数组时,被引用的方法声明的形参也一定是对象或数组,这种方式称为是按引用传递的。例如当表示两个类的依赖关系(如学生和书本)时,通常是在某个类的成员方法中通过使用另一个类的对象作为参数来实现。5.3.4this关键字在面向对象程序设计中,this使程序设计变得更加规范、简单、灵活。this表示当前对象,是指正在调用类中的变量或方法的那个对象。先看如下代码。
行号例59JavaObjectDemo5_1.java代码1package javaobjectdemo;2class Person {3private String name;4private int age;5public Person(String name) { //一个参数的构造方法6this.name = name;7}8public Person(String name, int age) { //两个参数的构造方法9this(name);//调用Person(String name)构造方法10this.age = age;11}12public String getInfo() {13return “姓名: ” name “,年龄: ” age;14}15public void printInfo() {16System.out.println(“Student类 –> ” this);17}18boolean compare(Person p) {19return (this.name.equals(p.name) && this.age == p.age);20}21}22public class JavaObjectDemo5_1 {23public static void main(String args[]) {24Person per1 = new Person(“李明”, 18);25System.out.println(per1.getInfo());26per1.printInfo();27Person per2 = new Person(“张三”, 18);28System.out.println(per1.compare(per2) ? “属性相同,是同一人!” :29″不相同,不是同一人!”);30}31}
输出结果如下:
行号例59输出结果1姓名: 李明,年龄: 182Student类 –> javaobjectdemo.Person@15db97423不相同,不是同一人!
在一个构造方法中,通过this()调用所在类中的另一个构造方法。如代码中第9行。注意,this()调用构造方法必须放在程序体的首行。 在一个方法内,当参数与成员变量的名称相同时,编译器无法区分,这时要在成员变量前用this关键字,如代码中第6行和第10行。在方法体中引用成员变量或其他的成员方法时,引用前都隐含着“this.”,一般情况下都会默认它; 但当成员变量与方法中的局部变量、参数同名时,为了区分且正确引用它们,成员变量前必须加“this.”不能默认。 在一个方法内,通过this关键字来访问当前实例的引用。如果在类的方法中需要返回一个对象,并且该对象还是方法所在的类的当前对象,就可以使用this关键字作为方法的返回值,如代码中第16行。 在判断两个对象是否相等时(在这里假设只要姓名、年龄都相同的就是同一个人,否则不是同一个人),由per1调用compare()方法,将per2传入到compare方法之中,所以在程序中第19行的this.name就代表per1.name,this.age就代表per1.age,而传入的参数per2则被compare()方法中的参数p表示。5.4实例成员与类成员在类中声明一个变量和方法时,可以指定它们是实例成员还是类成员。类成员是指有static关键字修饰的成员变量、成员方法和代码块。5.4.1static关键字前面的案例介绍了在类中定义的成员变量和成员方法,并且指出定义的变量和方法只能在该类的对象中使用,即这些在类中每个对象各自拥有一份定义的属性和方法,对象之间互不影响,但是还存在一些情况与这个特性不太符合。例如: 历法中12个月的天数,每个月的天数是规定不变的,因此若把这些不依赖某个对象的变化而变化的信息在所有该类的对象中同样复制一份,不仅浪费了存储空间,还会为了执行这些方法,首先创建对象再计算,同时又浪费了时间。为了解决这个问题,Java语言通常把这些需要所有对象共享使用的成员定义为类所有的,即可以让类的所有对象共享,使用static关键字作为修饰符。static表示“全局”或者“静态”的意思,主要用来修饰成员变量、成员方法、代码块。被static修饰的成员变量和成员方法,也称为类变量和类方法,是独立于该类的任何对象,即它不依赖类特定的对象,可被类的所有对象共享。只要这个类被加载,在运行时Java虚拟机就能根据类名在数据区的方法区内找到它们。因此,static对象可以在它的任何对象创建之前访问,而无须引用任何对象。5.4.2实例变量和类变量在声明成员变量时,被关键字static修饰的变量称作类变量,也称为静态变量。没有被static修饰的变量称为实例变量,也称为非静态变量。在成员变量修饰符中,还有修饰符final,被final修饰的变量称为最终变量,即常量,若和static修饰符一起使用,则表示静态的最终变量即静态常量。类变量在类被加载后(即分配了存储空间),它是类成员,不属于一个具体的对象,而是给所有对象共享,它可以由类直接引用也可由对象引用。实例变量在对象被创建时分配存储空间,它是实例成员,属于本对象,只能由本对象引用。另外,前面介绍了很多类型的变量,都存在各自的作用区域,一旦超出了起作用的区域,变量就不能发挥作用,程序如果引用了不在控制范围内的变量将会引起错误。表57列出了每个位置上定义的变量以及起作用的范围。
表57变量作用域
位置类方法和静态代码块所有对象成员方法代码块备注类变量○○○○该类的所有对象成员变量(实例变量) ○○所有成员方法方法中的形式参数○○同一方法内方法中声明的变量○同一代码块内异常捕获参数○异常处理块内
另外,在一个小范围内定义的变量名可能会与在包含它的大范围内的另外一个变量名称相同,在这种情况下会出现同名变量覆盖的情况。也就是说,在默认情况下该变量代表的是小范围内定义的变量,即采用就近的原则。类变量和成员变量都可以被类中的方法访问,所以它们也被称为全局变量(global variable)。在方法中声明的变量只能在方法内部使用,称为局部变量(local variable)。5.4.3实例方法和类方法同样,在声明成员方法时,用关键字static修饰的方法称作类方法,也称为静态方法,没有被static修饰的方法称为实例方法,也称为非静态方法。前面所提到的main方法是类方法。两者在使用时需要注意以下五个方面。(1) 使用对象来调用实例方法,使用类名来调用类方法。(2) 当类被加载到内存之后,类方法就获得了相应的入口地址,该地址在类中是共享的,可以直接通过类名来引用它。而实例方法只有在创建类的对象之后才会获得入口地址,它只能被对象所引用。(3) 无论是类方法还是实例方法,当它们被引用时,方法中的局部变量才会被分配内存空间,方法执行完毕,局部变量会立刻释放其所占内存。(4) 在类方法里只能引用类中其他静态的成员(类变量和类方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的变量和方法,需要在创建类的对象后才能使用,而类方法在使用前不需要创建任何对象。在非静态的实例方法中,所有的成员均可以使用。(5) 不能使用this和super关键字(super关键字将在第6章中介绍)的任何形式引用类方法。这是因为this和super是针对对象而言的,类方法在使用前不需创建任何对象,当类方法被调用时,对象还没有产生。5.4.4静态代码块与构造代码块构造方法通常是在对象被创建时执行某些初始化的工作,那么类在初次加载到内存时,如果希望执行一些初始化的工作,可以使用“初始化块”的方法,即在类加载时把执行的代码放到初始化块中。Java中初始化块是类中一段置于如下格式的花括号中的独立代码块。初始化块有两类,静态代码块是在类加载时自动执行的,非静态代码块是在创建对象时自动执行的代码,也称构造代码块。1. 静态代码块静态代码块的格式:
static{
//代码块
}
使用规则如下: (1) 静态代码块,在类中存在的位置是独立的,可放在任何合适的位置,但它不在任何的方法体内。(2) 静态代码块不用命名,没有访问控制修饰符,只能用static来修饰。(3) 只在类初次加载时被执行一次,而且只能被执行一次。代码执行优先于对象创建。如果static代码块有多个,将按照它们在类中出现的先后顺序依次执行。
行号例510JavaObjectDemo5_3.java代码1package javaobjectdemo;2public class JavaObjectDemo5_3 {3static{4System.out.println(“hello,world!”);5System.exit(0);6}7public static void main(String[] args){8System.out.println(“main”);9}10}
输出结果如下:
行号例510输出结果1hello,world!
由程序的输出结果可以发现,首先执行代码第3行的代码块,静态代码块中加入System.exit(0);语句,则会直接结束这个程序,不会再执行main函数中的语句。2. 构造代码块构造代码块是非静态代码块,其格式如下:
{
//代码块
}
使用规则如下: 构造代码块是在对象建立时调用的,在函数体中的执行时间要看对象是什么时候建立的。与静态代码块不同,操作时要先建立对象才能调用代码块中的语句,所以main函数是肯定要执行的。
行号例511JavaObjectDemo5_4.java代码1package javaobjectdemo;2public class JavaObjectDemo5_4 {3static{4System.out.println(“静态代码块!”);5 }6{7 System.out.println(“构造代码块!”);8}9public static void main(String[] args)10{11JavaObjectDemo5_4 st = new JavaObjectDemo5_4 (); 12//在对象一建立时就调用构造代码块13System.out.println(“主函数!”); 14}15}
输出结果如下:
行号例511输出结果1静态代码块!2构造代码块!3主函数!
5.5内部类在有些情况下,需要将类定义在一个比较小的范围内,这个类的使用只限于在这个小范围之中,就可以将类定义成内部类(Inner Class),嵌套内部类的类称为外部类(Outer Class)。5.5.1内部类的概念内部类通常被看成是外部类的一个成员,外部类不能直接存取内部类的成员,只有通过内部类才能访问内部类的成员。内部类是特殊形式的类,它们不能形成单独的Java源文件,在编译后也不会形成单独的类文件。内部类作为一个成员,其分类如表58所示。
表58内部类的分类
名称特点成员内部类在类中定义的内部类局部内部类在类中的方法中定义的内部类静态内部类使用static修饰的内部类匿名内部类没有名称的内部类
若使用static修饰,则为静态内部类; 否则为非静态内部类。静态和非静态内部类的主要区别在于: (1) 内部静态类对象和外部类对象可以相对独立。它可以直接创建对象,即使用new外部类名.内部类名()格式; 也可通过外部类对象创建。非静态类对象只能由外部对象创建。(2) 静态类中只能使用外部类的静态成员而不能使用外部类的非静态成员; 非静态类中可以使用外部类的所有成员。5.5.2成员内部类成员内部类和成员变量一样,属于类的全局变量。内部类声明的格式为:
public class Outer{//外部类
class Inner{//成员内部类
//代码块
}
}
内部类Inner不可以使用public修饰符,因为公共类的名称必须与类文件同名,所以每个Java类文件中只允许存在一个public公共类。只有创建了成员内部类的实例,才能使用成员内部类的变量和方法。实例化的方法如下:
Outerouter = new Outer();
Outer.Inner inner = outer.new Inner();
行号例512JavaObjectDemo5_5.java代码1package javaobjectdemo;2class Outer1{//外部类3int ID;4String name;5public Outer1(int id, String name){6this.ID = id;7this.name = name;8}9class Inner{//成员内部类10public void print(){11System.out.println(“编号: ” ID ” ,名称: ” name);12} 13}14}15public class JavaObjectDemo5_5 {//测试类16public static void main(String args[]) {17 Outer1 outer = new Outer1(1701,”设计1班”);//外部类实例化18 Outer1.Inner inner = outer.new Inner();//内部类实例化19 inner.print();//调用内部类的方法20}21}
输出结果如下:
行号例512输出结果1编号: 1701 ,名称: 设计1班
5.5.3局部内部类局部内部类和局部变量一样,都是在方法内定义的,有效范围只在方法内部有效。内部类声明的格式为:
public class Outer{
public void method{ //成员方法
class Inner{//局部内部类
//代码块
}
}
}
使用时注意: 局部内部类可以访问它在创建类中的所有成员变量和成员方法,包括私有方法。
行号例513JavaObjectDemo5_6.java代码1package javaobjectdemo;2class Outer2{3int ID;4String name;5public Outer2(int id, String name){//外部类构造方法6this.ID = id;7this.name = name;8}9public void docounting (int count) {//外部类的成员方法10class Inner{//局部内部类11int innercount = 0;12public Inner(int count){//局部内部类的构造方法13innercount=count;14}15public void print(){16System.out.println(“编号: ” ID ” ,名称: ” name);17}18public void count() {19System.out.println(“现有学生数量: ” innercount “人。”);20}21}22Inner inner = new Inner(count);//内部类实例化23inner.print();24inner.count();25} 26}27public class JavaObjectDemo5_6 {28public static void main(String args[]) {29 Outer2 outer = new Outer2(1701,”设计1班”);//外部类实例化30 outer.docounting(40);//外部类调用成员方法31}32}
输出结果如下:
行号例513输出结果1编号: 1701 ,名称: 设计1班2现有学生数量: 40人。
5.5.4静态内部类静态内部类和静态变量类似,都使用static修饰。内部类声明的格式为:
public class Outer{
static class Inner {//静态内部类
//代码块
}
}
使用时注意: 静态内部类可以在不创建Outer类的情况下直接使用。
行号例514JavaObjectDem05_7.java代码1package javaobjectdemo;2class Outer3{3static int ID;4static String name;5public Outer3(int id, String name){ //外部类构造方法6Outer3.ID = id;7Outer3.name = name;8}9static class Inner{ //静态内部类10int innercount = 0;11public Inner(int count){//局部内部类的构造方法12innercount=count;13}14public void print(){15System.out.println(“编号: ” ID ” ,名称: ” name);16}17public void count() {18System.out.println(“现有学生数量: ” innercount “人。”);19}20}21}22public class JavaObjectDemo5_7 {23public static void main(String args[]) {24 Outer3 outer = new Outer3(1701,”设计1班”);//外部类实例化25 Outer3.Inner inner = new Outer3.Inner(40);//内部类实例化26 inner.print();27 inner.count();28}29}
输出结果如下:
行号例514输出结果1编号: 1701 ,名称: 设计1班2现有学生数量: 40人。
5.5.5匿名内部类匿名内部类就是没有名称的内部类。正因为它没有名字,所以匿名内部类只能使用一次,当只需要创建一个类的对象而不需要它的名字时,使用内部类可以使代码更加简洁、清晰。使用匿名内部类时需要涉及继承、接口等概念,详见第6章。以下的代码示例可结合第6章的内容学习,在这里提到的目的只是对匿名内部类的使用方法有一个大致的了解。一般来说,使用匿名内部类来继承一个父类或实现一个接口,它经常被用于用户界面中的事件监听处理、创建接口的唯一实现类和创建某个类的唯一子类等情况。匿名类可以继承父类的方法,也可以重写父类的方法。使用匿名类时,必须在某个类中直接使用匿名类来创建对象。声明的格式为:
public class Outer{
new Inner() {//匿名内部类
//代码块
}
}
行号例515JavaObjectDemo5_8.java代码1package javaobjectdemo;2interface Inner{//声明接口3public void innerprint();4}5class Outer4{ //外部类6public static void print(Inner inner) {//print方法7inner.innerprint();8}9}10public class JavaObjectDemo5_8 {11public static void main(String args[]) {12 Outer4.print(new Inner() {//以匿名内部类作为print方法的实参13 @Override 14 public void innerprint(){//匿名内部类实现接口的方法15 System.out.println(“这是一个班的人数”);16 } 17 } );//print方法调用结束18}19}
输出结果如下:
行号例515输出结果1这是一个班的人数
本章习题及答案
第5章二维码
评论
还没有评论。