这是 Effective Java 的第一节的标题。本文更多的是摘译该节的内容。
什么是静态工厂方法(static factory methods)
static factory methods 翻译过来就是静态工厂方法。它并不是 GOF 提的设计模式中的一个设计模式。
我们看下面的例子(摘自JDK 1.7)。
publicfinalclassBooleanimplements java.io.Serializable, Comparable<Boolean>{ publicstaticfinalBoolean TRUE =newBoolean(true); publicstaticfinalBoolean FALSE =newBoolean(false); publicstaticBoolean valueOf(boolean b){ return(b ? TRUE : FALSE); } }
我们要获取一个 Boolean 的一个对象,可以使用构造函数 new Boolean(true)
也可以使用里面的静态方法Boolean.valueOf(true)
,后者便是静态工厂方法。
静态工厂方法的优点
和直接使用构造函数相比,静态工厂方法的优点有:
-
静态工厂方法在方法命名上更具有可读性在使用构造函数去构造对象的时候,我们传递不同的参数构造不同类型的对象。如果不看文档的话,我们很难记住传递什么参数能够构造什么样子的对象。用静态的工厂方法就不一样啦,我们可以不同的工厂方法不同名字,我们就可以很容易的记住什么方法名可以构造什么样的对象。关于这一点,在 JDK 中最有说服力的一个例子就是
java.util.concurrent.Executors
,里面N多的静态工厂方法:newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool、newScheduledThreadPool等等 -
静态工厂方法不需要每次在被调用的时候都构造一个新的对象也就是说我们调用静态工厂方法返回的可能是缓存的一个对象,而不是一个新的对象。这可以减少创建新的对象,从来提高性能,前面提到的 Boolean 就是一个例子。这对于 immutable 的对象特别有用,读到这里,我翻看了一下 JDK 的源代码,才发现原来 JDK 中原始数据类型(Primitive Data Types)的包装类都是 immutable 的。也就是说只要创建 Boolean、Integer、Long 等的对象,它的值就是不能改变的。我们再看 Integer 提供的静态工厂函数:
publicstaticInteger valueOf(int i){ assertIntegerCache.high >=127; if(i >=IntegerCache.low && i <=IntegerCache.high) returnIntegerCache.cache[i +(-IntegerCache.low)]; returnnewInteger(i); }
上面的代码把出现概率高的 int 做了一个 cache,这样每次只要返回 cache 里的对象,而不用新建一个对象。
-
静态工厂方法还可以返回该类型的子类对象这个特性让静态工厂方法的可扩展性大大的优于构造函数。在 JDK 中最典型的应该是 java.util.EnumSet。EnumSet 本身是 absract,我们无法直接调用它的构造函数。不过我们可以调用它的静态方法 noneOf 来创建对象,RegularEnumSet/JumboEnumSet 都继承至 EnumSet,noneOf 根据参数返回合适的对象。
publicabstractclassEnumSet<E extendsEnum<E>>extendsAbstractSet<E> implementsCloneable, java.io.Serializable{ EnumSet(Class<E>elementType,Enum[] universe){ } publicstatic<E extendsEnum<E>>EnumSet<E> noneOf(Class<E> elementType){ if(universe.length <=64) returnnewRegularEnumSet<>(elementType, universe); else returnnewJumboEnumSet<>(elementType, universe); } }
-
静态工厂方法还可以简化参数化类型的对象创建这个优点优点语法糖的味道,不过语法糖人人都喜欢啦。
Map<String,List<String>> m = newHashMap<String,List<String>>(); publicstatic<K, V>HashMap<K, V> newInstance(){ returnnewHashMap<K, V>(); } Map<String,List<String>> m =HashMap.newInstance();
第一行冗长的代码我们就可以简化成第三行的代码。比较典型的例子就是 guava 中的 Maps (Google collections library)
静态工厂方法的缺点
静态工厂方法当然也有其缺点。
- 如果我们在一个类中将构造函数设为private,只提供静态工厂方法来创建对象,那么我们就不能通过继承的方式来扩展该类。不过还好的是,在需要进行扩展的时候,我们现在一般提倡用组合而不是继承。
- 第二个缺点是,静态构造方法不能和其他的静态方法很方便的区分开来。好吧,原文的意思是静态构造方法做的是一等公民(构造函数)的事,却得不到一等公民的待遇。
为了和普通函数有所区分,原文建议在命名静态工厂方法的时候遵循一定的规则
- valueOf — 返回和参数一样的对象,通常都用作类型转换,比如 Intger.valueOf(int i)
- of — 和 valueOf 类似。
- getInstance — 根据参数返回对应的对象,该对象可能是缓存在对象池中的对象。对于单例 singleton,我们使用无参数的 getInstance,并且总是返回同一个对象
- newInstance — 和 getInstance 一样,不过这个方法的调用每次返回的都是新的对象。
- getType — 和 getInstance 类似,不过区别是这个方法返回的对象是另外一个不同的类。
- newType — 和 getType 类似,不过每次返回的都是一个新的对象。
相关推荐
文档的内容部分开始讲述了Java编程中的一个关键知识点:使用静态工厂方法替代构造方法。以下是该知识点的详细解释: 1. 静态工厂方法与构造方法的区别:在Java中,构造方法用于创建类的实例,它与类同名并可拥有...
Effective Java是一本关于Java编程语言的经典书籍,本笔记主要总结了Java语言的发展历程、静态工厂方法的应用、构造器模式的使用等重要知识点。 一、Java语言的发展历程 Java语言的发展可追溯到1991年,当时由...
1. **静态工厂方法**:相比构造器,静态工厂方法有优点如可以不返回新实例、允许返回同一实例(单例)、可以有更具选择性的访问控制,并且命名更自由。 2. **构建器(Builder pattern)**:当类有多个构造器参数时,...
本学习记录主要介绍了 Effective Java 3 中的静态工厂方法和 Builder 模式两部分内容。 一、静态工厂方法 静态工厂方法是指返回类实例的命名规则,例如:from、of、valueOf、instance 或 getinstance、create 或 ...
Builder 模式是一种构建对象的方法,不直接生成想要的对象,而是利用必要参数调用构造器(或者静态工厂)得到一个 builder 对象,然后在 builder 对象上调用类似 setter 的方法,设置可选参数,最后调用无参的 build...
- Item1:静态工厂方法相比构造子,提供了更大的灵活性,例如可以返回对象的子类实例,或者在不改变API的情况下更改返回的对象类型。 - Item2:Builder模式适用于有大量构建参数的情况,它可以避免构造器的链式...
《EffectiveJava》是Java开发领域的经典著作,由Joshua Bloch撰写,提供了许多关于如何编写高效、可维护和设计良好的Java代码的实用建议。这本书的第2版在原有的基础上进行了更新,以适应Java语言的新发展。现在,...
声明的返回类型的任何子类都是允许的。返回对象的类也可以随每次发布而不同。EnumSet 类(详见第 36 条)没有公共构造方法,只有静态工厂。在 OpenJDK
2. **构造器**:推荐使用私有构造器或静态工厂方法来限制类的实例化,以实现不可变类或者控制对象的创建。此外,还强调了构造器不应抛出检查异常。 3. **枚举**:枚举在Java中不仅仅是常量集合,还可以包含方法,...
3. **构造函数与工厂方法(Constructors and Factory Methods)**: 书中提倡使用工厂方法代替公共构造函数,以实现更好的封装和灵活性。这里可能包含不同类型的工厂模式实现。 4. **可变与不可变对象(Mutable vs ...
1. **命名清晰**:与构造器相比,静态工厂方法能够通过其名字更直观地表达出将要创建的对象的特征。例如,`BigInteger.probablePrime()` 明确地告诉用户它将返回一个大概率质数的大整数对象。 2. **支持多种构造方式...
2. **构造器与工厂方法**:提倡使用私有构造器和静态工厂方法,以便于控制类的实例化过程,提高代码灵活性,例如实现不可变对象、延迟初始化等。 3. **接口与抽象类**:讨论了接口和抽象类在设计上的差异,强调接口...
有效的Java 有效的java se 书中的例子 建造者模式 第 2 条:当面临许多构造函数参数时考虑构建器 伸缩构造函数模式有效,但是当参数很多时很难编写客户端代码,而且更难...在设计具有构造函数或静态工厂将有多个参数
3. **构造器与工厂方法**:讨论了何时应该使用构造器,何时应使用工厂方法,并强调了私有构造器和静态工厂方法的优势。 4. **重用对象,避免对象创建**:提倡使用`StringBuilder`进行字符串连接,以及使用`Arrays....
8. **静态工厂方法与构造器**:书中分析了两者的优劣,指出静态工厂方法在某些情况下比构造器更灵活,如隐藏类的创建,控制实例数量等。 9. **序列化**:针对Java的序列化机制, Bloch提出了一些注意事项,如实现...
项目中的代码可能包含了各种工厂模式的实现,如静态工厂方法和抽象工厂模式。 3. **单例模式**:《Effective Java》讲解了如何正确实现单例模式,避免线程安全问题和内存泄漏。LF_EffectiveJava可能包含不同版本的...