建议
Consider static factory methods instead of constructors
创建对象时尽量考虑静态工厂方法
优点
静态工厂方法可以通过方法名字来表示创建了什么对象
比如
java.math.BigInteger#probablePrime
创建对象时不需要每次都创建一个新的
例如java源码:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
每次创建对象都可以缓存起来返回,避免创建大量重复对象。这个在Integer对象使用==比较要注意。在使用锁对象的时候,也要注意。
静态工厂方法可以返回该类的子类
例如java9中:
java.util.List#of(E, E, E, E, E, E)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
e6);
}
ImmutableCollections.listFromTrustedArray的实现:
static <E> List<E> listFromTrustedArray(Object... input) {
assert input.getClass() == Object[].class;
for (Object o : input) { // implicit null check of 'input' array
Objects.requireNonNull(o);
}
return switch (input.length) {
case 0 -> (List<E>) ImmutableCollections.EMPTY_LIST;
case 1 -> (List<E>) new List12<>(input[0]);
case 2 -> (List<E>) new List12<>(input[0], input[1]);
default -> (List<E>) new ListN<>(input, false);
};
}
静态工厂方法可以根据参数来调整返回的子类
上面的代码也说明了这一点。
还有一例:
java.util.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);
}
根据条件,可以返回子类RegularEnumSethu或JumboEnumSet。
静态工厂方法创建的对象可以暂时不存在。
例如:
java.sql.DriverManager#getConnection(java.lang.String, java.util.Properties, java.lang.Class<?>)
的实现中会用到SPI机制,动态加载类以实例化所需。
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
缺点
没有public的构造函数那么这个类就没办法被继承
在documentation里不好找,毕竟取一个奇怪的名字也没人知道是创建方法的。
但是,我们可以通过科学的命名来避免这个问题,书中给了很多例子,就不一一解释了。
总结
当然,构造函数并不是让我们不用,而是有选择的使用,一般场景下,优选考虑使用静态工厂方法ch创建对象。