获取一个实例的方法有两种:
1.就是提供一个公有的构造器。
2.提供一个公有的静态工厂方法,它只是一个返回类的实例的静态方法。
注意:静态工厂方法与设计模式中的工厂方法模式不同。
静态工厂方法对于构造器具有以下一些优势。
1.静态工厂方法有名称。
构造器没有名称,不利于描述返回结果,只能通过其参数去猜测返回的实例所具有的属性。而如果用静态工厂方法就可以通过方法名来突出它们之间的区别。
public class Number1 {
private int number;
/**
* Number1构造方法
* number属性为1
*/
public Number1 () {
this.number=1;
}
/**
* Number1构造方法
* balance==true,number属性设置为2
*/
public Number1 (boolean balance) {
if (balance) this.number=2;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public class Number2 {
private int number;
public static Number2 getOne(){
Number2 number=new Number2();
number.setNumber(1);
return number;
}
public static Number2 getTwo(){
Number2 number=new Number2();
number.setNumber(2);
return number;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public class NumberTest extends TestCase {
public void test(){
Number1 number1=new Number1();
System.out.println(number1.getNumber());
number1=new Number1(true);
System.out.println(number1.getNumber());
Number2 number2=Number2.getOne();
System.out.println(number2.getNumber());
number2=Number2.getTwo();
System.out.println(number2.getNumber());
}
}
在单元测试代码中Number2通过静态工厂方法获取到的返回对象的代码,比Number1通过构造方法获取到的返回对象更容易阅读。
2.静态工厂方法不必在每次调用它们的时候都创建一个新对象。
静态工厂方法使得不可变类可以预先构建好的实例,或者将构建好的实例缓存起来,进行重复使用。如果程序经常请求创建相同的对象,并且创建对象的代价很高,这项技术可以极大地提升性能。
静态工厂方法能够为重复的调用返回相同对象,这样有助于类总能严格控制在某个时刻哪些实例应该存在(实例受控的类instance-controlled)。
public final class Boolean{
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
}
3.静态工厂方法可以返回原返回类型的任何子类型的对象。
静态工厂方法可以让我们在返回对象的类时,有更大的灵活性。这种方式使得API可以返回非公的有类对象。
如EnumSet类就采用了这种方式,当<=64的时候返RegularEnumSet其他的情况就返回JumboEnumSet
public class EnumSet{
public static <E extends Enum<e>> EnumSet<e> noneOf(Class<e> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
}
在Java Collections Framework的集合接口有32个便利实现,分别提供了不可修改的集合,同步集合等等。几乎所有这些实现都通过静态工厂方法在一个不可实例化的类(java.util.Collections)中导出。所有返回对象的类都是非公有的。
public class Collections{
public static <e> Set<e> checkedSet(Set<e> s, Class<e> type) {
return new CheckedSet<>(s, type);
}
/**
* @serial include
*/
static class CheckedSet<e> extends CheckedCollection<e> implements Set<e>, Serializable{
private static final long serialVersionUID = 4694047833775013803L;
CheckedSet(Set<e> s, Class<e> elementType) { super(s, elementType); }
public boolean equals(Object o) { return o == this || c.equals(o); }
public int hashCode() { return c.hashCode(); }
}
}
4.静态工厂方法在创建参数化类型实例的时候,它们使代码变得更加简洁。
缺点
1.类如果不含公有的或者受保护的构造器,就不能被子类化。
例如,想要将Collections中的任何方便的实现类子类化,这是不可能的。但是这样也许会因祸得福,因为它鼓励程序员使用复合(composition),而不是继承。
2.它们与其他的静态方法实际上没有任何区别。
目前它们不会像构造器那样在API文档中明确标识出来,对于那些提供了静态工厂方法而不是构造器的类来说,想要查明如何实例化一个类,是非常困难的。
你可以通过在类或者接口注释中关注静态工厂,并准守标准的命名习惯。下面是静态工厂方法的一些习惯名称。
valueOf:不太严格的说,该方法返回的实例与它的参数具有相同的值。这样的静态工厂方法实际上是类型转换方法。
of:valueOf的一种更为简洁的替代,在EnumSet中使用并流行起来。
getInstance:返回的实例是通过方法的参数来描述的,但是不能够说与参数具有同样的值。对于Singleton来说,该方法没有参数,并返回唯一的实例。
newInstance:像getInstance一样,但newInstance能够确保返回的每个实例都与所有其他实例不同。
getType:像getInstance一样,但是在工厂方法处于不同的类中的时候使用,Type表示工厂方法所返回的对象类型。
newType:像newInstance一样,但是在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。