静态方法与构造器不同的第一大优势在于,它们有名称
对于类的构造器来说他们的名字一定是一样的
下面的例子中 无论是戴眼镜的人还是不戴眼镜的人,他们都是通过NEW的时候传进来的参数.但是这样很不明确,构造器并没有完美的表达这个意思,可读性很差.
public class person {
private String name;
private int sex;
private boolean glasses;
// 普通的人
public person(String name, int sex) {
this.name = name;
this.sex = sex;
}
// 带眼镜的人
public person(String name, int sex, boolean glasses) {
this.name = name;
this.sex = sex;
this.glasses = glasses;
}
}
我们来看看作者举的一个正面的例子
// BigInteger构造方法 这个方法可能会返回素数 语义表达不明确
public BigInteger(int bitLength, int certainty, Random rnd) {
BigInteger prime;
if (bitLength < 2)
throw new ArithmeticException("bitLength < 2");
prime = (bitLength < SMALL_PRIME_THRESHOLD
? smallPrime(bitLength, certainty, rnd)
: largePrime(bitLength, certainty, rnd));
signum = 1;
mag = prime.mag;
}
//所以在最后BigInteger 提供了一个静态方法 这个方法名清晰的告诉了我们可能是返回素数的
public static BigInteger probablePrime(int bitLength, Random rnd) {
if (bitLength < 2)
throw new ArithmeticException("bitLength < 2");
return (bitLength < SMALL_PRIME_THRESHOLD ?
smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
}
静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新的对象
我们知道既然你调用了构造方法那肯定是会新建一个对象的,但是用静态工厂方法就不一定了,我们可以先将对象缓存起来
这个例子是Boolean类的
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
// 直接返回了保存好的对象
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
静态工厂方法与构造器不同的第三大优势在于,他们可以返回原返回类型的任何子类型的对象
RegularEnumSet 和 JumboEnumSet 全部都是继承自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");
// 返回一个EnumSet子类
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
本段落还有一个例子, 现在我并没有看懂,也并没有懂适配器模式,所有以后再来补充
静态工厂第四大优在于,在创建参数化类型实例的时候,它们使代码变得更加简洁
这一点现在已经不存在了,但还是举个例子
// java1.7以前 即使泛型已经规定好了数据类型,但是你还是要写出来
List<String> list = new ArrayList<String>();
// java1.7以后
List<String> list = new ArrayList<>();
// Guava Lists静态工厂方法
public static <E> ArrayList<E> newArrayList(E... elements) {
checkNotNull(elements);
int capacity = computeArrayListCapacity(elements.length);
ArrayList<E> list = new ArrayList<>(capacity);
Collections.addAll(list, elements);
return list;
}
//调用 通过静态方法工厂就不需要写出来了
List<String> list = Lists.newArrayList("1");
静态工厂方法的主要缺点在于,类如果不含公有的或者受保护的构造器,就不能被子类化
如果构造器为私有的,通过静态方法来获得对象,那么该类是没有办法子类化的,也就是说无法继承.
静态工厂方法的第二个缺点在于,它们与其他的静态方法实际上没有任何区 别
本质上还是一个静态方法,但是实质上它用于创建对象,和普通静态方法差别很大,却没有有效的办法可以区分他们
作者的建议: 在类或接口注释中关注静态工厂,给静态工厂方法命名时遵守惯用的命名规范.
总结
简而言之,静态工厂方法和公有构造器都各有用处,我们需要理解它们各自的长处,静态工厂通常更加合适,因此切忌第一反应就是提供公有的构造器,而不先考虑静态工厂