Effective Java 4.通过私有构造器强化不可实例化的能力

43 阅读1分钟

有时可能需要编写只包含静态方法和静态成员的类。例如:工具类。不论是JDK还是平时工作中的项目,总是会有很多的工具类。 这样的工具类不希望被实例化,因为实例化并没有太大的意义。 但是在缺少显式构造器的情况下,编译器会自动提供一个公有的无参构造器。 如何尝试让这些工具类不被实例化呢?

  1. 企图通过将类做成抽象类来强制该类不可被实例化是行不通的,该类可以被子类化,可以通过匿名内部类的方式进行实例化。这样做甚至会误导用户,以为这种类是专门为了继承而设计的
public class UtilDemo {
    public static void main(String[] args) {
        new XxUtil() {
            @Override
            public void test() {
                System.out.println("被实例化了");
            }
        };
    }
}
  1. 由于显式的构造器是私有的,不可以在类的外部访问。AssertionError不是必须的,可以是任何错误,这样做可以避免别的地方调用内部的构造器。保证该类在任何情况下都不会被实例化
public  class XxUtil {
    private XxUtil(){
        throw new AssertionError();
    }
}

public class UtilDemo {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 这种方式是创建不了的
        //XxUtil xxUtil = new XxUtil();
        Class<XxUtil> clazz = XxUtil.class;
        Constructor<XxUtil> ctor = clazz.getDeclaredConstructor();
        ctor.setAccessible(true);
        // 通过这种方式报错: java.lang.AssertionError
        XxUtil xxUtil = ctor.newInstance();
        System.out.println(xxUtil);
    }
}

这种做法的副作用,就是不能被子类化。所有的构造器都必须显式或隐式调用超类构造器,在这种情形下,子类就没有可访问的超类构造器可调用了。 但是,一般情况下,工具类是没有子类的