This commit is contained in:
sjsdfg 2019-04-05 15:09:19 +08:00
parent db0ab03d12
commit ed6c73a148

View File

@ -8,16 +8,16 @@
  经验法则很简单:**让每个类或成员尽可能地不可访问。** 换句话说,使用尽可能低的访问级别,与你正在编写的软件的对应功能保持一致。   经验法则很简单:**让每个类或成员尽可能地不可访问。** 换句话说,使用尽可能低的访问级别,与你正在编写的软件的对应功能保持一致。
  对于顶层 (非嵌套的) 类和接口,只有两个可能的访问级别:包级私有package-private和公共的public。如果你使用 public 修饰符声明顶级类或接口,那么它是公开的;否则,它是包级私有的。如果一个顶层类或接口可以被做为包级私有,那么它应该是。通过将其设置为包级私有,可以将其作为实现的一部分,而不是导出的 API你可以修改它、替换它或者在后续版本中消除它而不必担心损害现有的客户端。如果你把它公开你就有义务永远地支持它以保持兼容性。   对于顶层(非嵌套的)类和接口,只有两个可能的访问级别:包级私有package-private和公共的public。如果你使用 public 修饰符声明顶级类或接口,那么它是公开的;否则,它是包级私有的。如果一个顶层类或接口可以被做为包级私有,那么它应该是。通过将其设置为包级私有,可以将其作为实现的一部分,而不是导出的 API你可以修改它、替换它或者在后续版本中消除它而不必担心损害现有的客户端。如果你把它公开你就有义务永远地支持它以保持兼容性。
  如果一个包级私有顶级类或接口只被一个类使用,那么可以考虑这个类作为使用它的唯一类的私有静态嵌套类 (条目 24)。这将它的可访问性从包级的所有类减少到使用它的一个类。但是,减少不必要的公共类的可访问性要比包级私有的顶级类更重要:公共类是包的 API 的一部分,而包级私有的顶级类已经是这个包实现的一部分了。   如果一个包级私有顶级类或接口只被一个类使用,那么可以考虑这个类作为使用它的唯一类的私有静态嵌套类 (条目 24)。这将它的可访问性从包级的所有类减少到使用它的一个类。但是,减少不必要的公共类的可访问性要比包级私有的顶级类更重要:公共类是包的 API 的一部分,而包级私有的顶级类已经是这个包实现的一部分了。
  对于成员 (属性、方法、嵌套类和嵌套接口),有四种可能的访问级别,在这里,按照可访问性从小到大列出:   对于成员 (属性、方法、嵌套类和嵌套接口),有四种可能的访问级别,在这里,按照可访问性从小到大列出:
- private——该成员只能在声明它的顶级类内访问。 - private —— 该成员只能在声明它的顶级类内访问。
- package-private——成员可以从被声明的包中的任何类中访问。从技术上讲如果没有指定访问修饰符 (接口成员除外,它默认是公共的),这是默认访问级别。 - package-private —— 成员可以从被声明的包中的任何类中访问。从技术上讲,如果没有指定访问修饰符 (接口成员除外,它默认是公共的),这是默认访问级别。
- protected——成员可以从被声明的类的子类中访问 (受一些限制JLS6.6.2),以及它声明的包中的任何类。 - protected —— 成员可以从被声明的类的子类中访问受一些限制JLS6.6.2,以及它声明的包中的任何类。
- public——该成员可以从任何地方被访问。 - public —— 该成员可以从任何地方被访问。
  在仔细设计你的类的公共 API 之后,你的反应应该是让所有其他成员设计为私有的。 只有当同一个包中的其他类真的需要访问成员时,需要删除私有修饰符,从而使成员包成为包级私有的。 如果你发现自己经常这样做,你应该重新检查你的系统的设计,看看另一个分解可能产生更好的解耦的类。 也就是说,私有成员和包级私有成员都是类实现的一部分,通常不会影响其导出的 API。 但是,如果类实现 Serializable 接口(条目 86 和 87则这些属性可以“泄漏leak”到导出的 API 中。   在仔细设计你的类的公共 API 之后,你的反应应该是让所有其他成员设计为私有的。 只有当同一个包中的其他类真的需要访问成员时,需要删除私有修饰符,从而使成员包成为包级私有的。 如果你发现自己经常这样做,你应该重新检查你的系统的设计,看看另一个分解可能产生更好的解耦的类。 也就是说,私有成员和包级私有成员都是类实现的一部分,通常不会影响其导出的 API。 但是,如果类实现 Serializable 接口(条目 86 和 87则这些属性可以“泄漏leak”到导出的 API 中。
@ -27,7 +27,7 @@
  为了便于测试你的代码,你可能会想要让一个类,接口或者成员更容易被访问。 这没问题。 为了测试将公共类的私有成员指定为包级私有是可以接受的,但是提高到更高的访问级别却是不可接受的。 换句话说,将类,接口或成员作为包级导出的 API 的一部分来促进测试是不可接受的。 幸运的是,这不是必须的,因为测试可以作为被测试包的一部分运行,从而获得对包私有元素的访问。   为了便于测试你的代码,你可能会想要让一个类,接口或者成员更容易被访问。 这没问题。 为了测试将公共类的私有成员指定为包级私有是可以接受的,但是提高到更高的访问级别却是不可接受的。 换句话说,将类,接口或成员作为包级导出的 API 的一部分来促进测试是不可接受的。 幸运的是,这不是必须的,因为测试可以作为被测试包的一部分运行,从而获得对包私有元素的访问。
  **公共类的实例属性很少公开 (条目 16)。** 如果一个实例属性是非 final 的,或者是对可变对象的引用,那么通过将其公开,你就放弃了限制可以存储在属性中的值的能力。这意味着你放弃了执行涉及该属性的不变量的能力。另外,当属性被修改时,就放弃了采取任何操作的能力,**因此公共可变属性的类通常不是线程安全的** 。即使属性是 final 的,并且引用了一个不可变的对象,通过使它公开,你就放弃切换到不存在属性的新的内部数据表示的灵活性。   **公共类的实例属性很少公开(条目 16。** 如果一个实例属性是非 final 的,或者是对可变对象的引用,那么通过将其公开,你就放弃了限制可以存储在属性中的值的能力。这意味着你放弃了执行涉及该属性的不变量的能力。另外,当属性被修改时,就放弃了采取任何操作的能力,**因此公共可变属性的类通常不是线程安全的** 。即使属性是 final 的,并且引用了一个不可变的对象,通过使它公开,你就放弃切换到不存在属性的新的内部数据表示的灵活性。
  同样的建议适用于静态属性,但有一个例外。 假设常量是类的抽象的一个组成部分,你可以通过 public static final 属性暴露常量。 按照惯例,这些属性的名字由大写字母组成,字母用下划线分隔(条目 68。 很重要的一点是,这些属性包含基本类型的值或对不可变对象的引用(条目 17。 包含对可变对象的引用的属性具有非 final 属性的所有缺点。 虽然引用不能被修改,但引用的对象可以被修改,并会带来灾难性的结果。   同样的建议适用于静态属性,但有一个例外。 假设常量是类的抽象的一个组成部分,你可以通过 public static final 属性暴露常量。 按照惯例,这些属性的名字由大写字母组成,字母用下划线分隔(条目 68。 很重要的一点是,这些属性包含基本类型的值或对不可变对象的引用(条目 17。 包含对可变对象的引用的属性具有非 final 属性的所有缺点。 虽然引用不能被修改,但引用的对象可以被修改,并会带来灾难性的结果。
@ -64,6 +64,6 @@ public static final Thing[] values() {
  与四个主要访问级别不同这两个基于模块的级别主要是建议advisory。 如果将模块的 JAR 文件放在应用程序的类路径而不是其模块路径中,那么模块中的包将恢复为非模块化行为:包的公共类的所有公共类和受保护成员都具有其普通的可访问性,不管包是否由模块导出[Reinhold1.2]。 新引入的访问级别严格执行的地方是 JDK 本身Java 类库中未导出的包在模块之外真正无法访问。   与四个主要访问级别不同这两个基于模块的级别主要是建议advisory。 如果将模块的 JAR 文件放在应用程序的类路径而不是其模块路径中,那么模块中的包将恢复为非模块化行为:包的公共类的所有公共类和受保护成员都具有其普通的可访问性,不管包是否由模块导出[Reinhold1.2]。 新引入的访问级别严格执行的地方是 JDK 本身Java 类库中未导出的包在模块之外真正无法访问。
  对于典型的 Java 程序员来说,不仅程序模块所提供的访问保护存在局限性,而且在本质上是很大程度上建议性的;为了利用它,你必须把你的包组合成模块,在模块声明中明确所有的依赖关系,重新安排你的源码树层级,并采取特殊的行动来适应你的模块内任何对非模块化包的访问[Reinhold 3]。 现在说模块是否会在 JDK 之外得到广泛的使用还为时尚早。 与此同时,除非你有迫切的需要,否则似乎最好避免它们。   对于典型的 Java 程序员来说,不仅程序模块所提供的访问保护存在局限性,而且在本质上是很大程度上建议性的;为了利用它,你必须把你的包组合成模块,在模块声明中明确所有的依赖关系,重新安排你的源码树层级,并采取特殊的行动来适应你的模块内任何对非模块化包的访问[Reinhold, 3]。 现在说模块是否会在 JDK 之外得到广泛的使用还为时尚早。 与此同时,除非你有迫切的需要,否则似乎最好避免它们。
  总而言之,应该尽可能地减少程序元素的可访问性(在合理范围内)。 在仔细设计一个最小化的公共 API 之后,你应该防止任何散乱的类,接口或成员成为 API 的一部分。 除了作为常量的公共静态 `final` 属性之外,公共类不应该有公共属性。 确保 `public static final` 属性引用的对象是不可变的。   总而言之,应该尽可能地减少程序元素的可访问性(在合理范围内)。 在仔细设计一个最小化的公共 API 之后,你应该防止任何散乱的类,接口或成员成为 API 的一部分。 除了作为常量的公共静态 `final` 属性之外,公共类不应该有公共属性。 确保 `public static final` 属性引用的对象是不可变的。