对于Effective Java第三版,每一个知识的翻译后都会选出比较难理解的部分进行验证,在翻译考虑静态工厂方法替代构造器一文中对于静态工厂的三个优点进行了描述,对于第一个和第二个优点就不再多说,那么关于第三个优点:“静态工厂方法的第三个优点是,与构造方法不同,它们可以返回其返回类型的任何子类型的对象”是怎么一回事呢。
与构造方法不同,它们可以返回其返回类型的任何子类型的对象的意思就是静态工厂方法可以返回该类的子类型,而构造器不能返回子类实例。
关于构造器只能返回该类的实例这一点我想大家都能理解,说到这里我想到向上转型这个知识点:子类重写父类方法,子类对象向上转型后调用该方法会执行谁的呢?
来看一下:
public class FactoryInsteadConstruction{
public void soutVal() {
System.out.println("父类");
}
}
class SubFactoryClass extends FactoryInsteadConstruction {
public void soutVal() {
System.out.println("子类");
}
}
class TestMain {
public static void main(String[] args) {
FactoryInsteadConstruction factoryInsteadConstruction =
new FactoryInsteadConstruction();
factoryInsteadConstruction.soutVal();
FactoryInsteadConstruction factoryInsteadConstruction1 =
new SubFactoryClass();
factoryInsteadConstruction1.soutVal();
}
}
输出是什么?
Connected to the target VM, address: '127.0.0.1:50432', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:50432', transport: 'socket'
父类
子类
Process finished with exit code 0
这个说明了什么呢?实例化父类,不会返回子类对象,但是子类可以向上转型为父类对象,但是调用的方法是子类方法。这验证了构造方法不能返回子类实例
那么静态工厂方法是怎么返回子类的实例呢?
public class FactoryInsteadConstruction {
public void soutVal() {
System.out.println("父类");
}
public static FactoryInsteadConstruction getSubInstance(){
return new SubFactoryClass();
}
}
class SubFactoryClass extends FactoryInsteadConstruction {
public void soutVal() {
System.out.println("子类");
}
}
class TestMain {
public static void main(String[] args) {
FactoryInsteadConstruction factoryInsteadConstruction =
new FactoryInsteadConstruction();
factoryInsteadConstruction.soutVal();
FactoryInsteadConstruction factoryInsteadConstruction1 =
new SubFactoryClass();
factoryInsteadConstruction1.soutVal();
FactoryInsteadConstruction factoryInsteadConstruction2 =
FactoryInsteadConstruction.getSubInstance();
factoryInsteadConstruction2.soutVal();
}
}
输出结果:
Connected to the target VM, address: '127.0.0.1:50574', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:50574', transport: 'socket'
父类
子类
子类
Process finished with exit code 0
通常父类有多个子类的时候,我们会通过new不同的子类,然后向上转型,调用重写的方法,这就要求我们每次都要写new 子类,但是通过静态工厂方法,我们可以通过传参数的形式去返回相应的子类,如下:
public class FactoryInsteadConstruction {
private static FactoryInsteadConstruction factoryInsteadConstruction;
public void soutVal() {
System.out.println("父类");
}
public static FactoryInsteadConstruction getSubInstance(int i) {
if (i == 0) {
if (factoryInsteadConstruction instanceof SubFactoryClass) {
System.out.println("SubFactoryClass已存在");
} else {
factoryInsteadConstruction = new SubFactoryClass();
}
return factoryInsteadConstruction;
}
if (i == 1) {
if (factoryInsteadConstruction instanceof SubFactoryClass2) {
System.out.println("SubFactoryClass2已存在");
} else {
factoryInsteadConstruction = new SubFactoryClass2();
}
return factoryInsteadConstruction;
} else {
if (factoryInsteadConstruction == null){
factoryInsteadConstruction = new FactoryInsteadConstruction();
}
System.out.println("factoryInsteadConstruction已存在");
return factoryInsteadConstruction;
}
}
}
class SubFactoryClass extends FactoryInsteadConstruction {
public void soutVal() {
System.out.println("子类");
}
}
class SubFactoryClass2 extends FactoryInsteadConstruction {
public void soutVal() {
System.out.println("子类2");
}
}
class TestMain {
public static void main(String[] args) {
for (int i=0;i<2;i++){
FactoryInsteadConstruction factoryInsteadConstruction =
new FactoryInsteadConstruction();
FactoryInsteadConstruction factoryInsteadConstruction1 =
new SubFactoryClass();
FactoryInsteadConstruction factoryInsteadConstruction2 =
FactoryInsteadConstruction.getSubInstance(1);
factoryInsteadConstruction.soutVal();
factoryInsteadConstruction1.soutVal();
factoryInsteadConstruction2.soutVal();
}
}
}
输出结果:
Connected to the target VM, address: '127.0.0.1:50661', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:50661', transport: 'socket'
父类
子类
子类2
SubFactoryClass2已存在
父类
子类
子类2
Process finished with exit code 0
当然类,我们也可以通过其他的形式得到类似的效果:写一个方法传入子类实例,然后调用就可以实现。
class TestMain {
public static void main(String[] args) {
for (int i=0;i<2;i++){
FactoryInsteadConstruction factoryInsteadConstruction =
new FactoryInsteadConstruction();
FactoryInsteadConstruction factoryInsteadConstruction1 =
new SubFactoryClass();
FactoryInsteadConstruction factoryInsteadConstruction2 =
FactoryInsteadConstruction.getSubInstance(1);
factoryInsteadConstruction.soutVal();
factoryInsteadConstruction1.soutVal();
factoryInsteadConstruction2.soutVal();
}
soutData(new SubFactoryClass2());
}
public static void soutData(FactoryInsteadConstruction factoryInsteadConstruction){
factoryInsteadConstruction.soutVal();
}
}
似乎扯到这里已经验证了:通过静态工厂方法返回子类实例。也说明了第四个优点:返回对象的类可以根据输入参数的不同而不同
但是在Effective Java第三版中,强调了JDK8(这也是我为什么买这本书的原因,他对于JDK8和JDK9有了一些说明,虽然我们在网上也能搜得到,但是这本书既然大家都说有意义,那就买回家吧)。
书中说到JDK8中接口不能包含静态工厂方法的限制移除了。我们都知道接口中只能声明方法,那么这句话就告诉我们接口中能够有方法了。看一下效果
可以看到确实不报错了。但是JDK8中静态工厂方法不能私有化,在JDK9中可以私有化,但是静态字段和静态成员类仍要公开。由于本人目前使用JDK8对于9暂时就不演示了。
-
更多文章请关注公众号:每天学Java。想获得更多最新面试提醒请进入小程序:每天学Java
公众号二维码: 小程序二维码: