《Effective Java》阅读笔记4 通过私有构造器强化不可实例化的能力

1.序

在第三节中,我们学习了如何通过不同的方法强化Singleton,但并非所有的类都是需要实例化的。有时候,我们可能需要编写至包含静态方法和静态域的类。这些类的名声很不好,因为有些人在面向对象的语言中滥用这样的类来编写过程化的程序。

尽管如此,它们也确实有它们特有的好处:

  • 1.利用这种类,以java.lang.Math或者java.util.Arrays的方式,把基本类型的值或者数组类型上的相关方法组织起来.
  • 2.我们也可以通过java.util.Collections的方式,把实现特定接口的对象上的静态方法包括工厂方法组织起来。
  • 3.利用这种类可以把final类上的方法组织起来,以取代扩展该类的做法。

以上是我们常用的一些工具类,一般是不希望被实例化的,因为实例化对它没有任何意义

2.思考

1.那么,我们可不可以将不可实例化的类定义为抽象类 ,因为我们知道抽象类是无法实例化的。但这样仍然不能保证,因为其子类依然可以被实例化

2.有一些简单的习惯用法可以确保类不可被实例化。由于只有当类不包含显示的构造器时,编译器才会生成缺省的构造器,因此我们只要让这个类 包含私有构造器 ,他就不能被实例化了:

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

3.优点

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

4.缺点

这种习惯用法也有副作用,它使得一个类不能拥有子类。因为子类的所有构造函数都必须显示或者隐式地调用父类的构造函数,在这种情形下,子类就没有可访问的父类构造器可用了。

5.完整代码

public class UtilityClass {
     // Suppress default constructor for noninstantiability
     private   UtilityClass() {
         throw   new   AssertionError();
     }
 
     public   static   UtilityClass getInstance()
     {
         return   new   UtilityClass ();
     }
}
 
public class Test {
     public static void main(String[] args)
     {
 
         UtilityClass one = UtilityClass .getInstance();
     }
}

上述代码执行了之后,会报如下错误:

Exception in thread “main” java.lang.AssertionError
at org.effectivejava.examples.chapter02.item04.UtilityClass.( UtilityClass.java:8 )
at org.effectivejava.examples.chapter02.item04.UtilityClass.getInstance( UtilityClass.java:13 )
at org.effectivejava.examples.chapter02.item04.Test.main( Test.java:9 )

添加throw new AssertionError()可以成功避免在UtilityClass中实例化UtilityClass类。
可以成功避免如下代码执行:

public class SubUtilityClass extends UtilityClass {
 
}
public class Test {
 
     public static void main(String[] args)
     {
 
        // UtilityClass one = new UtilityClass();
     }
}

当试图继承该类时,会提示如下错误:
Implicit super constructor UtilityClass() is not visible for default constructor. Must define an explicit constructorImplicit super constructor UtilityClass() is not visible for default constructor. Must define an explicit constructor

客户端也无法调用默认的构造器。

6.参考文献

https://blog.csdn.net/u012516166/article/details/78421902
https://my.oschina.net/u/1034176/blog/646861

在这里插入图片描述

本公众号分享自己从程序员小白到经历春招秋招斩获10几个offer的面试笔试经验,其中包括【Java】、【操作系统】、【计算机网络】、【设计模式】、【数据结构与算法】、【大厂面经】、【数据库】期待你加入!!!

1.计算机网络----三次握手四次挥手
2.梦想成真-----项目自我介绍
3.你们要的设计模式来了
4.一字一句教你面试“个人简介”
5.接近30场面试分享
6.你们要的免费书来了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haikuotiankongdong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值