类是对象的模板,对象是类的实例。当你定义一个类时,就生命了该类确切的形式和属性。
通过指定类中包含的数据和对这些数据进行操作的代码来定义一个类。最简单的类可以只包含代码或只有数据,大部分实际的类二者都有。
我们使用关键字class来声明一个类。通常定义class的形式如下所示:
class classname { type instance-varable1; type instance-varable2; //... type instance-varableN; type metbodname1(parameter-list) { //body of method } type metbodname2(parameter-list) { //body of method } //... type metbodnameN(parameter-list) { //body of method } } |
在一个class中定义的数据或叫变量叫做实例变量。代码包含在方法中。总体来说,类中定义的方法和变量叫做该类的成员。在大部分类中,实例变量由该类所定义的方法调用和访问。因此,这就决定了类中的数据如何被使用。所有的方法都在类中声明,并且通常都具有如下形式:
type name(parameter-list) {
//body of method
}
在这里,type指定了由方法返回的数据类型。它可以是任意有效的类型,包括你创建的类类型。如果方法没有返回值,则其返回类型必须是void。方法的名字由name指定。这个名字可以是除了那些在当前作用域中已经使用的标识符之外的任意合法标识符。parameter-list是类型、标识符对组成的序列,每对之间用逗号分开。参数实际上是方法被调用时接收传递过来的参数值的变量。如果方法没有参数,则参数表就是空的。除了返回void方法外,那些具有返回类型的方法使用下面的返回语句形式对调用他们的程序返回一个值。
return value;
value是返回值。下面是一个简单的类的例子:
class Sameple { int a,b; int sum() { return a+b; } } |
声明类的对象
每当创建一个类时,就是在创建一个新的数据类型,可以用这个数据类型去声明这种类型的对象。然而,获得一个类的对象一般分两步进行。首先,必须声明这个类型的一个变量,这个变量并没有定义对象本身,而仅仅是一个可以指向对象的变量。第二步,必须获得这个对象的一个实际的物理拷贝,并将其赋给已声明的那个变量。使用new运算完成这一步。new运算符为对象动态分配(即在程序运行时分配)内存,并为其返回一个引用。该引用或多或少的是由new分配给对象的内存的地址。然后该引用被保存在变量中。因此,JAVA中所有类的对象一定是动态分配的。
下面是一个创建Sample类(前面定义的)对象的例子:
Sample ob = new Sample();
这条语句将刚才提到的两步合二为一了。可以重新写成下面这样一来,更清楚的表示出2步:
Sample ob;
ob = new Sample();
一旦得到一个类对象,就可以使用“.“运算符访问其成员。下面是通常的形式:
object-name.member-name
如,给ob的成员a赋值10,使用下面语句:
ob.a = 10;
构造函数
构造函数在创建对象时立即对其进行初始化。构造函数与它所在的类具有相同的名字,在语句构成上与方法类似。然而,构造函数没有返回值,甚至也不返回void。这是因为类的构造函数隐含的返回类型是类类型本身。初始化对象的内部状态,以便使代码创建实例时有一个完全初始化的、可用的对象是构造函数的任务。
构造函数可以有参数,这些参数接收创建对象时传递给构造的参数。典型情况下,包含在构造函数参数中的这些值用于初始化对象。当创建每个对象的时候,传递给构造函数的参数即被指定。例如,下面是一个加到Sample类中有参数的构造函数的例子。
class Sample { int a,b; // constructor Sample(int x,int y) { a = x; b = y; } int sum() { return a+b; } } |
class Example { public static void main(String args[]) { Sample ob = new Sample(-99,88); System.out.println(ob.sum()); } } |
对于一个类,当没有明确定义构造函数时,JAVA创建一个默认的构造函数。默认构造函数自动将所有实例变量初始化为0 。对于简单的类来说,默认的构造函数已足够用,但对于复杂的程序而言通常不会这样做。一旦定义了自己的构造函数,默认的构造函数就不再使用了。
垃圾回收
有些语言,比如C++,动态分配对象必须使用delete运算符手工释放它。而JAVA则采用了不同的方法,自动的重新分配内存。完成这种功能的技术叫垃圾回收。垃圾回收是这样工作的:当一个对象的引用不存在时,这个对象就被认为不再需要的了,它所占用的内存就可以被回收。这时候不需要像C++那样明确的清楚对象。垃圾回收只是在程序执行过程中偶然发生。对于那些已不再使用但仍旧存在的一个或多个对象来说,垃圾回收不会因此而简单的发生。此外,不同的JAVA运行系统采用不同的垃圾回收方法,但对于大多数情况来说,编写程序时不用过多的考虑这些。
finalize()方法
在删除一个对象之前,有时需要确认某些动作已经完成。例如:如果一个对象已经获得了某些系统资源,比如一个文件句柄,那么在删除该对象之前需要确定该资源已经被释放。JAVA提供了一种叫做终止的机制对这些情况进行处理。使用终止可以定义指定的动作,这个动作在一个对象刚好被垃圾回收器回收时发生。
为类增加一个终止,只需简单的定义finalize()方法。无论何时对那个类中的对象进行回收时,JAVA的运行系统都会调用这个方法。在finalize()方法中指定在一个对象被销毁前所必须要执行的那些动作。finalize()方法的通常形式如下:
protected void finalize()
{
// finalization code here
}
理解finalize()只在垃圾回收前被调用是非常重要的。例如,当对象超出作用域时,finalize()就不会被调用。这意味着不会知道finalize()将会在什么时候执行。因此,程序中应当提供由其它对象使用的释放系统资源的方法。对于一般的程序操作不必依赖finalize()。