对象和类
辽宁经济职业技术学院信息系
硕士、副教授 陈英
对象和类
Object Orient Programming——简称 OOP
面向对象程序设计的三个特点,
1) 数据封装
2) 继承
3) 多态
程序是由一定的属性和行为的对象组成的,这些行为可
被对象执行。是自己创建对象还是购买它可能取决于
你的预算开支或时间。
只要对象能满足你的需求,就不必去关心其功能是如
何实现的。
在 OOP中惟一需要关心的是对象的接口是什么。
OOP中对象的三个主要特性
1,对象的行为 ——这个对象能做什么,或
者说可以对这个对象施加什么方法?
2,对象的状态 ——当对象施加方法时,对
象如何反应?
3,对象的标识符 ——对象是如何与可能具
有相同行为和状态的其他对象相区别的?
类的一个实例 —— 对象
对属于同一个类的所有实例对象来说,它们都
支持类似的行为,就像一家人那样。
对象的行为是通过可被调用的方法来定义的。
每个对象都保存有其当前特征的信息,即对象
的状态。
一个对象状态的改变必然是方法调用的结果
(如果没有方法调用施加于此对象,而对象的
状态却发生了变化,那么就破坏了封装)。
对象的状态并不能完全地描述一个对象,每个
对象还有一个惟一的标识符。
对象 —— 类的一个实例
在传统的面向过程的程序中,以 main函数
从最顶部开始编写。
在设计一个面向对象的系统时,并没有
“最顶部”之说,所以对于 OOP的新手来
说,往往不知道从哪里开始。答案就是:
首先设计类,然后往每个类中添加方法。
使用现有的类
要使用对象,首先就必须构造它们,并指
定它们的初始状态,然后将方法应用于对
象。
在 Java程序设计语言中,使用构造器
( constructor)来构造新的实例。
一个构造器就是一个特殊的方法,它的作
用是构造并初始化对象。
使用现有的类
在 Java中,没有类就不能做任何事。
然而,如 Math类,我们可以使用 Math类
的方法,如 Math.random,而不必知道它
们是如何实现的(如果有的话,我们只需
知道名字和参数)。这正是封装的的含义。
Math类只是封装了功能,它既不需要也没
有隐藏数据。由于没有数据,所以既不需
要创建对象,也不需要初始化其实例字段。
使用现有的类
以标准 Java库中的 Date类为例,它的对象
描述了时间。
构造器的名字和其类名相同。因此,Data
类的构造器叫做 Date。
在构造一个 Date对象时,在构造器前面加
上 new运算符,如下所示:
new Date()
这个表达式即构造了一个新的对象,并且
此对象被初始化为当前日期和时间。
使用现有的类
我们可以把对象传递给一个方法:
System.out.println(new Date());
相反,也可以把一个方法应用于刚刚构
造的对象。 Date类中有一个 toString方法。
此方法产生表示时间的一个字符串。下
面表示了如何把 toString方法应用于新构
造的 Date对象。
String s = new Data().toString();
使用现有的类
在前面的两个例子中,被构造的对象只能使用一
次。通常我们希望构造的对象可被多次使用,这
时需要把一个对象存储在一个变量中。
Date birthday = new Date();
在对象和对象变量之间存在着一个重要的不同。
例如,Date deadline;
它定义了一个对象变量 ——deadline,它可以指向
类型为 Date的对象。但是,变量 deadline并不是
一个对象,而且在此也没以指向任何一个对象。
此时,不能对这个变量应用任何 Date方法。
使用现有的类
语句 s = deadline.toString(); 会产生一个编
译期的错误。
我们必须首先初始化变量 deadline。可以有
两种方法:
1) 使用新构造的对象初始化变量:
deadline = new Date();
2) 使变量指向一个已存在的对象:
deadlean = birthday;
这样两个变量都指向同一个对象。实际上,
一个对象变量并不包含一个对象,它只是指
向一个对象。
使用现有的类
在 Java中,任何对象变量的值都是对存储在别处的
对象的一个引用。
New运算符的返回值也是一个引用。语句 Date
deadline = new Date();
由两部分构成。首先表达式 new Date()生成了一个类
型为 Date的对象,它的值是对新生成的对象的一个
引用。然后这个引用被存储在变量 deadline中。
可以显示地给一个对象赋值为 null,以明确地表示
它当前没有指向任何对象。
Deadline = null;
创建自己的类
Class NameOfClass
{
constructor1
constructor2
… …
method1
method2
… …
field1
field2
… …
}
在 Java中
最简单的类定
义形式如右面
所示:
创建自己的类 —— Employee
class Employee
{
public Employee(String n,double s,int year,int month,int day)
{ name = n; // construct
salary = s;
hireDay = new GregorianCalendar(year,month - 1,day);
}
public String getName() // method1
{ return name; }
… … // more methods
… … // instance fields
private String name;
private double salary;
private Date hireDay; }
创建主类 —— EmployeeText
在程序中,构造一个 Employee数组,并给
它赋值以三个 Employee对象。
Employee[] staff = new Employee[3];
staff[0] = new Employee("Carl Cracker",75000,1987,12,
15);
staff[1] = new Employee("Harry Hacker",50000,1989,10,
1);
staff[2] = new Employee("Tony Tester",40000,1990,3,15);
创建主类 —— EmployeeText
使用 Employee类的 raiseSalary方法使每
个员工的薪金增长 5%:
for (int i = 0; i < staff.length; i++)
staff[i].raiseSalary(5);
创建主类 —— EmployeeText
通过调用 getName,getSalary和 getHireDay方法给出
每个员工的信息:
for (int i = 0; i < staff.length; i++)
{
Employee e = staff[i];
System.out.println("name=" + e.getName()
+ ",salary=" + e.getSalary()
+ ",hireDay=" + e.getHireDay());
}
创建主类 —— EmployeeText
此程序包含了两个类:一个 Employee类和一个带有
public访问提示符的 EmployeeText类。
Main方法在 EmployeeText类中。
由于源文件的名字必须与 public(公开的)类的名字
相同,所以源文件的名字为 EmployeeText.java
在一个源文件中只能有一个公开类,但可以含有任意
数量的非公开类。
当编译这段源代码时,编译器会在源代码目录下创建
两个类文件,EmployeeText.class和 Employee.class
把程序中包含 main方法的那个类名指定给字节码解
释器,程序开始执行,java EmployeeText
分析 Employee类
Employee类有一个构造器:
public Employee(String n,double s,
int year,int month,int day)
Employee类有四个方法:
1) public String getName()
2) public double getSalary()
3) public Date getHireDay()
4) public void raiseSalary(double byPercent)
分析 Employee类
Employee类有三个实例字段,它们含有
在 Employee类的实例内部被操作的数据。
private String name;
private double salary;
private Date hireDay;
Private(私有的)关键字用来确保可以
访问这些实例字段的只能是 Employee类
本身的方法。任何外部方法都不能读或者
写这些字段。
分析 Employee类
public Employee(String n,double s,int year,int month,int day)
{
name = n;
salary = s;
GregorianCalendar calendar
= new GregorianCalendar(year,month - 1,day);
// GregorianCalendar uses 0 for January
hireDay = calendar.getTime();
}
由构造方法可知,name 和 hireDay 字段分别是
对 String和 Date对象的引用。
类中常常含有 class 类型的实例字段。
分析 Employee类
创建构造器:构造器的名字和类的名字是相
同的。
当构造 Employee类的对象时,此构造器被启
动,它给实例字段赋初值。
例如:
new Employee("Carl Cracker",75000,1987,12,15);
实例字段被赋值如下:
name =,Carl Cracker”;
salary = 75000;
hireDay = December 15,1987;
有关构造器的注意事项
构造器和其它方法一个重要的不同是:构造器
只能和 new运算符一起使用。
不能把构造器应用于一个已存在的对象来重新
设置其实例字段。
需要记住以下几点:
1) 构造器和类具有相同的名字。
2) 一个类可以多个构造器。
3) 构造器可以有 0个,1个或多个参数。
4) 构造器没有返回值。
5) 构造器只能和 new运算符一起使用。
Employee类的方法 ——raiseSalary
在 Employee类中的方法相当简单。所有的
方法都可以通过名字访问私有的实例字段。
实例字段总是可以被它们所在类的方法访
问。例:
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
Employee类的方法 ——raiseSalary
在上述的代码中,执行此方法的对象中的 salary
实例字段被设置了一个新值(此特定的方法不
返回任何值)。
例如,下面的调用,number007.raiseSalary(5);
通过把 number007.raiseSalary变量的值增加 5%
来提高 number007的薪金。
更具体地讲,此调用执行下面的指令:
double raise = number007.salary * 5 / 100;
number007.salary + = raise;
Employee类的方法 ——raiseSalary
raiseSalary方法有两个参数。
1) 在方法名字之前的类型为 Employee的对象,
此参数中作隐式参数。
2) 在方法名字之后的圆括号内的数字,它是显
示参数。
显示参数被明确地列在方法声明部分,
例如,double byPercent。
隐式参数并不出现在方法声明中。
在每个方法中,关键字 this指向隐式参数。
Employee类的方法 ——raiseSalary
只要喜欢,可以按如下方式编写 raiseSalary方法:
public void raiseSalary(double byPercent)
{
double raise = this.salary * byPercent / 100;
this.salary += raise;
}
字段访问器
getName,getSalary和 getHireDay方法
都是访问器方法因为它们都是简单地返
回实例字段的值,有时又被称作字段访
问器。
Name字段是一个“只读”字段。一旦
在构造器中设定它的值,便没有对它进
行改变的方法。这样,就保证了此 name
字段永远不会被破坏。
salary字段不是只读的,它可以被
raiseSalary方法改变其值。
API java.util.GregorianCalendar
GregorianCalendar以日历记号表示日期,而
Date类表示当前的时间点。
GregorianCalendar()
构造一个日历对象,此对象表示了默认地区的默
认时区的当前时间。
Int get(int field)
得到一个特定字段的值。
GregorianCalendar 是对更一般的 Calendar类
的扩展。 Calendar类从总体上描述了历法的属
性。
Employee类的方法 ——raiseSalary
raiseSalary方法有两个参数。
1) 在方法名字之前的类型为 Employee的对象,
此参数叫作隐式参数。
2) 在方法名字之后的圆括号内的数字,它是显
示参数。
显示参数被明确地列在方法声明部分,例如,
double byPercent。
隐式参数并不出现在方法声明中。
在每个方法中,关键字 this指向隐式参数 。