java声明公有构造器_java代码优化——静态工厂方法与公有构造器

通常,我们使用new来创建一个对象。这应该是最简单的一种方式。但一个优秀的程序员需要考虑具体的应用场景以及性能等问题,从而编写出优秀的代码。那么我们就从创建对象开始,了解如何创建对象?

本文通过静态工厂方法与公有构造器的比较,分析各自的优缺点,提供不同场景下创建对象的推荐方式。

创建对象的两种方式:

方法1: 使用类公有构造器。

方法2:使用类的静态工厂方法返回一个实例。

什么是静态工厂方法?

静态工厂方法(static factory methods)即是static修饰的返回类的实例的一种静态方法。

下面是一个静态工厂方法的简单示例(摘自JDK 1.7 java.lang.Boolean)。

public final class Boolean implements java.io.Serializable,

Comparable {

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);

}

}

如果需要获取一个Boolean对象,常规的方法是new Boolean(true),但是也可以如上图所示Boolean.valueOf(true),这便是静态工厂方法。

静态工厂方法与公有构造器的区别:

1:构造方法的名字必须与类名相同。这一特性的优点是符合Java语言的规范,缺点是类的所有重载的构造方法的名字都相同,不能从名字上区分每个 重载方法,容易引起混淆。静态工厂方法的方法名可以是任意的,这一特性的优点是可以提高程序代码的可读性,在方法名中能体现与实例有关的信息。不同的工厂方法有不同名字,我们就可以很容易的记住什么方法名可以构造什么样的对象。关于这一点,在 JDK 中最有说服力的一个例子就是 java.util.concurrent.Executors,里面N多的静态工厂方法:newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool、newScheduledThreadPool等等

2:每次执行new语句时,都会创建一个新的对象。而静态工厂方法每次被调用的时候,是否会创建一个新的对象完全取决于方法的实现。我们调用静态工厂方法返回的可能是缓存的一个对象,而不是一个新的对象。这可以减少创建新的对象,从来提高性能,前面提到的 Boolean 就是一个例子。这对于 不可变类的对象特别有用,因为对象的不可变性,只需要实现一个对象实例即可。包装类 Integer 便利用了这种思想,Integer中的静态工厂函数如下:

public static Integer valueOf(int i) {

assert IntegerCache.high >= 127;

if (i >= IntegerCache.low && i <= IntegerCache.high)

return IntegerCache.cache[i + (-IntegerCache.low)];

return new Integer(i);

}

上面的代码把出现概率高的 int 做了一个 cache,这样每次只要返回 cache 里的对象,而不用新建一个对象。

单例模式便是一种利用了静态工厂方法来获得对象实例的一种方式。确保该类只有一个对象实例。

3:new语句只能创建当前类的实例,而静态工厂方法可以返回当前类的子类的实例。这个特性让静态工厂方法的可扩展性大大的优于构造函数。在 JDK 中最典型的应该是 java.util.EnumSet。EnumSet 本身是 absract,我们无法直接调用它的构造函数。不过我们可以调用它的静态方法 noneOf 来创建对象,RegularEnumSet/JumboEnumSet 都继承至 EnumSet,noneOf 根据参数返回合适的对象。

public abstract class EnumSet> extends AbstractSet

implements Cloneable, java.io.Serializable {

EnumSet(ClasselementType, Enum[] universe) {

}

public static > EnumSet noneOf(Class elementType) {

if (universe.length <= 64)

return new RegularEnumSet<>(elementType, universe);

else

return new JumboEnumSet<>(elementType, universe);

}

}

静态工厂方法的缺点:

1. 如果一个类只能通过静态工厂方法来获得实例,那么该类的构造函数就不能是共有的或受保护的,那么该类就不会有子类,即该类不能被继承。单例模式中首先要私有化构造器。

2.静态工厂方法和其他静态方法从名字上看无法区分,建议在命名静态工厂方法的时候遵循一定的规则。

valueOf — 返回和参数一样的对象,通常都用作类型转换,比如 Intger.valueOf(int i)

of — 和 valueOf 类似。

getInstance — 根据参数返回对应的对象,该对象可能是缓存在对象池中的对象。对于单例 singleton,我们使用无参数的 getInstance,并且总是返回同一个对象

newInstance — 和 getInstance 一样,不过这个方法的调用每次返回的都是新的对象。

getType — 和 getInstance 类似,不过区别是这个方法返回的对象是另外一个不同的类。

newType — 和 getType 类似,不过每次返回的都是一个新的对象。

静态工厂方法最主要的特点是:每次被调用的时候,不一定要创建一个新的对象。利用这一特点,静态工厂方法可用来创建以下类的实例。

<1>单例类:只有惟一的实例。实例一旦创建,其属性值就不会被改变。

<2>枚举类:实例的数量有限的类。

<3>具有实例缓存的类:能把已经创建的实例暂且存放在缓存中的类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值