Java是典型的面向对象的语言,在Java泰斗级别书籍《Effective Java》中,第2章(第1章引言)开始变介绍了对象的创建和销毁。本篇文章将重点对该书籍第2章第1条定律——考虑用静态方法代替构造器的讲解进行剖析。
构造器用于初始化创建的类对象,因此不能有以下非访问性质的修饰: abstract, final, native, static, 或者 synchronized。构造器通过构造函数起作用,构造函数具有如下特点:
public class ConstrTest {
ConstrTest() {} //不带参数
ConstrTest(String args,...,Object args) {} //带参数
}
则创建对象时可以通过如下方式:
ConstrTest constrTest1 = new ConstrTest();//无参
ConstrTest constrTest1 = new ConstrTest(String args,...,Object args);//有参
静态方法肯定是带有static 的一种方法,例如
public static String staticMethod( String str) {
return str;
}
静态工厂方法不同于工厂(模式)方法,实际上设计模式里的单例模式是静态工厂方法的一种实现,通过调用静态的方法实现构造函数的功能。具体可以参考本叼研究生时候写的一篇科普性知识。
链接: Java单例模式.
原始方法的对象创建如 Section 1.1 所示。采用静态工厂方(懒汉模式)法如下:
public class ConstrFactoryTest {
private static ConstrFactoryTest cft1;
private ConstrFactoryTest (){}
public static ConstrFactoryTest getCFT() {
if (cft1== null) {
cft1= new ConstrFactoryTest ();
}
return cft1;
}
}
那么便可以通过以下方式创建获取实例。
ConstrFactoryTest.getCFT();
静态工厂方法相较于构造器的第一大优势在于它们有名称
我们知道可以通过静态方法我们可以给对象起名字为大佬、二狗子、三胖等来区分他们;但是构造函数只有一个名字(与类名相同),我们只能通过参数不同来区分,这很不方便。因此这是静态工厂方法的第一个优势。
静态工厂方法相较于构造器的第二大优势在于不必在每次调用的时候都重新创建对象
从静态工厂方法实现方式可以看出,创建对象后,通过调用对象的不同静态方法即可达到原始采用不同构造方法的效果。
静态工厂方法相较于构造器的第三大优势在于可以返回原始类型的任何子类型的对象
根据『里氏替换』原则,即子类能替换父类。
显然,构造方法只能返回确切的自身类型,而静态工厂方法则能够更加灵活,可以根据需要方便地返回任何它的子类型的实例。举例如下:
Class Vehicle {
public static Vehicle getInstance(){
return new Vehicle ();
// 也可以 return new Car () / Train ()
}
}
Class Car extends Vehicle {
}
Class Train extends Vehicle {
}
静态工厂方法相较于构造器的第四大优势在于创建参数化类型实例的时候代码更加简洁
调用参数化类型的构造器方式如下:
Map> m = new HashMap>();
以上方式需要指明每个具体的参数,当参数越来越多,我们需要查看说明才能准确的构造想要的对象。
采用静态工厂方法方式如下:
public static HashMap newInstance() {
return new HashMap();
}
Map> m = HashMap.newInstance();
可见代码变得简洁很多,这是由于静态工厂方法情况下,编译器会通过类型推导找到类型参数。
静态工厂的主要缺点在于类必须含有公有或者受保护的构造器,负责无法被子类化
静态工厂方法目前提供的帮助文档很少
在API文档中,构造器具有明确的标识,但是静态工厂类却没有,因此需要查询如何通过静态工厂方法实例化一个类,是很困难的。目前只能通过规范的命名方式区分。希望Javadoc工具可以解决这个问题
静态工厂方式相对于构造器在大多情况下是第一选择,但是也存在缺点,因此我们需要理解什么情况下使用静态工厂方式更适合。
欢迎各位来盘: