在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第一條