Agile Java
中文版
Java Basics
Java 基础
本课内存容包括:
使用整型 int 来统计学生人数
使用 Java 的集合类 java.util.ArrayList 存储多个学生对象
理解默认构造函数
学习如何利用 J2SE API 文档,理解如何使用 java.util.ArrayList
限定 java.util.ArrayList 只能包含 Student 对象
创建一个 TestSuite(测试套件)来测试一个以上的类
学习包和 import 语句
理解如何定义和使用类常量
使用系统库的 Date 和 Calendar 类(译注:原文为 date 和 calendar,疑为作者笔误)
学习不同类型的 Java 注释
使用 javadoc 为您的代码生成 API 文档
课程安排
在学校,有很多每个学期都开的课程,例如 Math 101 和 Engl 200。从一个学期到下一个学
期,基本的课程信息都是一样的,例如名称、编号、学分、课程介绍。
CourseSession 表示课程安排,它存储上课时间和教师信息,同时保留一份这门课程的学生
清单。
您需要定义 CourseSession 类,该类捕获基本的课程信息和上课学生的情况。只要您在仅考
虑一个学期的情况下使用 CourseSession 对象,就不会有两个 CourseSession 对象指向同一门课
程。一旦存在两个 CourseSession 对象必须指向同一门课程,那么基本课程信息存储在两个
2
63
第
2
课
Java
基础
Agile Java
中文版
26
CourseSession 对象就显得冗余了。目前,不考虑多个课程安排的情况,稍后您将整理现在的设
计以支持“一门课程的多种课程安排”。
创建 CourseSessionTest.java,并在其内编写一个名为 testCreate 的测试。就像 StudentTest
中的 testCreate,这个测试方法将展示您如何创建 CourseSession 对象。创建测试是一个观察
创建后的对象将会如何工作的好地方。
public class CourseSessionTest extends junit.framework.TestCase {
public void testCreate() {
CourseSession session = new CourseSession("ENGL", "101");
assertEquals("ENGL", session.getDepartment());
assertEquals("101", session.getNumber());
}
}
该测试表明可以用课程名称和编号来创建一个 CourseSession。该测试也确保课程名称和编
号可以被正确地存储在 CourseSession 对象中。
为了使这个测试得以通过,CourseSession 的代码如下:
class CourseSession {
private String department;
private String number;
CourseSession(String department, String number) {
this.department = department;
this.number = number;
}
String getDepartment() {
return department;
}
String getNumber() {
return number;
}
}
到目前为止,您已经创建了存储学生数据的 Student 类,以及存储课程信息的 CourseSession
类。两个类都提供了 getter 方法,来让其它对象获取数据。
但是,诸如 Student 和 CourseSession 的数据类并不怎么有趣。如果所有的面向对象开发都
是关于数据的存储和获取,那么系统将不会特别有用,也不是真正的面向对象。请记住:面向
对象系统是行为建模。行为通过向对象发送消息产生作用——让对象做某件事情或者从对象获
取数据。
不过,您已经从某个地方开始了。而且,如果不能查询对象的话,您将不能在测试中编写
断言。
64
int
Agile Java
中文版
27
学生注册
除非有学生报名,否则课程不能为学校带来任何收入。多数情况下,学生信息系统要求能
够同时处理多个学生。您应该能把很多学生存储到组或者集合里,并且在这些集合里对学生执
行某些操作。
CourseSession 需要存储一个新的属性—— Student 对象的集合。您应该增强 CourseSession
的创建测试,来支持这个新属性。如果您只是创建了一个新的 CourseSession 对象,还没有招收
任何学生。那么,您能针对一个空的 CourseSession 对象做出什么断言呢?
修改 testCreate,使其包含黑体的断言:
public void testCreate() {
CourseSession session = new CourseSession("ENGL", "101");
assertEquals("ENGL", session.getDepartment());
assertEquals("101", session.getNumber());
assertEquals(0, session.getNumberOfStudents());
}
int
新断言验证一门新课程的报名学生人数应该为 0。符号 0 是数字符号,代表整数零。特别
地,它是一个整型数,在 Java 中称为 int。
将方法 getNumberOfStudents 添加到 CourseSession:
class CourseSession {
...
int getNumberOfStudents() {
return 0;
}
}
( 省 略 号 代 表 实 例 变 量 , 构 造 函 数 , 以 及 您 已 经 编 写 的 getter 方 法 。) 指 定
getNumberOfStudents 的返回值类型为 int。从方法返回的值必须与声明的返回值类型相匹
配。在 getNumberOfStudents 方法中返回了一个整型数字。int 型允许的整型数字范围是
-2 147 483 648 到 2 147 483 647。
不像字符串,Java 中的数字不是对象。尽管数字如同字符串一样,可以作为参数随着消息
传递,但是您不能发送消息给数字。Java 在语法上提供了对基本算术运算的支持;对别的很多
操作,由系统库提供支持。稍后您将学到类似的非对象类型。简而言之,这些非对象类型被称
为基本类型。
65
第
2
课
Java
基础
Agile Java
中文版
28
您已经证实新 CourseSession 对象可以正确地初始化,但是您没有说明这个类可以正常地招
收学生。创建第二个测试方法 testEnrollStudents 来招收两个学生。对每一个学生,创建
一个 Student 对象,招收这个 student,然后确信 CourseSession 对象报告正确的学生数目。
public class CourseSessionTest extends junit.framework.TestCase {
public void testCreate() {
...
}
public void testEnrollStudents() {
CourseSession session = new CourseSession("ENGL", "101");
Student student1 = new Student("Cain DiVoe");
session.enroll(student1);
assertEquals(1, session.getNumberOfStudents());
Student student2 = new Student("Coralee DeVaughn");
session.enroll(student2);
assertEquals(2, session.getNumberOfStudents());
}
}
您如何知道需要 enroll 方法,并且该方法需要 Student 对象作为参数?在测试方法中您
所做的部分工作是为类设计 public 接口——开发者如何与这个类交互。您的目标是设计一个类,
并且让这个类以尽可能简单的方式来满足开发者的需要。
使第二个断言(学生人数为 2)能够通过的最简单的办法是让 getNumberOfStudents 方
法返回值为 2。但是,这样会破坏第一个断言。所以您必须在 CourseSession 内部记录学生的人
数。为了实现这个目的,您需要再引入一个成员变量。任何时候,如果需要存储信息,您可以
使用一个表示对象状态的成员变量。像下面这样修改 CourseSession 类:
class CourseSession {
...
private int numberOfStudents = 0;
...
int getNumberOfStudents() {
return numberOfStudents;
}
void enroll(Student student) {
numberOfStudents = numberOfStudents + 1;
}
}
将记录学生人数的成员变量 numberOfStudents 设为 private,这是一个好的实践。该
成员变量的类型为 int,而且被初始化为 0。当一个 CourseSession 对象被初始化时,成员变量
也会被初始化,例如 numberOfStudents。成员变量在构造函数执行之前被初始化。
getNumberOfStudents 方法返回成员变量 numberOfStudents,而不再返回整型数 0。
每次 enroll 方法被调用时,学生的数目都会增加 1。enroll 方法中的唯一一行代码实
66
初始化
Agile Java
中文版
29
现了这个功能:
numberOfStudents = numberOfStudents + 1;
加号和其它很多算术操作符,可以用来处理整型变量(也可以用来处理其它数字类型,稍
后会讨论)。等号右边的表达式取出 numberOfStudents 当前的值,并将其加 1。由于成员变
量 numberOfStudents 出 现 在 等 号 的 左 边 , 所 以 右 边 表 达 式 的 结 果 赋 值 给
numberOfStudents。这个例子中,将变量加 1,是一种常用的变量自增的方法。后面会讨论
其它增加变量值的方法。
numberOfStudents 同时出现在等号的两边,这让人看起来很奇怪。请记住:Java
虚拟机总是先执行某个赋值语句右边的代码。Java 虚拟机计算出等号右边表达式的值,然后将
结果赋值给左边。
请注意 enroll 方法的返回值类型为 void,这意味着 enroll 方法针对消息发送者不返
回任何东西。
图 2.1 显示了截至现在的系统结构。
图 2.1 CourseSession 和 Student 类图
概念上,一个 CourseSession 可以包含多个学生。实际上——在代码中——CourseSession 没
有包含学生对象的引用。目前 CourseSession 只包含学生的计数。稍后,当修改 CourseSession
类来实际存储 Student 引用的时候,您将修改 UML 类图来表示 CourseSession 和 Student 之间的
一对多的关系。
因为 enroll 方法需要 Student 对象作为参数,所以 CourseSession 依赖于 Student 类。换句
话说,如果 Student 类不存在,您将无法编译 CourseSession 类。
图 2.1 是最后一个显示每一个测试类的类图。由于您正在进行测试驱动的开发,所以如果没
有特别说明,后面类图中每一个生产类都暗示存在对应的测试类。
初始化
67
- 1
- 2
- 3
- 4
- 5
- 6
前往页