在Java中,創建對象常用的方法是通過公有構造方法創建;
舉個例子:如下,是Boolean類的一個構造方法,以及通過該構造方法創建一個Boolean對象;
public Boolean(String s) {
this(toBoolean(s));
}
Boolean bTrue = new Boolean("true");
其實,創建對象還有另外一種方法,通過公有靜態工廠方法來創建對象,不過這種方法往往容易被程序員忽略;
舉個例子,如下是Boolean類的valueOf方法,以及通過該靜態工廠方法返回的Boolean實例,注意,這裡並沒有創建Boolean實例對象,而是返回事先創建好的Boolean對象;
public static Boolean valueOf(String s) {
return toBoolean(s) ? TRUE : FALSE;
}
Boolean bTrue = Boolean.valueOf("true");
注意,這裡的靜態工廠方法與設計模式裡的工廠方法模式不是一個概念:
不過,如果要說相似的話,靜態工廠方法跟簡單工廠模式倒有那麼點像,不過區別也挺大,簡單工廠模式裡的靜態工廠方法會創建各種不同的對象(不同類的實例),而靜態工廠方法一般只創建屬於該類的一個實例(包括子類);
假設我們需要寫一個產生隨即數的類RandomIntGenerator,該類有兩個成員屬性:最小值min和最大值max,
假設我們的需求是需要創建三種類型的RandomIntGenerator對象,
1、大於min,小於max;
2、大於min 小於Integer.MAX_VALUE;
3、大於Integer.MIN_VALUE 小於max
如果我們不使用靜態工廠方法,代碼一般如下設計:
class RandomIntGenerator
{
/**
* 最小值
*/
private int min = Integer.MIN_VALUE;
/**
* 最大值
*/
private int max = Integer.MAX_VALUE;
/**
* 大於min 小於max
* @param min
* @param max
*/
public RandomIntGenerator(int min, int max)
{
this.min = min;
this.max = max;
}
/**
* 大於min 小於Integer.MAX_VALUE
*/
public RandomIntGenerator(int min)
{
this.min = min;
}
// 報錯:Duplicate method RandomIntGenerator(int) in type RandomIntGenerator
// /**
// * 大於Integer.MIN_VALUE 小於max
// */
// public RandomIntGenerator(int max)
// {
// this.max = max;
// }
}
觀察以上代碼,我們發現,以上代碼不僅可讀性差(new RandomIntGenerator(1, 10)與new RandomIntGenerator(10),不查文檔,不看注釋很難知道其創建的對象的具體含義),而且在設計最後一個構造方法的時候,還報錯,因為已經存在一個參數一致的工作方法了,提示重復定義;
那麼假設我們使用靜態工廠方法會怎樣呢,如下所示:
class RandomIntGenerator
{
/**
* 最小值
*/
private int min = Integer.MIN_VALUE;
/**
* 最大值
*/
private int max = Integer.MAX_VALUE;
/**
* 大於min 小於max
* @param min
* @param max
*/
public RandomIntGenerator(int min, int max)
{
this.min = min;
this.max = max;
}
/**
* 大於min 小於max
* @param min
* @param max
*/
public static RandomIntGenerator between(int min, int max)
{
return new RandomIntGenerator(min, max);
}
/**
* 大於min 小於Integer.MAX_VALUE
*/
public static RandomIntGenerator biggerThan(int min)
{
return new RandomIntGenerator(min, Integer.MAX_VALUE);
}
/**
* 大於Integer.MIN_VALUE 小於max
*/
public static RandomIntGenerator smallerThan(int max)
{
return new RandomIntGenerator(Integer.MIN_VALUE, max);
}
}
成功滿足需求:創建三種類型的RandomIntGenerator對象,而且創建對象的時候,代碼可讀性比使用構造方法強;
JDK中的Boolean類的valueOf方法可以很好的印證這個優勢,在Boolean類中,有兩個事先創建好的Boolean對象(True,False)
public final class Boolean implements java.io.Serializable,
Comparable<Boolean>
{
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true);
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
當我們調用Boolean.valueOf("true")方法時,返回的就是這兩個實例的引用,這樣可以避免創建不必要的對象,如果使用構造器的話,就達不到這種效果了;
public static Boolean valueOf(String s) {
return toBoolean(s) ? TRUE : FALSE;
}
//RedDog和BlackDog為Dog的子類
public static Dog getInstance(){
return new RedDog();//或者return new BlackDog();
}
package tmp;
class MyMap<K,V> {
/**
*
*/
public MyMap()
{
}
public static <K,V> MyMap<K,V> newInstance(){
return new MyMap<K, V>();
}
}
public class Main
{
public static void main(String[] args)
{
MyMap<String, String> map1 = new MyMap<String, String>();
//更加簡潔,不需要重復指明類型參數,可以自行推導出來
MyMap<String, String> map2 = MyMap.newInstance();
}
}
如下類,不能被其它類繼承;
class MyMap<K,V> {
/**
*
*/
private MyMap()
{
}
public static <K,V> MyMap<K,V> newInstance(){
return new MyMap<K, V>();
}
}
所以,一般一個靜態工廠方法需要有詳細的注釋,遵守標准的命名,如使用getInstance、valueOf、newInstance等方法名;
參考自effective java第一條