创建和销毁对象-通过私有构造器强化不可实例化的能力

306 阅读2分钟

这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战

前言

本文介绍如何通过私有构造器来帮助实现类的不可实例化。主要在自己写工具类的时候需要注意这一点,不要认为不加构造器就没有构造器了!!!

缺省构造器带来的问题

有的时候你想提供只包含静态方法和静态域的类,比如一些工具类,这些工具类我们并不想实例化,而且实例对它没有任何意义了。比如java.util.Math 等包。

然而在缺少显式构造器的情况下,编译器会自动提供一个公有,无参(英文是parameterless)的缺省构造器,在我们提供的Api中常常能够看到它,有的时候,用户不理解的情况下有可能就会错误的实例化。

比如我们可以在hutool里面看到反编译的代码中就有对应的这种情况出现。

image.png

尝试将这个类做成抽象类也不现实,因为有可能用户以为你这个类就是只有被继承才能用,给你哐哐整个子类,照样可以实例化

解决方法

最简单且直接的方式就是让类包含一个显式的私有构造器就可以了。

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

可以通过将构造器方法访问标识符设置为private,将构造器方法私有化,从而将对象强化为不可实例化

注意私有构造器里面的AssertionError,它可以防止在这个类的内部调用这个实例化构造器,也可以防止用户通过反射来调用。不过一般都没什么人写,我们可以去看Math包中的代码,也没有throw这个Error。

image.png 可以看到那里写的大大的不要让任何人实例化这个类。

副作用

这种方式也有一些副作用,就是使一个类不能够被子类化。因为所有构造器都必须显式或隐式地调用超类的构造方法,在这种情况下,子类就没有可以访问的超类构造方法调用了,因为超类的唯一一个构造器也被private了。