为什么要Initialization & Cleanup(初始化和清除)呢?引用下原书的话:As the computer revolution progresses,"unsafe" programming has become one of the major culprits that makes programming expensive.
其中的两个安全问题就是初始化和清除(Initialization and Cleanup),在C中,如果程序员忘记初始化一个变量,将会出现bugs,尤其是对于现成的库,当程序员不知道如何初始化库的一个组件时(而这些初始化是必须)。清除(Cleanup)是另外一个特殊的问题,当完成工作时,会很容易忘记需要清除的资源,而这些资源一直被你之前的程序占用着,而这往往会导致资源的耗尽(running out of resources),尤其是内存。
注意:在C++中,引入了构造器(constructor)的概念,当一个对象被创建时,这么特殊的方法会被自动的调用。Java同样采用了构造器,并且引入了垃圾回收器(garbage collector),自动回收那些不再被占用的内存资源。
Guaranteed initialization with the constructor(构造器保证初始化)
每一个创建的方法都会调用initialize(),它的名字表明这个方法将会在对象被使用之前调用,但不幸的是,这意味着用户必须记住调用方法。在Java中,类的设计者通过提供构造器来每个对象的初始化。如果一个类有一个构造器,当一个对象被创建时,在用户着手之前,Java会自动地调用这个构造器,以此来保证初始化。
另外的一个问题是如何命名这个方法。存在两方面的问题。第一个是我们使用的任何名字都可能与打算为某个类成员使用的名字冲突。第二是由于编译器(compiler)的责任是调用构建器,所以它必须知道要调用是哪个方法。C++采取的方案看来是最简单的,且更有逻辑性,所以也在Java里得到了应用:构建器的名字与类名相同。这样一来,就可保证象这样的一个方法(构造器方法)会在初始化期间自动调用。
注意:自动初始化,其实就是指在调用new构造函数时,自动为创建的对象分配内存空间。
下面是一个构造器的简单例子。
1-1 a simple class with construtor
//: initialization/SimpleConstructor.java // Demonstration of a simple constructor. class Rock { Rock() { // This is the constructor System.out.print("Rock "); } } public class SimpleConstructor { public static void main(String[] args) { for(int i = 0; i < 10; i++) new Rock(); } }
输出结果如下:
当一个对象被创建时
new Rock();
Java就会为这个对象分配内存(storage is allocated),并且会调用构造器,这就保证了在我们着手处理处理之前,对象会被正确的初始化。
注意:重申一下的话,构造器的名与类名相同。
没有参数的构造器被称为默认构造器(default constructor),有时也称为无参构造器(no-arg constructor),就像其他的方法,构造器也可以有参数,以此来指定一个对象是如何创建的。可简单地改动上述例子,以便构建器使用自己的自变量(参数)。
1-2 带参数的构造器
//: initialization/SimpleConstructor2.java // Constructors can have arguments. class Rock2 { Rock2(int i) { System.out.print("Rock " + i + " "); } } public class SimpleConstructor2 { public static void main(String[] args) { for(int i = 0; i < 8; i++) new Rock2(i); } }
输出如下:
构建器可以消除大量涉及类的问题,并提高了代码的可读性。比如,在上面的两个例子中,我们并没有看到明显的调用initialize(——在概念上和创建(creation)是独立的。但是在Java中,创建和初始化是统一的概念,二者缺一不可
构造器是一种特殊的方法,因为它没有返回值。而这种没有返回值与void型的返回值有着明显的不同,在void返回值型中,尽管方法本身不会返回什么,但仍然你可以让它返回另一些东西。构建器不返回任何东西,并且你也没有任何选择(不像new表达式会返回刚刚被创建的对象的引用,但是构造器本身不返回任何值)——若存在一个返回值,并且假设我们可以自行选择返回的内容,那么编译器(compiler)无论如何都要知道如何处理那个返回值。
注:文章的代码摘自 Thinking in Java(Fourth Edition)英文版,作者 [美]Bruce Eckef,刘中兵 评注