Java编程思想-第5章 初始化与清理(要点)

  随着计算机革命的发展,“不安全”的编程方式已逐渐成为编程代价高昂的主因之一。

  初始化和清理( cleanup)正是涉及安全的两个问题。许多C程序的错误都源于程序员忘记 初始化变量。特别是在使用程序库时,如果用户不知道如何初始化库的构件(或者是用户必须 进行初始化的其他东西),更是如此。清理也是一个特殊问题,当使用完一个元素时,它对你也 就不会有什么影响了,所以很容易把它忘记。这样一来,这个元素占用的资源就会一直得不到 释放,结果是资源(尤其是内存)用尽。

5.1 用构造器确保初始化

  可以假想为编写的每个类都定义一个 initialized方法。该方法的名称提醒你在使用其对象 之前,应首先调用 initialized。然而,这同时意味着用户必须记得自己去调用此方法。在Java 中,通过提供构造器,类的设计者可确保每个对象都会得到初始化。创建对象时,如果其类 具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造器,从而保证了初始化 的进行。 接下来的问题就是如何命名这个方法。有两个问题:第一,所取的任何名字都可能与类的 某个成员名称相冲突;第二,调用构造器是编译器的责任,所以必须让编译器知道应该调用哪 个方法。C++语言中采用的解决方案看来最简单且更符合逻辑,所以在Java中也采用了这种方 案:即构造器采用与类相同的名称。考虑到在初始化期间要自动调用构造器,这种做法就顺理成章了。

5.2 方法重载

  任何程序设计语言都具备的一项重要特性就是对名字的运用。当创建一个对象时,也就给 此对象分配到的存储空间取了一个名字。所谓方法则是给某个动作取的名字。通过使用名字, 你可以引|用所有的对象和方法。名字起得好可以使系统更易于理解和修改。就好比写散文——目 的是让读者易于理解。 在Java(和C++)里,构造器是强制重载方法名的另一个原因。既然构造器的名字已经由类 名所决定,就只能有一个构造器名。那么要想用多种方式创建一个对象该怎么办呢?假设你要 创建一个类,既可以用标准方式进行初始化,也可以从文件里读取信息来初始化。这就需要两 个构造器:一个默认构造器,另一个取字符串作为形式参数—该字符串表示初始化对象所需 的文件名称。由于都是构造器,所以它们必须有相同的名字,即类名。为了让方法名相同而形 式参数不同的构造器同时存在,必须用到方法重载。同时,尽管方法重载是构造器所必需的, 但它亦可应用于其他方法,且用法同样方便

5.2.2 涉及基本类型的重载

  基本类型能从一个“较小”的类型自动提升至一个“较大”的类型,此过程一旦牵涉到重 载,可能会造成一些混淆。

5.3 默认构造器

5.4 this关键字

this关键字对于将当前对象传递给其他方法也很有用:

//: initialization/Passingthis java

class person{

     public void eat(Apple apple){

         Apple peeled = apple getpeeled();

         System. out. printin("Yummy");

     }

}

class Peeler{

     static Apple peel(Apple apple){

         //... remove peel

         return apple; // Peeled class Apple

     }

     Apple getpeeled(){ return Peeler. peel(this);}

}

public class Passingthis{    

public static void main(String[] args){

        new Person().eat(new Apple)

     }

}/*Output

Yummy *///:

  Apple 需要调用 Peeler.peel()方法,它是一个外部的工具方法,将执行由于某种原因而必须放 在 Apple 外部的操作(也许是因为该外部方法要应用于许多不同的类,而你却不想重复这些代码)。 为了将其自身传递给外部方法, Apple必须使用this关键字。

5.4.1在构造器中调用构造器

  可能为一个类写了多个构造器,有时可能想在一个构造器中调用另一个构造器,以避免重 复代码。可用this关键字做到这一点。 通常写this的时候,都是指“这个对象”或者“当前对象”,而且它本身表示对当前对象的 引用。在构造器中,如果为this添加了参数列表,那么就有了不同的含义。这将产生对符合此参 数列表的某个构造器的明确调用;这样,调用其他构造器就有了直接的途径:

//: initialization/Flower.java

//Calling construc tors with "this"

import static net mindview util. Print.*;

public class Flower{

    int petalCount = 0;

    String s ="initial value";

    Flower(int petals){

        petalcount petals

        print("Constructor w/ int arg only, petalCount= "

               +petalCount);

    Flower(String ss){

        print("Constructor w/ String arg only, s = "+ss);

        s = ss;

    }

    Flower(String s, int petals){

        this(petals);

    //! this(s);// can't call two

        this.s = s;// Another use of "this"

        print("String & int args");

    }

    Flower(){

        this("hi",47);

        print("default constructor (no args)");

    }

    void printPetalCount{

     // this(11): // Not inside non-constructor

        print("petalcount =" + petalcount +" s = " + s);

    }

    public static void main(String[] args ){

        Flower x = new Flower();

        x.printPetalCount();

    }

}/* Output:

Constructor w/ int arg only, petalcount= 47

String & int args

default constructor (no args)

petalCount = 47 s = hi

*///:

  构造器 Flower( String s, int petals)表明:尽管可以用this调用一个构造器,但却不能调用两个。 此外,必须将构造器调用置于最起始处,否则编译器会报错。 这个例子也展示了this的另一种用法。由于参数s的名称和数据成员s的名字相同,所以会产 生歧义。使用 this s来代表数据成员就能解决这个问题。在Java程序代码中经常出现这种写法, 本书中也常这么写。 printPetalCount()方法表明,除构造器之外,编译器禁止在其他任何方法中调用构造器。

5.4.2 static的含义

  了解this关健字之后,就能更全面地理解 static(静态)方法的含义。 static方法就是没有this 的方法。在 static方法的内部不能调用非静态方法°,反过来倒是可以的。而且可以在没有创建 任何对象的前提下,仅仅通过类本身来调用 static方法。这实际上正是 static方法的主要用途。它 很像全局方法。Java中禁止使用全局方法,但你在类中置入 static方法就可以访问其他 static方法 和 static域。

5.5 清理:终结处理和垃圾回收

5.6 成员初始化

  Java尽力保证:所有变量在使用前都能得到恰当的初始化。对于方法的局部变量,Java以编 译时错误的形式来贯彻这种保证。所以如果写成

void f(){

    int i;

    i++; // Error --i not initialized

}

  就会得到一条出错消息,告诉你i可能尚未初始化。当然,编译器也可以为i赋一个默认值,但是 未初始化的局部变量更有可能是程序员的疏忽,所以采用默认值反而会掩盖这种失误。因此强 制程序员提供一个初始值,往往能够帮助找出程序里的缺陷。 要是类的数据成员(即字段)是基本类型,情况就会变得有些不同。正如在“一切都是对 象”一章中所看到的,类的每个基本类型数据成员保证都会有一个初始值。

5.6.1 指定初始化

5.7 构造器初始化

5.7.1 初始化顺序

5.7.2 静态数据的初始化

5.7.3 显示的静态初始化

5.7.4 非静态实例初始化

5.8 数组初始化

5.8.1 可变参数列表

5.9  枚举类型

5.10 总结

  构造器,这种精巧的初始化机制,应该给了读者很强的暗示:初始化在Java中占有至关重 要的地位。C++的发明人 Bjarne Stroustrup在设计C++期间,在针对C语言的生产效率所进行的最 初调査中发现,大量编程错误都源于不正确的初始化。这种错误很难发现,并且不恰当的清理 也会导致类似问题。构造器能保证正确的初始化和清理(没有正确的构造器调用,编译器就不 允许创建对象),所以有了完全的控制,也很安全。

posted @ 2018-03-01 13:30  JackYgy  阅读(154)  评论(0)    收藏  举报