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

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

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




如果想创建新类型的一个对象,它就必须是已提供所有定义的一个类。尽管Hero 没有为 fight()明确地提供 

一个定义,但定义是随同ActionCharacter 来的,所以这个定义会自动提供,我们可以创建Hero 的对象。  

在类Adventure 中,我们可看到共有四个方法,它们将不同的接口和具体类作为自己的自变量使用。创建一 

个Hero 对象后,它可以传递给这些方法中的任何一个。这意味着它们会依次上溯造型到每一个接口。由于接 

口是用Java 设计的,所以这样做不会有任何问题,而且程序员不必对此加以任何特别的关注。  

注意上述例子已向我们揭示了接口最关键的作用,也是使用接口最重要的一个原因:能上溯造型至多个基础 

类。使用接口的第二个原因与使用抽象基础类的原因是一样的:防止客户程序员制作这个类的一个对象,以 



                                                                                             175 


…………………………………………………………Page 177……………………………………………………………

及规定它仅仅是一个接口。这样便带来了一个问题:到底应该使用一个接口还是一个抽象类呢?若使用接 

口,我们可以同时获得抽象类以及接口的好处。所以假如想创建的基础类没有任何方法定义或者成员变量, 

那么无论如何都愿意使用接口,而不要选择抽象类。事实上,如果事先知道某种东西会成为基础类,那么第 

一个选择就是把它变成一个接口。只有在必须使用方法定义或者成员变量的时候,才应考虑采用抽象类。  



7。5。2  通过继承扩展接口  



利用继承技术,可方便地为一个接口添加新的方法声明,也可以将几个接口合并成一个新接口。在这两种情 

况下,最终得到的都是一个新接口,如下例所示:  

  

//: HorrorShow。java  

// Extending an interface with inheritance  

  

interface Monster {  

  void menace();  

}  

  

interface DangerousMonster extends Monster {  

  void destroy();  

}  

  

interface Lethal {  

  void kill();  

}  

  

class DragonZilla implements DangerousMonster {  

  public void menace() {}  

  public void destroy() {}  

}  

  

interface Vampire   

    extends DangerousMonster; Lethal {  

  void drinkBlood();  

}  

  

class HorrorShow {  

  static void u(Monster b) { b。menace(); }  

  static void v(DangerousMonster d) {  

    d。menace();  

    d。destroy();  

  }  

  public static void main(String'' args) {  

    DragonZilla if2 = new DragonZilla();  

    u(if2);  

    v(if2);  

  }  

} ///:~  

  

DangerousMonster 是对Monster 的一个简单的扩展,最终生成了一个新接口。这是在DragonZilla 里实现 

的。  

Vampire 的语法仅在继承接口时才可使用。通常,我们只能对单独一个类应用 extends (扩展)关键字。但由 

于接口可能由多个其他接口构成,所以在构建一个新接口时,extends可能引用多个基础接口。正如大家看 

到的那样,接口的名字只是简单地使用逗号分隔。  



                                                                                             176 


…………………………………………………………Page 178……………………………………………………………

7。5。3  常数分组  



由于置入一个接口的所有字段都自动具有 static 和final 属性,所以接口是对常数值进行分组的一个好工 

具,它具有与C 或C++的enum 非常相似的效果。如下例所示:  

  

//: Months。java  

// Using interfaces to create groups of constants  

package c07;  

  

public interface Months {  

  int  

    JANUARY = 1; FEBRUARY = 2; MARCH = 3;   

    APRIL = 4; MAY = 5; JUNE = 6; JULY = 7;   

    AUGUST = 8; SEPTEMBER = 9; OCTOBER = 10;  

    NOVEMBER = 11; DECEMBER = 12;  

} ///:~  

  

注意根据Java 命名规则,拥有固定标识符的 static final基本数据类型(亦即编译期常数)都全部采用大 

写字母(用下划线分隔单个标识符里的多个单词)。  

接口中的字段会自动具备public 属性,所以没必要专门指定。  

现在,通过导入c07。*或c07。Months,我们可以从包的外部使用常数——就象对其他任何包进行的操作那 

样。此外,也可以用类似Months。JANUARY 的表达式对值进行引用。当然,我们获得的只是一个 int,所以不 

象C++的enum 那样拥有额外的类型安全性。但与将数字强行编码(硬编码)到自己的程序中相比,这种(常 

用的)技术无疑已经是一个巨大的进步。我们通常把“硬编码”数字的行为称为“魔术数字”,它产生的代 

码是非常难以维护的。  

如确实不想放弃额外的类型安全性,可构建象下面这样的一个类(注释①):  

  

//: Month2。java  

// A more robust enumeration system  

package c07;  

  

public final class Month2 {  

  private String name;  

  private Month2(String nm) { name = nm; }  

  public String toString() { return name; }  

  public final static Month2  

    JAN = new Month2(〃January〃);   

    FEB = new Month2(〃February〃);  

    MAR = new Month2(〃March〃);  

    APR = new Month2(〃April〃);  

    MAY = new Month2(〃May〃);  

    JUN = new Month2(〃June〃);  

    JUL = new Month2(〃July〃);  

    AUG = new Month2(〃August〃);  

    SEP = new Month2(〃September〃);  

    OCT = new Month2(〃October〃);  

    NOV = new Month2(〃November〃);  

    DEC = new Month2(〃December〃);  

  public final static Month2'' month =  {  

    JAN; JAN; FEB; MAR; APR; MAY; JUN;  

    JUL; AUG; SEP; OCT; NOV; DEC  

  };  

  public static void main(String'' args) {  



                                                                                          177 


…………………………………………………………Page 179……………………………………………………………

    Month2 m = Month2。JAN;  

    System。out。println(m);  

    m = Month2。month'12';  

    System。out。println(m);  

    System。out。println(m == Month2。DEC);  

    System。out。println(m。equals(Month2。DEC));  

  }  

} ///:~  

  

①:是 Rich Hoffarth 的一封E…mail 触发了我这样编写程序的灵感。  

  

这个类叫作 Month2,因为标准 Java 库里已经有一个Month。它是一个 final 类,并含有一个private 构建 

器,所以没有人能从它继承,或制作它的一个实例。唯一的实例就是那些 final static对象,它们是在类本 

身内部创建的,包括:JAN,FEB,MAR 等等。这些对象也在month 数组中使用,后者让我们能够按数字挑选 

月份,而不是按名字(注意数组中提供了一个多余的JAN,使偏移量增加了 1,也使 December 确实成为 12 

月)。在main()中,我们可注意到类型的安全性:m 是一个 Month2 对象,所以只能将其分配给Month2。在 

前面的Months。java 例子中,只提供了 int值,所以本来想用来代表一个月份的 int 变量可能实际获得一个 

整数值,那样做可能不十分安全。  

这儿介绍的方法也允许我们交换使用==或者equals(),就象main()尾部展示的那样。  



7。5。4  初始化接口中的字段  



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