mirror of
https://github.com/Jueee/effective-Java.git
synced 2024-12-28 05:40:27 +08:00
33 lines
2.4 KiB
Markdown
33 lines
2.4 KiB
Markdown
|
## 使用私有构造方法执行非实例化
|
|||
|
|
|||
|
### 示例
|
|||
|
|
|||
|
- [Item04Example01.java](CreatingAndDestroyingObjects/src/main/java/com/jueee/item04/Item04Example01.java):禁止默认构造函数以实现非实例化
|
|||
|
|
|||
|
### 说明
|
|||
|
|
|||
|
偶尔你会想写一个类,它只是一组静态方法和静态属性。
|
|||
|
|
|||
|
这样的类获得了不好的名声,因为有些人滥用这些类而避免以面向对象方式思考,但是它们确实有着特殊的用途。
|
|||
|
|
|||
|
它们可以用来按照`java.lang.Math`或`java.util.Arrays`的方式,在基本类型的数值或数组上组织相关的方法。 它们也可以用于将静态方法(包括工厂(条目 1))分组,用于实现某个接口的对象,其方式为`java.util.Collections`。
|
|||
|
|
|||
|
最后,这样的类可以用于在final类上对方法进行分组,因为不能将它们放在子类中。
|
|||
|
|
|||
|
这样的实用类( utility classes)不是设计用来被实例化的:一个实例是没有意义的。然而,在没有显式构造方法的情况下,编译器提供了一个公共的、无参的默认构造方法。对于用户来说,该构造方法与其他构造方法没有什么区别。在已发布的 API中经常看到无意识的被实例的类。
|
|||
|
|
|||
|
**试图通过创建抽象类来强制执行非实例化是行不通的。**该类可以被子类化,子类可以被实例化。此外,它误导用户认为该类是为继承而设计的(条目 19)。不过,有一个简单的方法来确保非实例化。只有当类不包含显式构造方法时,才会生成一个默认构造方法,**因此可以通过包含一个私有构造方法来实现类的非实例化**:
|
|||
|
|
|||
|
```java
|
|||
|
// 不可实例化的程序类
|
|||
|
class UtilityClass {
|
|||
|
// 禁止默认构造函数以实现非实例化
|
|||
|
private UtilityClass() {
|
|||
|
throw new AssertionError();
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
因为显式构造方法是私有的,所以在类之外是不可访问的。`AssertionError`异常不是严格要求的,但是它提供了一种保证,以防在类中意外地调用构造方法。它保证类在任何情况下都不会被实例化。这个习惯用法有点违反直觉,好像构造方法就是设计成不能调用的一样。因此,如前面所示,添加注释是种明智的做法。
|
|||
|
|
|||
|
这种习惯有一个副作用,阻止了类的子类化。所有的构造方法都必须显式或隐式地调用父类构造方法,而子类则没有可访问的父类构造方法来调用。
|