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

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

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





…………………………………………………………Page 134……………………………………………………………

  }  

} ///:~  

  

这个例子向我们证明了使用private 的方便:有时可能想控制对象的创建方式,并防止有人直接访问一个特 

定的构建器(或者所有构建器)。在上面的例子中,我们不可通过它的构建器创建一个Sundae 对象;相反, 

必须调用makeASundae ()方法来实现(注释③)。  

  

③:此时还会产生另一个影响:由于默认构建器是唯一获得定义的,而且它的属性是 private,所以可防止 

对这个类的继承(这是第6 章要重点讲述的主题)。  

  

若确定一个类只有一个“助手”方法,那么对于任何方法来说,都可以把它们设为private,从而保证自己 

不会误在包内其他地方使用它,防止自己更改或删除方法。将一个方法的属性设为private 后,可保证自己 

一直保持这一选项(然而,若一个句柄被设为 private,并不表明其他对象不能拥有指向同一个对象的 

public 句柄。有关“别名”的问题将在第 12 章详述)。  



5。2。4 protected :“友好的一种”  



protected (受到保护的)访问指示符要求大家提前有所认识。首先应注意这样一个事实:为继续学习本书一 

直到继承那一章之前的内容,并不一定需要先理解本小节的内容。但为了保持内容的完整,这儿仍然要对此 

进行简要说明,并提供相关的例子。  

protected 关键字为我们引入了一种名为“继承”的概念,它以现有的类为基础,并在其中加入新的成员, 

同时不会对现有的类产生影响——我们将这种现有的类称为“基础类”或者“基本类”(Base Class)。亦 

可改变那个类现有成员的行为。对于从一个现有类的继承,我们说自己的新类“扩展”(extends)了那个现 

有的类。如下所示:  

class Foo extends Bar {  

类定义剩余的部分看起来是完全相同的。  

若新建一个包,并从另一个包内的某个类里继承,则唯一能够访问的成员就是原来那个包的 public 成员。当 

然,如果在相同的包里进行继承,那么继承获得的包能够访问所有“友好”的成员。有些时候,基础类的创 

建者喜欢提供一个特殊的成员,并允许访问衍生类。这正是protected 的工作。若往回引用5。2。2 小节 

 “public:接口访问”的那个Cookie。java 文件,则下面这个类就不能访问“友好”的成员:  

  

//: ChocolateChip。java  

// Can't access friendly member  

// in another class  

import c05。dessert。*;  

  

public class ChocolateChip extends Cookie {  

  public ChocolateChip() {  

   System。out。println(  

     〃ChocolateChip constructor〃);  

  }  

  public static void main(String'' args) {  

    ChocolateChip x = new ChocolateChip();  

    //! x。foo(); // Can't access foo  

  }  

} ///:~  

  

对于继承,值得注意的一件有趣的事情是倘若方法 foo()存在于类Cookie 中,那么它也会存在于从Cookie 

继承的所有类中。但由于foo()在外部的包里是“友好”的,所以我们不能使用它。当然,亦可将其变成 

public。但这样一来,由于所有人都能自由访问它,所以可能并非我们所希望的局面。若象下面这样修改类 

Cookie:  

  

public class Cookie {  



                                                                                    133 


…………………………………………………………Page 135……………………………………………………………

  public Cookie() {   

    System。out。println(〃Cookie constructor〃);  

  }  

  protected void foo() {  

    System。out。println(〃foo〃);   

  }  

}  

  

那么仍然能在包dessert 里“友好”地访问 foo(),但从Cookie 继承的其他东西亦可自由地访问它。然而, 

它并非公共的(public)。  



5。3 接口与实现  



我们通常认为访问控制是“隐藏实施细节”的一种方式。将数据和方法封装到类内后,可生成一种数据类 

型,它具有自己的特征与行为。但由于两方面重要的原因,访问为那个数据类型加上了自己的边界。第一个 

原因是规定客户程序员哪些能够使用,哪些不能。我们可在结构里构建自己的内部机制,不用担心客户程序 

员将其当作接口的一部分,从而自由地使用或者“滥用”。  

这个原因直接导致了第二个原因:我们需要将接口同实施细节分离开。若结构在一系列程序中使用,但用户 

除了将消息发给public 接口之外,不能做其他任何事情,我们就可以改变不属于 public 的所有东西(如 

 “友好的”、protected 以及private),同时不要求用户对他们的代码作任何修改。  

我们现在是在一个面向对象的编程环境中,其中的一个类(class)实际是指“一类对象”,就象我们说“鱼 

类”或“鸟类”那样。从属于这个类的所有对象都共享这些特征与行为。“类”是对属于这一类的所有对象 

的外观及行为进行的一种描述。  

在一些早期 OOP 语言中,如 Simula…67,关键字class 的作用是描述一种新的数据类型。同样的关键字在大 

多数面向对象的编程语言里都得到了应用。它其实是整个语言的焦点:需要新建数据类型的场合比那些用于 

容纳数据和方法的“容器”多得多。  

在Java 中,类是最基本的 OOP 概念。它是本书未采用粗体印刷的关键字之一——由于数量太多,所以会造成 

页面排版的严重混乱。  

为清楚起见,可考虑用特殊的样式创建一个类:将 public 成员置于最开头,后面跟随protected、友好以及 

private 成员。这样做的好处是类的使用者可从上向下依次阅读,并首先看到对自己来说最重要的内容(即 

public 成员,因为它们可从文件的外部访问),并在遇到非公共成员后停止阅读,后者已经属于内部实施细 

节的一部分了。然而,利用由 javadoc 提供支持的注释文档(已在第 2 章介绍),代码的可读性问题已在很 

大程度上得到了解决。  

  

public class X {  

  public void pub1( ) { /* 。 。 。 */ }  

  public void pub2( ) { /* 。 。 。 */ }  

  public void pub3( ) { /* 。 。 。 */ }  

  private void priv1( ) { /* 。 。 。 */ }  

  private void priv2( ) { /* 。 。 。 */ }  

  private void priv3( ) { /* 。 。 。 */ }  

  private int i;  

  // 。 。 。  

}  

  

由于接口和实施细节仍然混合在一起,所以只是部分容易阅读。也就是说,仍然能够看到源码——实施的细 

节,因为它们需要保存在类里面。向一个类的消费者显示出接口实际是“类浏览器”的工作。这种工具能查 

找所有可用的类,总结出可对它们采取的全部操作(比如可以使用哪些成员等),并用一种清爽悦目的形式 

显示出来。到大家读到这本书的时候,所有优秀的 Java 开发工具都应推出了自己的浏览器。  



                                                                               134 


…………………………………………………………Page 136……………………………………………………………

5。4 类访问  



在Java 中,亦可用访问指示符判断出一个库内的哪些类可由那个库的用户使用。若想一个类能由客户程序员 

调用,可在类主体的起始花括号前面某处放置一个 public 关键字。它控制着客户程序员是否能够创建属于这 

个类的一个对象。  

为控制一个类的访问,指示符必须在关键字class 之前出现。所以我们能够使用:  

public class Widget {  

也就是说,假若我们的库名是mylib,那么所有客户程序员都能访问Widget——通过下述语句:  

import mylib。Widget;  

或者  

import mylib。*;  

然而,我们同时还要注意到一些额外的限制:  

(1) 每个编译单元(文件)都只能有一个public 类。每个编译单元有一个公共接口的概念是由那个公共类表 

达出来的。根据自己的需要,它可拥有任意多个提供支撑的“友好”类。但若在一个编译单元里使用了多个 

public 类,编译器就会向我们提示一条出错消息。  

(2) public类的名字必须与包含了编译单元的那个文件的名字完全相符,甚至包括它的大小写形式。所以对 

于Widget 来说,文件的名字必须是Widget。java,而不应是widget。java 或者WIDGET。java。同样地,如果 

出现不符,就会报告一个编译期错误。  

(3) 可能(但并常见)有一个编译单元根本没有任何公共类。此时,可按自己的意愿任意指定文件名。  

  

如果已经获得了mylib 内部的一个类,准备用它完成由Widget 或者 mylib 内部的其他某些public 类执行的 

任务,此时又会出现什么情况呢?我们不希望花费力气为客户程序员编制文档,并感觉以后某个时候也许会 

进行大手笔的修改,并将自己的类一起删掉,换成另一个不同的类。为获得这种灵活处理的能力,需要保证 

没有客户程序员能够依赖自己隐藏于mylib 内部的特定实施细节。为达到这个目的,只需将public 关键字从 

类中剔除即可,这样便把类变成了“友好的”(类仅能在包内使用)。  

注意不可将类设成 private (那样会使除类之外的其他东西都不能访问它),也不能设成protected (注释 

④)。因此,我们现在对于类的访问只有两个选择:“友好的”或者 public。若不愿其他任何人访问那个 

类,可将所有构建器设为private。这样一来,在类的一个static 成员内部,除自己之外的其他所有人都无 

法创建属于那个类的一个对象(注释⑤)。如下例所示:  

  

//: Lunch。java  

// Demonstrates class access specifiers。  

// Make a class effectively private  

// with private constructors:  

  

class Soup {  

  private Soup() {}  

  // (1) Allow creation via static method:  

  public static Soup makeSoup() {  

    return new Soup();  

  }  

  // (2) Create a static object and  

  // return a reference upon request。  

  // (The 〃Singleton〃 pattern):  

  private static Soup ps1 = new Soup();  

  public static Soup access() {  

    return ps1;  

  }  

  public void f() {}  

}  

  

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