`

第4条:通过私有构造器强化不可实例化的能力

阅读更多
第4条:通过私有构造器强化不可实例化的能力

有时候,可能需要编写只包含静态方法和静态域的类。这些类的名声很不好,因为有些人滥用它们来避免从对象的角度进行思考,但是它们也确实有它们特有的用处。我们可以利用这种类,以java.lang.Math或者java.util.Arrays的方式,把基本类型的值或者数组类型上的相关方法组织起来。我们也可以通过java.util.Collections的方式,把实现特定接口的对象上的静态方法(包括工厂方法,见第1条)组织起来。最后,还可以利用这种类把final类上的方法组织起来,以取代扩展该类的做法。

这样的工具类(utility class)不是要被实例化的:实例没有任何意义。然而,在缺少显式构造器的情况下,编译器会自动提供一个公有的、无参的默认构造器(default constructor)。对于用户而言,这个构造器与其他的构造器没有任何区别。在已发行的API中常常可以看到一些被无意识地实例化的类。

企图通过将类做成抽象类来强制该类不可被实例化,这是行不通的。该类可以被子类化,并且该子类也可以被实例化。这样做甚至会误导用户,以为这种类是专门为了继承而设计的(见第17条)。然而,有一些简单的习惯用法可以确保类不可被实例化。由于只有当类不包含显式的构造器时,编译器才会生成默认的构造器,因此让类包含私有构造器,它就不能被实例化了:

// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
    throw new AssertionError();
}
... // Remainder omitted
}


由于显式的构造器是私有的,所以不可以在该类的外部访问它。AssertionError不是绝对必要,但是它可以避免不小心在类的内部调用构造器。它保证该类在任何情况下都不会被实例化。这种习惯用法有点违反直觉,好像构造器就是专门设计成不能调用一样。因此,明智的做法就是在代码中增加一条注释,如上所示。

这种习惯用法也有副作用,它使得一个类不能被子类化。所有的构造器都必须显式或隐式地调用超类(superclass)构造器,在这种情形下,子类就没有可访问的超类构造器来调用了。
分享到:
评论

相关推荐

    effective Java(第3版)各章节的中英文学习参考(已完成).zip

    请考虑构建器)Item 3: Enforce the singleton property with a private constructor or an enum type(使用私有构造函数或枚举类型实施单例属性)第 4 条使用私有构造函数强制不可实例化(用初始化构造函数实施不可...

    Effective-Java读书笔记(上)

    **通过私有构造器强化不可实例化的类**: - **工具类**:通常,工具类应包含私有构造器以防止被实例化。 - **副作用**:使用私有构造器的一个副作用是使得该类不能被继承。 **避免创建不必要的对象**: 1. **不可...

    Effective Java第三版1

    4. **不可实例化**:使用私有构造器可以强化一个类只能通过特定方式(如静态方法)访问的特性。 5. **依赖注入**:推荐使用依赖注入而非硬编码依赖,以提高代码灵活性和测试性。 6. **避免不必要的对象创建**:对象...

    effective-java.pdf

    - 不可实例化:当类设计为工具类,不希望有实例存在时,可以使用私有构造器来防止外部实例化。 - 不可变值类:使用预先构建的实例或构造时缓存实例,确保不会创建重复对象。 4. 基于接口的框架:通过接口提供静态...

    JAVA基础第章继承与多态练习题.docx

    - 私有类 `Base` 的实例化会在 `Pri` 类的实例化过程中进行,但由于 `Base` 中的 `i` 是局部变量,它的输出只会在 `Base` 构造器内部显示。而 `Pri` 类的静态变量 `i` 在类加载时初始化,所以输出只有 `200`,答案...

    Java中对象的生命周期 ..doc

    4. **私有构造函数**: - 私有构造函数只能在当前类内部使用。 - 通常用于单例模式或当类不希望被实例化时使用。 #### 四、对象的销毁 1. **对象生命周期的结束**: - 当没有任何引用指向该对象时,即对象成为...

    java中构造方法和方法全面解析.pdf

    - **构造方法**:`super`用于调用超类的构造器,确保子类在实例化时能正确初始化父类的状态。同样,`super`调用必须位于构造方法的第一行。 - **普通方法**:`super`用于调用被重写的超类方法,确保在子类中能够执行...

    JavaScript与OOP

    - **类属性**:直接在构造函数上定义,可以被所有实例共享,无需通过`new`实例化。 8. **对象方法** - **私有方法**:仅在构造函数内部可用。 - **实例方法**:在对象实例化后定义,通过`this`访问。 - **类...

    第二季:C#面向对象基础(苏坤主讲).doc

    6. **类的引用**:非静态(`static`)的方法或属性需要通过实例化对象来访问,而静态成员则可以直接通过类名来访问。 7. **访问修饰符**:C#提供了四个主要的访问修饰符:`public`(公开)、`internal`(内部)、`...

    VC++实例.pdf

    - **静态控件:** 用于显示不可编辑的文本或图标。 **6.5 文本编辑控件** - **编辑控件:** 允许用户输入文本。 **6.6 列表框控件** - **列表框:** 显示列表供用户选择。 **6.7 组合框** - **组合框:** 结合...

    Visual C# 2005编程技巧大全第四部分

    《Visual C# 2005编程技巧大全第四部分》主要涵盖了C#语言在2005版本中的高级特性和实战应用。Visual C# 2005是微软.NET Framework的重要组成部分,它提供了丰富的功能和工具,使得开发高效、安全的桌面和Web应用...

    编程技能强化作业答案(JDBC+网络编程+注解+反射).zip

    这份作业答案涵盖了以上四个关键领域,通过实际操作和解答,可以巩固理论知识,提升编程能力。建议结合代码示例和练习逐步学习,加深理解,同时注意将学到的知识应用到实际项目中,这样才能真正提升编程技能。

    java练习三.docx

    3. 类的实例化:在给定的代码中,第四行尝试将父类引用指向子类实例,这是不允许的,因此会出现编译错误。 4. 访问修饰符:私有(private)成员只能在定义它的类内部访问,受保护(protected)成员在包内和子类中可...

    j2ee(1)asdfasdf

    - `java.lang.Double`:不可实例化(F),`Double` 是一个包装类,用于包装 `double` 基本类型,但其构造器是私有的,不能直接创建实例。 - `java.lang.Math`:不可实例化(F),该类包含数学函数,为静态方法提供...

    JAVA笔记总结

    14. **final修饰构造器**:用`final`修饰的构造器不可被子类重写。 15. `equals()`方法:重写`Object`类的`equals()`方法可以自定义对象的相等性比较。 16. **线程**:Java提供了两种创建线程的方式:一是继承`...

    第四章 在Ioc容器中装配Bean

    在探讨Spring 3.X企业应用开发过程中,第四章的内容聚焦于如何在Spring框架的核心组件——IoC(控制反转)容器中装配Bean。在Spring框架中,Bean装配是指Spring容器将应用程序中的对象进行实例化、配置以及组装的...

Global site tag (gtag.js) - Google Analytics