一.不同类型的静态
静态,即static,可以用来修饰类、变量、方法等,下面简单进行介绍。
1.1静态方法代表方法为类所有,而不是为对象所有。静态方法内只能直接访问静态成员,需要构造实例对象才能访问非静态成员。在静态方法中不能直接调用实例成员或者使用this关键字,因为此时对象有可能未被创建。
1.2静态变量只能是成员变量,不能是局部变量。静态变量一样是属于类的,无论有多少个实例对象,都共享一个静态变量。
1.3静态类只能包含静态方法或静态变量,不能被实例化,同时也不能被继承,考虑到其本质是一个抽象的密封类。
注意静态类只能是内部类,如下图。
会出现如下错误
作为内部类则不会
1.4合理运用静态修饰词,建议在以下情况使用static进行修饰:
1)一个类中只有静态成员时可以将类定义为静态类
2) 变量在不同对象间共享时可以定义为静态变量
3) 节省反复调用同一方法开销时,可以将其定义为静态方法
二.被广泛认识的静态工厂方法优势与缺点
静态工厂方法也是一种静态方法,《Effective Java》一书中提出了现在被广泛认识的静态工厂方法的几种优缺点。
1. 各有名称。
具有适当名称的静态工厂会更容易使用和阅读,通过名称突出参数和返回值的特点和不同。如对于具有多个重载的构造函数,参数的位置和类型、意义难以理解,像老版的Date,可以有Date date1 = new Date("0");Date date2 = new Date(1,3,1);等不同构造方式,难以区分辨析。静态工厂方法可以通过有意义的函数名方便代码编写,解决这个问题。
2. 可以不必每次调用时都创建新的对象
可以使用预先创建好的实例,如Boolean.valueOf 就使用了这个优势
3. 可以返回子类型的对象
根据Liskov替换原则,子类能无条件的替换父类。静态工厂方法返回子类型的实例仍然有效,相比于构造方法只能返回自身类型,更为灵活
至于静态工厂方法的缺点,书中主要有两点:
1.类如果没有public或者protected的构造方法,就不能被继承。但是注意一般的类是有默认的构造方法的,不写也可以被继承;当我们设置一个private的构造方法时,就会发现子类报错。
2.静态工厂方法归根到底也只是普通的静态方法,编译器不会特别提示、标记为构造器,如果不加以说明,他人可能发现不了静态工厂方法。
三.实践中认识到的静态工厂方法优势
在这几次的实验实践中,我也发现了静态工厂方法的一些其他优点。
1.当我们想得到参数类型、数目相同但实际作用不同的构造方法时,会发现构造函数冲突,但是创建两种参数类型数目相同的静态工厂方法就不会冲突。
2.可以规范构造时传入的参数。
当我们构造语句形如Hiter hiter = new Hiter(i),而i被要求只能是1、2、3三者之一时,我们把风险转移到了客户端,而这是不安全的。此时我们可以构造三种静态工厂方法,内部分别实现i为1,2,3这三种情况,同时将构造方法设为private,防止被客户端使用,就消除了风险。
class H {
int i;
private H(int i) {
this.i = i;
}
public static Player new1() {
return new H(1);
}
public static Player new2() {
return new H(2);
}
public static Player new3() {
return new H(3);
}
}
3.设置默认对象。
当我们需要频繁的使用一个默认对象时,如果每次都需要new一个新对象、再调用set方法依次设置属性, 无疑太麻烦了。如果有一个提前设置好的静态工厂方法,在其内部把属性都设置好,每次通过类名调用它得到默认对象,就方便多了。
四.总结
根据对静态类、静态方法这些具体例子的分析,我认为静态的本质是“与实例对象分离”,像静态类不能被实例化、静态方法和静态变量都是属于类的,而不是属于实例对象的;正是这种分离本质决定了它的特性,像是静态方法被调用时、对象可能还未创建,所以不能使用this。同时也正是这种分离性,给予了静态工厂方法相对的灵活性和优势。