友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第56章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




在自己的类中定义它们。如下所示(若执行该程序时有麻烦,请参见第3 章3。1。2 小节“赋值”):  

  

//: SprinklerSystem。java  

// position for code reuse  

package c06;  

  

class WaterSource {  

  private String s;  

  WaterSource() {  

    System。out。println(〃WaterSource()〃);  

    s = new String(〃Constructed〃);  

  }  

  public String toString() { return s; }  

}  

  

public class SprinklerSystem {  

  private String valve1; valve2; valve3; valve4;  

  WaterSource source;  

  int i;  

  float f;  

  void print() {  

    System。out。println(〃valve1 = 〃 + valve1);  

    System。out。println(〃valve2 = 〃 + valve2);  

    System。out。println(〃valve3 = 〃 + valve3);  

    System。out。println(〃valve4 = 〃 + valve4);  

    System。out。println(〃i = 〃 + i);  

    System。out。println(〃f = 〃 + f);  

    System。out。println(〃source = 〃 + source);  



                                                                                     139 


…………………………………………………………Page 141……………………………………………………………

  }  

  public static void main(String'' args) {  

    SprinklerSystem x = new SprinklerSystem();  

    x。print();  

  }  

} ///:~  

  

WaterSource 内定义的一个方法是比较特别的:toString()。大家不久就会知道,每种非基本类型的对象都 

有一个 toString()方法。若编译器本来希望一个String,但却获得某个这样的对象,就会调用这个方法。所 

以在下面这个表达式中:  

System。out。println(〃source = 〃 + source) ;  

编译器会发现我们试图向一个WaterSource 添加一个String 对象(〃source =〃)。这对它来说是不可接受 

的,因为我们只能将一个字串“添加”到另一个字串,所以它会说:“我要调用toString(),把source 转 

换成字串!”经这样处理后,它就能编译两个字串,并将结果字串传递给一个System。out。println()。每次 

随同自己创建的一个类允许这种行为的时候,都只需要写一个 toString()方法。  

如果不深究,可能会草率地认为编译器会为上述代码中的每个句柄都自动构造对象(由于Java 的安全和谨慎 

的形象)。例如,可能以为它会为WaterSource 调用默认构建器,以便初始化 source。打印语句的输出事实 

上是:  

  

valve1 = null  

valve2 = null  

valve3 = null  

valve4 = null  

i = 0  

f = 0。0  

source = null  

  

在类内作为字段使用的基本数据会初始化成零,就象第 2 章指出的那样。但对象句柄会初始化成null 。而且 

假若试图为它们中的任何一个调用方法,就会产生一次“违例”。这种结果实际是相当好的(而且很有 

用),我们可在不丢弃一次违例的前提下,仍然把它们打印出来。  

编译器并不只是为每个句柄创建一个默认对象,因为那样会在许多情况下招致不必要的开销。如希望句柄得 

到初始化,可在下面这些地方进行:  

(1) 在对象定义的时候。这意味着它们在构建器调用之前肯定能得到初始化。  

(2) 在那个类的构建器中。  

(3) 紧靠在要求实际使用那个对象之前。这样做可减少不必要的开销——假如对象并不需要创建的话。  

  

下面向大家展示了所有这三种方法:  

  

//: Bath。java  

// Constructor initialization with position  

  

class Soap {  

  private String s;  

  Soap() {  

    System。out。println(〃Soap()〃);  

    s = new String(〃Constructed〃);  

  }  

  public String toString() { return s ; }  

}  

  

public class Bath {  

  private String   



                                                                                          140 


…………………………………………………………Page 142……………………………………………………………

    // Initializing at point of definition:  

    s1 = new String(〃Happy〃);   

    s2 = 〃Happy〃;   

    s3; s4;  

  Soap castille;  

  int i;  

  float toy;  

  Bath() {  

    System。out。println(〃Inside Bath()〃);  

    s3 = new String(〃Joy〃);  

    i = 47;  

    toy = 3。14f;  

    castille = new Soap();  

  }  

  void print() {  

    // Delayed initialization:  

    if(s4 == null)  

      s4 = new String(〃Joy〃);  

    System。out。println(〃s1 = 〃 + s1);  

    System。out。println(〃s2 = 〃 + s2);  

    System。out。println(〃s3 = 〃 + s3);  

    System。out。println(〃s4 = 〃 + s4);  

    System。out。println(〃i = 〃 + i);  

    System。out。println(〃toy = 〃 + toy);  

    System。out。println(〃castille = 〃 + castille);  

  }  

  public static void main(String'' args) {  

    Bath b = new Bath();  

    b。print();  

  }  

} ///:~  

  

请注意在Bath 构建器中,在所有初始化开始之前执行了一个语句。如果不在定义时进行初始化,仍然不能保 

证能在将一条消息发给一个对象句柄之前会执行任何初始化——除非出现不可避免的运行期违例。  

下面是该程序的输出:  

  

Inside Bath()  

Soap()  

s1 = Happy  

s2 = Happy  

s3 = Joy  

s4 = Joy  

i = 47  

toy = 3。14  

castille = Constructed  

  

调用print()时,它会填充 s4,使所有字段在使用之前都获得正确的初始化。  



6。2 继承的语法  



继承与Java (以及其他OOP 语言)非常紧密地结合在一起。我们早在第 1 章就为大家引入了继承的概念,并 

在那章之后到本章之前的各章里不时用到,因为一些特殊的场合要求必须使用继承。除此以外,创建一个类 

时肯定会进行继承,因为若非如此,会从Java 的标准根类 Object 中继承。  



                                                                                           141 


…………………………………………………………Page 143……………………………………………………………

用于合成的语法是非常简单且直观的。但为了进行继承,必须采用一种全然不同的形式。需要继承的时候, 

我们会说:“这个新类和那个旧类差不多。”为了在代码里表面这一观念,需要给出类名。但在类主体的起 

始花括号之前,需要放置一个关键字extends,在后面跟随“基础类”的名字。若采取这种做法,就可自动 

获得基础类的所有数据成员以及方法。下面是一个例子:  

  

//: Detergent。java  

// Inheritance syntax & properties  

  

class Cleanser {  

  private String s = new String(〃Cleanser〃);  

  public void append(String a) { s += a; }  

  public void dilute() { append(〃 dilute()〃); }  

  public void apply() { append(〃 apply()〃); }  

  public void scrub() { append(〃 scrub()〃); }  

  public void print() { System。out。println(s); }  

  public static void main(String'' args) {  

    Cleanser x = new Cleanser();  

    x。dilute(); x。apply(); x。scrub();  

    x。print();  

  }  

}  

  

public class Detergent extends Cleanser {  

  // Change a method:  

  public void scrub() {  

    append(〃 Detergent。scrub()〃);  

    super。scrub(); // Call base…class version  

  }  

  // Add methods to the interface:  

  public void foam() { append(〃 foam()〃); }  

  // Test the new class:  

  public static void main(String'' args) {  

    Detergent x = new Detergent();  

    x。dilute();  

    x。apply();  

    x。scrub();  

    x。foam();  

    x。print();  

    System。out。println(〃Testing base class:〃);  

    Cleanser。main(args);  

  }  

} ///:~  

  

这个例子向大家展示了大量特性。首先,在Cleanser append()方法里,字串同一个 s 连接起来。这是用 

 “+=”运算符实现的。同“+”一样,“+=”被Java 用于对字串进行“过载”处理。  

其次,无论 Cleanser 还是Detergent 都包含了一个main()方法。我们可为自己的每个类都创建一个 

main()。通常建议大家象这样进行编写代码,使自己的测试代码能够封装到类内。即便在程序中含有数量众 

多的类,但对于在命令行请求的public 类,只有main()才会得到调用。所以在这种情况下,当我们使用 

 “java Detergent”的时候,调用的是Degergent。main()——即使Cleanser 并非一个public 类。采用这种 

将main()置入每个类的做法,可方便地为每个类都进行单元测试。而且在完成测试以后,毋需将main()删 

去;可把它保留下来,用于以后的测试。  

在这里,大家可看到Deteregent。main()对 Cleanser。main()的调用是明确进行的。  



                                                                                             142 


…………………………………………………………Page 144……………………………………………………………

需要着重强调的是Cleanser 中的所有类都是public 属性。请记住,倘若省略所有访问指示符,则成员默认 

为“友好的”。这样一来,就只允许对包成员进行访问。在这个包内,任何人都可使用那些没有访问指示符 

的方法。例如,Detergent 将不会遇到任何麻烦。然而,假设来自另外某个包的类准备继承Cleanser ,它就 

只能访问那些public 成员。所以在计划继承的时候,一个比较好的规则是将所有字段都设为private,并将 

所有方法都设为public (protected 成员也允许衍生出来的类访问它;以后还会深入探讨这一问题)。当 

然,在一些特殊的场合,我们仍然必须作出一些调整,但这并不是一个好的做法。  

注意Cleanser 在它的接口中含有
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!