对象和简单数据对象
这节教程将开始讨论对象的生命周期。包括怎样创建对象、怎样使用它以及在不使用它的时候将它从系统中清除。下面一个一个介绍:
4.1 对象的生命周期
在这一小节中你可以学到怎样创建和使用任何类型的对象,还讨论了当对象不再需要的时候系统怎样清除对象的。
典型的JAVA程序创建对象,对象之间的交互是通过发送消息来实现的。通过这些对象的交互,JAVA程序可以执行一个GUI、运行一个动画或者通过网络发送和接收信息。一旦对象已经完成了任务,它就被作为无用信息被回收,它的资源可以由其它对象回收利用。
以下是一个小的例子程CreateObjectDemo,它创建三个对象:一个是Point对象和两个Rectange对象,你需要这三个源程序才可以编译这个程序:
public 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的位置
rect_two.origin = origin_one;
// 显示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);
}
}
一旦创建了对象,程序就可以操作对象并将它们有关的一些信息显示出来,以下是这个程序的输出结果:
Width of rect_one: 100
Height of rect_one: 200
Area of rect_one: 20000
X Position of rect_two: 23
Y Position of rect_two: 94
X Position of rect_two: 40
Y Position of rect_two: 72
这一节使用这个例子来在程序中描述对象的生命周期。从这你可以学到怎样编写代码来创建、使用对象以及系统怎样将它从内存中清除的。
下面主要分成几部分来讨论:
创建对象
使用对象
清除没有使用的对象
4.1.1 创建对象
众所周知,可以从类来创建对象。下面的几条语句都是用来创建对象的,它们都是来自上面程序CreateObjectDemo程序:
Point origin_one = new Point(23, 94);
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
Rectangle rect_two = new Rectangle(50, 100);
上面第一条语句从Point类创建了一个对象,而第二条和第三条语句是从Rectangle类众创建了对象。但是每条语句都有三部分组成:
声明:Point origin_one、Rectangle rect_one以及Rectangle rect_two都是变量的声明,它们的格式是类型后加变量名。当你创建一个对象的时候,你不必声明一个变量来引用它。然而,变量生命经常出现在创建对象代码的相同行上。
实例化:new是JAVA运算符,它可以创建新的对象并且为对象分配了内存空间。
初始化:new运算符后跟着一个构造函数的调用。比如 Point(23,94)就是一个Point类的构造函数的调用。这个构造函数初始化了这个新对象。
4.1.1.1 声明一个变量来引用对象
从前面的教程,你应该知道了如何声明一个变量了,你可以这样来编写:
type name
其中type是数据类型,而name是变量名。
除了原始类型(比如int和boolean),JAVA平台还直接提供了类和接口也是数据类型。这样为了声明一个变量来引用对象,你可以使用类或者接口的名字作为变量的类型。下面的例程使用了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);
声明没有创建新对象。Point origin_one代码没有一个新的Point对象,它只是声明一个变量orgin_one,它将用来引用Point对象。这个引用暂时是空的直到被赋值了。一个空的引用就是一个NULL引用。
4.1.1.2 实例化对象
为了创建一个对象你必须用new来实例化它。New运算符是通过为新对象分配内存来实例化一个类的。这个new运算符需要一个后缀参数,即构造函数的一个调用。构造函数的名字提供了要初始化类的名字。构造函数初始化了新的对象。
New运算符号返回一个引用给它创建的对象的。通常,这个引用被赋值为适当类型的变量。
4.1.1.3 初始化对象
以下是Point类的代码:
public class Point {
public int x = 0;
public int y = 0;
//一个构造函数
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
这个类包含了一个构造函数。你可以识别这个构造函数因为它跟类的名字是相同名字的,它没有任何的返回类型。这个在Point类中的构造函数有两个整型参数,它是由代码(int x, int y)来定义的。下面的整数23和94就是这个参数的数值:
Point origin_one = new Point(23, 94);
4.1.1.3 初始化对象
下面是Rectangle类的代码,它包含了四个构造函数:
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;
}
//用于移动rectangle的方法
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
//用于计算矩形面积的方法
public int area() {
return width * height;
}
}
每一个构造函数可以让你为矩形的各个方法提供初始数值,你可以设置矩形的原点、宽度和高度。如果一个类中有多个构造函数,它们的名字都是相同的只是它们有不同类型的参数或者不同数目的参数。JAVA平台可以根据参数的不同数目和类型类来区分构造函数。当JAVA平台遇到的代码的时候,它就调用在Rectangle类中的构造函数,这个函数需要一个Point参数以及两个整型参数:
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
这个调用初始化了矩形的原点(orgin_one)。代码也设置了矩形的宽度(100)和高度(200)。
多个引用可以引用相同的对象。下面的代码行调用了需要两个整型参数的构造函数,它为宽度和高度提供了初始化数值。如果你仔细看看这个代码,你会发现它创建一个Point对象,它的x和y数值被初始化为0。
下面的Rectangle构造函数没有任何参数:
Rectangle rect = new Rectangle();
如果一个类没有显性声明任何构造函数,JAVA平台自动提供一个没有参数的构造函数,这是一个缺省的构造函数,它没有完成任何事情。这样,所有的类就至少有一个构造函数。
4.1.2 使用对象
一旦你创建了一个对象,你可能想使用它来做一些事情。你可能从它得到一些信息,或者想改变它的状态或者让它来完成一些动作。对象允许你做以下两件事情:
操作或者检查它的变量。
调用它的方法。
4.1.2.1 引用对象的变量
下面是引用对象变量的基本形式,它是使用了有条件的名字即长名字:
objectReference.variableName
当实例变量处在作用域内的时候,你可以为实例变量使用一个简单的名字,也就是说,在对象类的代码中。处在对象类外面的代码必须使用有条件的名字。比如,在CreateObjectDemo类中的代码处在类Rectangle类代码的外面。所以为了引用Rectangle对象rect_one的origin、width和height变量,CreateObjectDemo必须相应使用rect_one.origin、rect_one.width和rect_one.height。这个程序使用了rect_one的width和height:
System.out.println("Width of rect_one: " + rect_one.width);
System.out.println("Height of rect_one: " + rect_one.height);
如果直接使用在CreateObjectDemo类中的变量width和height,那就将产生一个编译错误。在后面,程序还将使用类似的代码来显示关于rect_two的信息。相同类型的对象将有相同实例变量的副本。这样,每一个Rectangle对象就都有变量origin、width和height了。当你通过对象引用来访问实例变量的时候,你就引用了特定对象的变量。在CreateObjectDemo程序有两个对象rect_one和rect_two,它们有不同的origin、width和height变量:
对象的长文件名的第一部分是对象引用,它必须是一个对象的引用。这里你可以使用引用变量的名字,或者你可以使用任何的表达式来返回一个对象引用。重新调用这个new运算符可以返回一个对象的引用。这样你可以使用从new返回的数值来访问一个新的对象变量:
int height = new Rectangle().height;
这个语句创建了一个新的Rectangl