典型的Java程序会建立许多对象,如你所知,经过调用方法进行交互,经过这些对象交互,程序能够执行各类任务,例如实现GUI,运行动画或经过网络发送和接收信息,一旦对象完成了建立它的工做,它的资源就会被回收以供其余对象使用。小程序
这是一个名为CreateObjectDemo
的小程序,它建立了三个对象:一个Point
对象和两个Rectangle
对象,你将须要全部三个源文件来编译此程序。segmentfault
public class CreateObjectDemo { public static void main(String[] args) { // Declare and create a point object and two rectangle objects. Point originOne = new Point(23, 94); Rectangle rectOne = new Rectangle(originOne, 100, 200); Rectangle rectTwo = new Rectangle(50, 100); // display rectOne's width, height, and area System.out.println("Width of rectOne: " + rectOne.width); System.out.println("Height of rectOne: " + rectOne.height); System.out.println("Area of rectOne: " + rectOne.getArea()); // set rectTwo's position rectTwo.origin = originOne; // display rectTwo's position System.out.println("X Position of rectTwo: " + rectTwo.origin.x); System.out.println("Y Position of rectTwo: " + rectTwo.origin.y); // move rectTwo and display its new position rectTwo.move(40, 72); System.out.println("X Position of rectTwo: " + rectTwo.origin.x); System.out.println("Y Position of rectTwo: " + rectTwo.origin.y); } }
该程序建立、操做和显示有关各类对象的信息,这是输出:网络
Width of rectOne: 100 Height of rectOne: 200 Area of rectOne: 20000 X Position of rectTwo: 23 Y Position of rectTwo: 94 X Position of rectTwo: 40 Y Position of rectTwo: 72
如下三节使用上面的示例来描述程序中对象的生命周期,经过它们,你将学习如何编写在你本身的程序中建立和使用对象的代码,你还将了解系统在对象生命结束后如何清理。函数
如你所知,一个类提供了对象的蓝图;你从一个类建立一个对象,从CreateObjectDemo
程序获取的如下每一个语句都会建立一个对象并将其分配给变量:学习
Point originOne = new Point(23, 94); Rectangle rectOne = new Rectangle(originOne, 100, 200); Rectangle rectTwo = new Rectangle(50, 100);
第一行建立Point
类的对象,第二行和第三行分别建立Rectangle
类的对象。动画
这些语句中的每个都有三个部分(下面将详细讨论):spa
new
关键字是一个建立对象的Java运算符。new
运算符后面是对构造函数的调用,该构造函数初始化新对象。以前,你了解到要声明变量,你能够编写:code
type name;
这会通知编译器你将使用name
来引用类型为type
的数据,对于原始变量,此声明还为变量保留适当的内存量。对象
你还能够在本身的代码行上声明引用变量,例如:blog
Point originOne;
若是你像这样声明originOne
,它的值将不肯定,直到实际建立并分配了一个对象,简单地声明引用变量不会建立对象,为此,你须要使用new
运算符,以下一节所述,在代码中使用对象以前,必须将对象分配给originOne
,不然,你将收到编译器错误。
此状态中的变量(当前不引用任何对象)能够以下所示(变量名称,originOne
,以及指向无的引用):
new
运算符经过为新对象分配内存并返回对该内存的引用来实例化一个类,new运算符还调用对象构造函数。
注意:短语“实例化类”与“建立对象”的含义相同,建立对象时,你正在建立类的“实例”,所以“实例化”一个类。
new
运算符须要一个后缀参数:对构造函数的调用,构造函数的名称提供要实例化的类的名称。
new
运算符返回对其建立的对象的引用,此引用一般分配给适当类型的变量,如:
Point originOne = new Point(23, 94);
new
运算符返回的引用没必要分配给变量,它也能够直接用在表达式中,例如:
int height = new Rectangle().height;
这条语句将在下一节中讨论。
这是Point
类的代码:
public class Point { public int x = 0; public int y = 0; //constructor public Point(int a, int b) { x = a; y = b; } }
该类包含一个构造函数,你能够识别构造函数,由于它的声明使用与该类相同的名称,而且它没有返回类型,Point
类中的构造函数接受两个整数参数,由代码(int a, int b)
声明,如下语句提供23
和94
做为这些参数的值:
Point originOne = new Point(23, 94);
执行此语句的结果能够在下图中说明:
这是Rectangle
类的代码,它包含四个构造函数:
public class Rectangle { public int width = 0; public int height = 0; public Point origin; // four constructors public Rectangle() { origin = new Point(0, 0); } public Rectangle(Point p) { origin = p; } public Rectangle(int w, int h) { origin = new Point(0, 0); width = w; height = h; } public Rectangle(Point p, int w, int h) { origin = p; width = w; height = h; } // a method for moving the rectangle public void move(int x, int y) { origin.x = x; origin.y = y; } // a method for computing the area of the rectangle public int getArea() { return width * height; } }
每一个构造函数都容许你使用基本类型和引用类型为矩形的origin
、width
和height
提供初始值,若是一个类有多个构造函数,则它们必须具备不一样的签名,Java编译器根据参数的数量和类型区分构造函数。当Java编译器遇到如下代码时,它知道在Rectangle
类中调用构造函数,该构造函数须要一个Point
参数后跟两个整数参数:
Rectangle rectOne = new Rectangle(originOne, 100, 200);
这就要求Rectangle
的一个构造初始化原点originOne
,此外,构造函数将width
设置为100
,将height
设置为200
,如今有两个对同一个Point
对象的引用 — 一个对象能够有多个对它的引用,以下图所示:
如下代码行调用Rectangle
构造函数,该构造函数须要两个整数参数,这些参数提供width
和height
的初始值,若是检查构造函数中的代码,你将看到它建立了一个新的Point
对象,其x
和y
值初始化为0
:
Rectangle rectTwo = new Rectangle(50, 100);
如下语句中使用的Rectangle
构造函数不带任何参数,所以它被称为无参数构造函数:
Rectangle rect = new Rectangle();
全部类至少有一个构造函数,若是类没有显式声明任何,则Java编译器会自动提供一个无参数构造函数,称为默认构造函数。此默认构造函数调用父类的无参数构造函数,若是类没有其余父级,则调用Object
构造函数,若是父级没有构造函数(Object
确实有构造函数),编译器将拒绝该程序。
一旦你建立了一个对象,你可能想要用它来作某事,你可能须要使用其中一个字段的值,更改其中一个字段,或调用其中一个方法来执行操做。
对象字段按名称访问,你必须使用明确的名称。
你能够在其本身的类中对于字段使用简单名称,例如,咱们能够在Rectangle
类中添加一个打印width
和height
的语句:
System.out.println("Width and height are: " + width + ", " + height);
在这种状况下,width
和height
是简单的名称。
对象类外部的代码必须使用对象引用或表达式,后跟点(.
)运算符,后跟简单字段名称,以下所示:
objectReference.fieldName
例如,CreateObjectDemo
类中的代码位于Rectangle
类的代码以外,所以,要引用名为rectOne
的Rectangle
对象中的origin
、width
和height
字段,CreateObjectDemo
类必须分别使用名称rectOne.origin
、rectOne.width
和rectOne.height
,该程序使用其中两个名称来显示rectOne
的width
和height
:
System.out.println("Width of rectOne: " + rectOne.width); System.out.println("Height of rectOne: " + rectOne.height);
尝试在CreateObjectDemo
类中的代码使用简单名称的width
和height
没有意义 — 这些字段仅存在于对象中 — 并致使编译器错误。
稍后,该程序使用相似的代码来显示有关rectTwo
的信息,相同类型的对象具备本身的相同实例字段的副本,所以,每一个Rectangle
对象都有名为origin
、width
和height
的字段。经过对象引用访问实例字段时,将引用该特定对象的字段,CreateObjectDemo
程序中的两个对象rectOne
和rectTwo
具备不一样的origin
、width
和height
字段。
要访问字段,你可使用对象的命名引用,如前面的示例所示,或者你可使用任何返回对象引用的表达式。回想一下,new
运算符返回对象的引用,所以,你可使用new
返回的值来访问新对象的字段:
int height = new Rectangle().height;
该语句建立一个新的Rectangle
对象并当即得到其高度,实质上,该语句计算Rectangle
的默认高度。请注意,在执行此语句以后,程序再也不具备对建立的Rectangle
的引用,由于程序从未在任何地方存储引用,该对象未被引用,其资源可由Java虚拟机自由回收。
你还可使用对象引用来调用对象的方法,将方法的简单名称附加到对象引用,并使用插入点运算符(.
),此外,你在括号内提供方法的任何参数,若是方法不须要任何参数,请使用空括号。
objectReference.methodName(argumentList);
或者:
objectReference.methodName();
Rectangle
类有两个方法:getArea()
用于计算矩形面积,move()
用于更改矩形的原点,这是调用这两个方法的CreateObjectDemo
代码:
System.out.println("Area of rectOne: " + rectOne.getArea()); ... rectTwo.move(40, 72);
第一个语句调用rectOne
的getArea()
方法并显示结果,第二行移动rectTwo
,由于move()
方法为对象的origin.x
和origin.y
分配新值。
与实例字段同样,objectReference
必须是对象的引用,你可使用变量名称,但也可使用任何返回对象引用的表达式,new
运算符返回一个对象引用,所以你可使用new
返回的值来调用新对象的方法:
new Rectangle(100, 50).getArea()
表达式new Rectangle(100, 50)
返回引用Rectangle
对象的对象引用,如图所示,你可使用点表示法来调用新的Rectangle
的getArea()
方法来计算新矩形的面积。
某些方法,如getArea()
返回一个值,对于返回值的方法,能够在表达式中使用方法调用,你能够将返回值分配给变量,使用它来作出决策或控制循环,此代码将getArea()
返回的值赋给变量areaOfRectangle
:
int areaOfRectangle = new Rectangle(100, 50).getArea();
请记住,在特定对象上调用方法与向该对象发送消息相同,在这种状况下,调用getArea()
的对象是构造函数返回的矩形。
某些面向对象的语言要求你跟踪所建立的全部对象,并在再也不须要时明确销毁它们,明确地管理内存是乏味且容易出错的,Java平台容许你根据须要建立任意数量的对象(固然,受系统能够处理的限制),你没必要关心销毁它们。Java运行时环境在肯定再也不使用对象时删除对象,此过程称为垃圾回收。
当没有对该对象的引用时,对象有资格进行垃圾回收,当变量超出范围时,一般会删除变量中保存的引用,或者,你能够经过将变量设置为特殊值null
来显式删除对象引用。请记住,程序能够对同一对象具备多个引用;在对象符合垃圾回收条件以前,必须删除对对象的全部引用。
Java运行时环境具备垃圾收集器,能够按期释放再也不引用的对象使用的内存,垃圾收集器在肯定时间正确时自动完成其工做。