4.2 使用现有类
在Java中,没有类就无法做任何事情,我们前面曾经接触过几个类。然而,并不是所有的类都具有面向对象特征。例如,Math类。在程序中,可以使用Math类的方法,如 Math.random,并只需要知道方法名和参数(如果有的话),而不必了解它的具体实现过程。这正是封装的关键所在,当然所有类都是这样。但遗憾的是,Math 类只封装了功能,它不需要也不必隐藏数据。由于没有数据,因此也不必担心生成对象以及初始化实例域。
下一节将会给出一个更加具有代表性的类—Date类。从中可以看到如何构造对象,以及如何调用类的方法。
4.2.1 对象与对象变量
要想使用对象,就必须首先构造对象,并指定其初始状态。然后,对对象施加方法。
在Java程序设计语言中,使用构造器(constructor)构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。下面看一个例子。在标准Java库中包含一个Date类。它的对象将描述一个时间点,例如:“December 31, 1999, 23:59:59 GMT”。
注释:可能会感到奇怪:为什么用类描述时间,而不像其他语言那样用一个内置的(built-in)类型?例如,在Visual Basic中有一个内置的date类型,程序员可以采用#6/1/1995#格式指定日期。从表面上看,这似乎很方便,因为程序员使用内置的date类型,而不必为设计类而操心。但实际上,Visual Basic这样设计的适应性如何呢?在有些地区日期表示为月/日/年,而另一些地区表示为日/月/年。语言设计者是否能够预见这些问题呢?如果没有处理好这类问题,语言就有可能陷入混乱,对此感到不满的程序员也会丧失使用这种语言的热情。如果使用类,这些设计任务就交给了类库的设计者。如果类设计的不完善,其他的操作员可以很容易地编写自己的类,以便增强或替代(replace)系统提供的类(作为这个问题的印证:Java的日期类库有些混乱,对它的重新设计正在进行中。请参看http://jcp.org/en/jsr/detailid=310)。
构造器的名字应该与类名相同。因此Date类的构造器名为Date。要想构造一个Date对象,需要在构造器前面加上new操作符,如下所示:
这个表达式构造了一个新对象。这个对象被初始化为当前的日期和时间。
如果需要的话,也可以将这个对象传递给一个方法:
相反,也可以将一个方法应用于刚刚创建的对象上。Date类中有一个toString方法。这个方法将返回日期的字符串描述。下面的语句可以说明如何将toString方法应用于新构造的 Date 对象上。
在这两个例子中,构造的对象仅使用了一次。通常,希望构造的对象可以多次使用,因此,需要将对象存放在一个变量中:
图4-3显示了引用新构造的对象变量birthday。
|
| 图4-3 创建一个新对象 |
在对象与对象变量之间存在着一个重要的区别。例如,语句
定义了一个对象变量deadline,它可以引用Date类型的对象。但是,一定要认识到:变量deadline不是一个对象,实际上也没有引用对象。此时,不能将任何 Date 方法应用于这个变量上。语句
将产生编译错误。
必须首先初始化变量deadline。这里有两个选择。当然,可以用新构造的对象初始化这个变量:
也让这个变量引用一个已存在的对象:
现在,这两个变量引用同一个对象(请参见图4-4)。
|
| 图4-4 引用同一个对象的对象变量 |
一定要认识到:一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。
在Java中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。new操作符的返回值也是一个引用。下列语句:
有两个部分。表达式new Date()构造了一个Date类型的对象,并且它的值是对新创建对象的引用。这个引用存储在变量deadline中。
可以显式地将对象变量设置为null,表明这个对象变量目前没有引用任何对象。
如果将一个方法应用于一个值为null的对象上,那么就会产生运行错误。
变量不会自动地初始化为null,而必须通过调用new 或将它们设置为null进行初始化。
C++(www.cppentry.com)注释:很多人错误地认为Java对象变量与C++(www.cppentry.com)的引用类似。然而,在C++(www.cppentry.com) 中没有空引用,并且引用不能被赋值。可以将Java的对象变量看作C++(www.cppentry.com)的对象指针。例如,
实际上,等同于
一旦理解了这一点,一切问题就迎刃而解了。当然,一个Date*指针只能通过调用new进行初始化。就这一点而言,C++(www.cppentry.com)与Java的语法几乎是一样的。
如果把一个变量的值赋给另一个变量,两个变量就指向同一个日期,即指向同一个对象。在Java中的null引用对应C++(www.cppentry.com)中的NULL指针。
所有的Java对象都存储在堆中。当一个对象包含另一个对象变量时,这个变量依然包含着指向另一个堆对象的指针。
在C++(www.cppentry.com)中,指针十分令人头疼,并常常导致程序错误。稍不小心就会创建一个错误的指针,或者造成内存溢出。在Java语言中,这些问题都不复存在。如果使用一个没有初始化的指针,运行系统将会产生一个运行时错误,而不是生成一个随机的结果。同时,不必担心内存管理问题,垃圾收集器将会处理相关的事宜。
C++(www.cppentry.com)确实做了很大的努力,它通过拷贝型构造器和复制操作符来实现对象的自动拷贝。例如,一个链表(linked list)拷贝的结果将会得到一个新链表,其内容与原始链表相同,但却是一组独立的链接。这使得将同样的拷贝行为内置在类中成为可能。在Java中,必须使用clone方法获得对象的完整拷贝。
【责任编辑:
夏书 TEL:(010)68476606】