Skip to content

【OnJava-七】封装

访问控制(或者隐藏实现)与” 最初的实现不恰当” 有关。

所有优秀的作者——包括这些编写软件的人——都知道一件好的作品都是经过反复打磨才变得优秀的。如果你把一段代码置于某个位置一段时间,过一会重新来看,你可能发现更好的实现方式。这是重构的原动力之一,重构就是重写可工作的代码,使之更加可读,易懂,因而更易维护。

但是,在修改和完善代码的愿望下,也存在巨大的压力。通常,客户端程序员希望你的代码在某些方面保持不变。所以你想修改代码,但他们希望代码保持不变。由此引出了面向对象设计中的一个基本问题:” 如何区分变动的事物和不变的事物”

这个问题对于类库而言尤其重要。类库的使用者必须依赖他们所使用的那部分类库,并且知道如果使用了类库的新版本,不需要改写代码。另一方面,类库的开发者必须有修改和改进类库的自由,并保证客户代码不会受这些改动影响。

这可以通过约定解决。例如,类库开发者必须同意在修改类库中的一个类时,不会移除已有的方法,因为那样将会破坏客户端程序员的代码。与之相反的情况更加复杂。在有成员属性的情况下,类库开发者如何知道哪些属性被客户端程序员使用?这同样会发生在那些只为实现类库类而创建的方法上,它们也不是设计成可供客户端程序员调用的。如果类库开发者想删除旧的实现,添加新的实现,结果会怎样呢?任何这些成员的改动都可能破环客户端程序员的代码。因此类库开发者会被束缚,不能修改任何事物。

为了解决这一问题,Java 提供了访问修饰符供类库开发者指明哪些对于客户端程序员是可用的,哪些是不可用的。访问控制权限的等级,从” 最大权限” 到” 最小权限” 依次是:publicprotected,包访问权限(没有关键字)和 private。根据上一段的内容,你可能会想,作为一名类库设计者,你会尽可能将一切都设为 private,仅向客户端程序员暴露你愿意他们使用的方法。这就是你通常所做的,尽管这与使用其他语言(尤其是 C)编程和访问不受任何限制的人们的直觉相违背。

然而,构建类库的概念和对类库组件的访问控制仍然不完善。其中仍然存在问题就是如何将类库组件捆绑到一个内聚到类库单元中。Java 中通过 package 关键字加以控制,类是在相同包下还是不同包下会影响访问修饰符。所以在这章开始,你将会学习如何将类库组件置于同一个包下,之后你就能明白访问修饰符的全部含义。

包的概念

包内包含一组类,它们被组织在一个单独的命名空间下。

一个 Java 源代码文件称为一个 编译单元(有时也称_翻译单元_)。每个编译单元的文件名后缀必须是 .java

在编译单元中可以有一个 public 类,它的类名必须与文件名相同(包括大小写,但不包括后缀名 .java)。

每个编译单元中只能有一个 public 类,否则编译器不接受。

如果这个编译单元中还有其他类,那么在包之外是无法访问到这些类的,因为它们不是 public 类,此时它们支持主 public 类。

代码组织

包访问权限

  • public
    • 那么无论是谁,无论在哪,都可以访问
  • private
    • 子类也不能访问
  • 默认
    • 自己包内可访问
  • protected
    • 继承的类既可以访问 public 成员,也可以访问 protected 成员
    • 同一个包内的其他类可以访问(默认访问权限特性)

外部要访问一个包内的方法,不仅需要class是public的,method也要是public的。

  • 每个编译单元(即每个文件)中只能有一个 public
  • 每个编译单元(即每个文件)中只能有一个 public