在Java中亦可用访问指示符判断出一个库内的哪些类可由那个库的用户使用若想一个类能由客户程序员调用可在类主体的起始花括号前面某处放置一个public关键字它控制着客户程序员是否能够创建属于这个类的一个对象 为控制一个类的访问指示符必须在关键字class之前出现所以我们能够使用 public class Widget { 也就是说假若我们的库名是mylib那么所有客户程序员都能访问Widget——通过下述语句 import mylibWidget; 或者 import mylib*; 然而我们同时还要注意到一些额外的限制 () 每个编译单元(文件)都只能有一个public类每个编译单元有一个公共接口的概念是由那个公共类表达出来的根据自己的需要它可拥有任意多个提供支撑的友好类但若在一个编译单元里使用了多个public类编译器就会向我们提示一条出错消息 () public类的名字必须与包含了编译单元的那个文件的名字完全相符甚至包括它的大小写形式所以对于Widget来说文件的名字必须是Widgetjava而不应是widgetjava或者WIDGETjava同样地如果出现不符就会报告一个编译期错误 () 可能(但并常见)有一个编译单元根本没有任何公共类此时可按自己的意愿任意指定文件名 如果已经获得了mylib内部的一个类准备用它完成由Widget或者mylib内部的其他某些public类执行的任务此时又会出现什么情况呢?我们不希望花费力气为客户程序员编制文档并感觉以后某个时候也许会进行大手笔的修改并将自己的类一起删掉换成另一个不同的类为获得这种灵活处理的能力需要保证没有客户程序员能够依赖自己隐藏于mylib内部的特定实施细节为达到这个目的只需将public关键字从类中剔除即可这样便把类变成了友好的(类仅能在包内使用) 注意不可将类设成private(那样会使除类之外的其他东西都不能访问它)也不能设成protected(注释④)因此我们现在对于类的访问只有两个选择友好的或者public若不愿其他任何人访问那个类可将所有构建器设为private这样一来在类的一个static成员内部除自己之外的其他所有人都无法创建属于那个类的一个对象(注释⑤)如下例所示 //: Lunchjava // Demonstrates class access specifiers // Make a class effectively private // with private constructors: class Soup { private Soup() {} // () Allow creation via static method: public static Soup makeSoup() { return new Soup(); } // () Create a static object and // return a reference upon request // (The Singleton pattern): private static Soup ps = new Soup(); public static Soup access() { return ps; } public void f() {} } class Sandwich { // Uses Lunch void f() { new Lunch(); } } // Only one public class allowed per file: public class Lunch { void test() { // Cant do this! Private constructor: //! Soup priv = new Soup(); Soup priv = SoupmakeSoup(); Sandwich f = new Sandwich(); Soupaccess()f(); } } ///:~ ④实际上Java 内部类既可以是受到保护的也可以是私有的但那属于特别情况第章会详细解释这个问题 ⑤亦可通过从那个类继承来实现 迄今为止我们创建过的大多数方法都是要么返回void要么返回一个基本数据类型所以对下述定义来说 public static Soup access() { return psl; } 它最开始多少会使人有些迷惑位于方法名(access)前的单词指出方法到底返回什么在这之前我们看到的都是void它意味着什么也不返回(void在英语里是虚无的意思但亦可返回指向一个对象的句柄此时出现的就是这个情况该方法返回一个句柄它指向类Soup的一个对象 Soup类向我们展示出如何通过将所有构建器都设为private从而防止直接创建一个类请记住假若不明确地至少创建一个构建器就会自动创建默认构建器(没有自变量)若自己编写默认构建器它就不会自动创建把它变成private后就没人能为那个类创建一个对象但别人怎样使用这个类呢?上面的例子为我们揭示出了两个选择第一个选择我们可创建一个static方法再通过它创建一个新的Soup然后返回指向它的一个句柄如果想在返回之前对Soup进行一些额外的操作或者想了解准备创建多少个Soup对象(可能是为了限制它们的个数)这种方案无疑是特别有用的 第二个选择是采用设计方案(Design Pattern)技术本书后面会对此进行详细介绍通常方案叫作独子因为它仅允许创建一个对象类Soup的对象被创建成Soup的一个static private成员所以有一个而且只能有一个除非通过public方法access()否则根本无法访问它 正如早先指出的那样如果不针对类的访问设置一个访问指示符那么它会自动默认为友好的这意味着那个类的对象可由包内的其他类创建但不能由包外创建请记住对于相同目录内的所有文件如果没有明确地进行package声明那么它们都默认为那个目录的默认包的一部分然而假若那个类一个static成员的属性是public那么客户程序员仍然能够访问那个static成员——即使它们不能创建属于那个类的一个对象 |