前言
這是第一次學習寫博客總結(jié)就珠,很多的不足的地方趣些,請客官多多指正日丹,有關(guān)java的地方,多多交流
現(xiàn)在進入正題:
一怎抛、考慮用靜態(tài)工廠方法代替構(gòu)造器
這里說的工廠方法和設(shè)計模式里面的工廠方法是有區(qū)別的卑吭,
設(shè)計模式里的工廠模式是定義一個創(chuàng)建對象的接口,讓子類選擇去實現(xiàn)哪一個類马绝,工廠模式讓一個類的初始化延遲到其子類(設(shè)計模式之禪)豆赏。
effective java中的靜態(tài)工廠只是為一個類提供一個靜態(tài)方法,它本質(zhì)是和當前類的其他靜態(tài)方法沒有區(qū)別,只是它是用來創(chuàng)建對象的河绽。和構(gòu)造器相比己单,提供的靜態(tài)方法本身具有一些優(yōu)勢,在于易閱讀耙饰,易使用纹笼,而且可以提供方法參數(shù),并且返回的對象可以協(xié)變成子類苟跪,相當?shù)木哂徐`活性廷痘。還有一個比較常見的好處是 在創(chuàng)建參數(shù)化類型實例的時候,和傳統(tǒng)的構(gòu)造器相比可以讓代碼更簡潔件已,比較實例如下:
傳統(tǒng)構(gòu)造器:?
Map<String,List<String>>? map = new HashMap<String,List<String>>();? ?
可以看到笋额,傳統(tǒng)的構(gòu)造需要在后面再寫一遍,但是篷扩,提供了靜態(tài)工廠方法后兄猩,這種情況就不再出現(xiàn)了:
靜態(tài)工廠方法:
public? static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
靜態(tài)方法構(gòu)造:
Map <String,List<String>> map = HashMap.newInstance();
直接看出來,簡便了很多鉴未。枢冤。。
靜態(tài)方法的缺陷铜秆,如果類沒有實現(xiàn)公有的或者受保護的構(gòu)造器淹真,那么不能實現(xiàn)子類化。连茧。
二核蘸、當對象的字段過多的時候,考慮使用Builder模式
我們在創(chuàng)建一個對象的時候啸驯,有幾種方式設(shè)置內(nèi)部參數(shù)
1.直接使用構(gòu)造器客扎,一般來說,都會創(chuàng)建一個構(gòu)造方法坯汤,將字段值放在構(gòu)造器里一起創(chuàng)建虐唠,但是當字段過多的時候,很容易造成字段很難區(qū)分惰聂,比如:
public Demo(String field1,String field2,int field3,int field4,int field5){}?
在實際開發(fā)中疆偿,字段的命名請規(guī)范且易理解,考慮加上doc注釋搓幌,不要像實例的一樣杆故。可以看到當字段很多的時候溉愁,類型基本相同的時候处铛,很難區(qū)分各個字段饲趋,所以很容易造成錯誤,就像把field3 field4 field5 的字段順序?qū)戝e了撤蟆,這個時候最好的結(jié)果是程序拋出運行時異常奕塑,最壞的結(jié)果程序可能還在運行中,且沒有拋出錯誤家肯,這時候的邏輯已經(jīng)出錯龄砰,而且不易發(fā)現(xiàn),很難查找讨衣,但是整個程序已經(jīng)偏離了我們的期望换棚。
2.使用JavaBeans方法,通過調(diào)用默認的無參構(gòu)造器反镇,構(gòu)造一個對象固蚤,之后通過提供的setter() 方法一個個的給字段添加值。
Demo demo = new Demo();
demo.setField1(field);
demo.setField2(field);
這樣的方法歹茶,可以很輕松的給每一個字段賦值夕玩,但是缺陷的地方在于給每個字段賦值都是分開的操作,可能造成狀態(tài)不一致惊豺。類無法僅僅通過檢驗構(gòu)造器參數(shù)的有效性來保證一致性风秤。試圖使用處于這樣不一致狀態(tài)的對象,將會導致失敗扮叨,這種失敗與包含錯誤的代碼大相徑庭,因此調(diào)試起來也十分困難领迈。另一點不足在于彻磁,JavaBeans模式防止了把類做成不可變的可能(15條有講),這就需要程序員付出格外努力來確保它的線程安全狸捅。
3.使用Builder模式構(gòu)造對象衷蜓,既可以實現(xiàn)像javaBeans的給字段一一賦值,也不會像直接使用構(gòu)造器一樣尘喝,容易造成字段混亂磁浇。比較常見的Builder模式實例? StringBuilder類,可以查看相關(guān)源碼朽褪。這里就不寫代碼了置吓。StringBuilder的缺陷在于,每一次創(chuàng)建對象的時候都需要先創(chuàng)建一個它的builder對象缔赠,然后才能創(chuàng)建對象衍锚。
三、使用私有構(gòu)造器或者枚舉來強化singleton屬性
對于單例模式嗤堰,要保證只存在只有一個對象實例戴质,一直以來都有很多實現(xiàn)方式,大多脫不出這兩種范圍
1,私有構(gòu)造器告匠,和靜態(tài)的單例對象字段
例如:
public class SingletonDemo{
public static SingletonDemo demo = new SingletonDemo();
private SingletonDemo(){}
}
這種方法實現(xiàn)的單例戈抄,保證了只存在一個實例,但是有種情況是后专,如果特權(quán)用戶用AccessibleObject.setAccess方法通過反射划鸽,可以調(diào)用當前類的私有構(gòu)造器,從而創(chuàng)建新對象行贪,對于抵御這種情況漾稀,需要添加判斷,在第二次創(chuàng)建對象的時候拋出異常就可以了建瘫。
2.靜態(tài)方法崭捍,私有的字段,私有的構(gòu)造器
public class SingletonDemo{
private static SingletonDemo demo = new SingletonDemo();
private SingletonDemo(){}
public static SingletonDemo getInstance(){ return? demo; }
}
這種方法也保證了只有一個實例啰脚,但是不管這種方法還是前面一種方法殷蛇,如果要實現(xiàn)Serializable接口,使得對象可序列化橄浓,就會出現(xiàn)問題粒梦,在反序列化的時候,readObject()方法不管顯示的還是默認的荸实,都會提供一個新的對象給我們匀们,導致反序列化單例失敗,這種情況需要提供readResolve()方法准给,當反序列化的時候泄朴,readResolve()方法調(diào)用時,返回當前對象的引用來替換新建對象的引用露氮,如
public SingletonDemo readResolve(){ return demo;}
這樣就可以防止對象重復創(chuàng)建了
3.單元素枚舉----其實這是實現(xiàn)單例的最好方法了
在java引入枚舉之后祖灰,枚舉就成了單例實現(xiàn)的最優(yōu)方式,它可以自動維護對象的個數(shù)畔规,絕對防止重復局扶。因為enmu的元素就是enmu的實例,當只有一個元素的時候叁扫,它就只存在一個實例三妈,枚舉的用處有很多,不懂得可以去看看基礎(chǔ)書(java程序設(shè)計語言 阿諾德莫绣,java編程思想)
public enmu SingletonDemo{
demo;
public void doSomething(){}
}
調(diào)用的時候沈跨,直接寫成SingletonDemo.demo.doSomething()就可以了
四,使用私有構(gòu)造器強化不可實例化的類屬性
這條其實很簡單兔综,在我們代碼中饿凛,有很多類是不需要實例化的狞玛,比如以前的配置類(現(xiàn)在不推薦這么寫,可以考慮使用枚舉來寫)涧窒,工具類等心肪,它只包含了靜態(tài)方法,靜態(tài)字段纠吴,我們不需要給它實例化硬鞍,這個時候,可以使用私有構(gòu)造器戴已,防止有人不小心實例化這個類固该。
注意:在給予私有構(gòu)造器的時候,請寫doc注釋糖儡,說明為什么這個類使用私有構(gòu)造器伐坏,因為私有之后直接創(chuàng)建對象也不能子類化了
五、避免創(chuàng)建不必要的對象
在代碼中握联,其實很多這樣的規(guī)則我們已經(jīng)在遵守了桦沉,但是這里還是寫出來,警惕自己犯錯
1.使用基本數(shù)據(jù)類型來替代包裝器類金闽,避免自動裝箱纯露,java引入自動裝箱和拆箱操作之后,基本數(shù)據(jù)類型和包裝器類之間其實很模糊了代芜,但是優(yōu)先使用基本數(shù)據(jù)類型可以有效避免創(chuàng)建多余對象埠褪。基本數(shù)據(jù)類型是直接將值存在堆棧中挤庇,來保證高效组橄,但是包裝器類對象是保存在堆中的
2.對于同時提供了靜態(tài)工廠方法和構(gòu)造器的不可變類,使用靜態(tài)工廠方法罚随,避免創(chuàng)建不必要對象--
3.重(chong)用已知的可變但不會修改的對象
4.維護對象池并不是好做法,除非真的是非常重量級的對象羽资,比較常規(guī)的是數(shù)據(jù)庫連接池和緩存連接池
六淘菩、消除過期引用
過期引用這點,其實牽扯到內(nèi)存泄漏(指的是被無意識的保存的對象屠升,導致內(nèi)存變谐备摹),所以在類自己管理內(nèi)存時腹暖,請警惕內(nèi)存泄漏的問題汇在,消除過期引用。
可以使用WeakHashMap來存儲 緩存 和監(jiān)聽器脏答,回調(diào)糕殉。這樣在內(nèi)存不夠的時候gc會優(yōu)先清理這部分亩鬼,達到釋放內(nèi)存的效果。
七阿蝶,避免使用finalizer方法
finalizer()一般來說很少用到雳锋,它的運行是不可預測的,gc并不保證你調(diào)用了這個方法之后羡洁,它就馬上運行玷过,而且調(diào)用這個方法會造成嚴重的性能損耗(java虛擬機)
結(jié)語
昨晚就花了我?guī)讉€小時的時間整理,今天中午午睡時間才打完發(fā)的筑煮,第一次寫很多地方都寫不好辛蚊,考慮不周全或者錯誤,不足的地方真仲,請多多指教袋马。來簡書是因為覺得里面的博客都很簡潔,不太喜歡csdn的博客樣子袒餐,哈哈飞蛹,可以看到后面幾條我寫的非常少,這些都是正常的注意下就好了灸眼,其實書上是有很多的內(nèi)容卧檐,推薦去看本書,認真研讀幾遍幫助很大焰宣,謝謝努力的自己和努力的你~~~