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.你们要的免费书来了