1. 盡量在合適的場合使用單例
成都創(chuàng)新互聯(lián)長期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為劍閣企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計、網(wǎng)站建設(shè),劍閣網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
使用單例可以減輕加載的負(fù)擔(dān),縮短加載的時間,提高加載的效率,但并不是所有地方都適用于單例,簡單來說,單例主要適用于以下三個方面:
第一,控制資源的使用,通過線程同步來控制資源的并發(fā)訪問;
第二,控制實(shí)例的產(chǎn)生,以達(dá)到節(jié)約資源的目的;
第三,控制數(shù)據(jù)共享,在不建立直接關(guān)聯(lián)的條件下,讓多個不相關(guān)的進(jìn)程或線程之間實(shí)現(xiàn)通信。
2. 盡量避免隨意使用靜態(tài)變量
要知道,當(dāng)某個對象被定義為stataic變量所引用,那么gc通常是不會回收這個對象所占有的內(nèi)存
3. 盡量避免過多過常的創(chuàng)建Java對象
盡量避免在經(jīng)常調(diào)用的方法,循環(huán)中new對象,由于系統(tǒng)不僅要花費(fèi)時間來創(chuàng)建對象,而且還要花時間對這些對象進(jìn)行垃圾回收和處理,在我們可以控制的范圍內(nèi),最大限度的重用對象,最好能用基本的數(shù)據(jù)類型或數(shù)組來替代對象。
4. 盡量使用final修飾符
帶有final修飾符的類是不可派生的。在Java核心API中,有許多應(yīng)用final的例子,例如java.lang.String.為String類指定final防止了使用者覆蓋length()方法。另外,如果一個類是final的,則該類所有方法都是final的。Java編譯器會尋找機(jī)會內(nèi)聯(lián)(inline)所有的final方法(這和具體的編譯器實(shí)現(xiàn)有關(guān))。此舉能夠使性能平均提高50%.
5. 盡量使用局部變量
調(diào)用方法時傳遞的參數(shù)以及在調(diào)用中創(chuàng)建的臨時變量都保存在棧(Stack)中,速度較快。其他變量,如靜態(tài)變量、實(shí)例變量等,都在堆(Heap)中創(chuàng)建,速度較慢。
6. 盡量處理好包裝類型和基本類型兩者的使用場所
雖然包裝類型和基本類型在使用過程中是可以相互轉(zhuǎn)換,但它們兩者所產(chǎn)生的內(nèi)存區(qū)域是完全不同的,基本類型數(shù)據(jù)產(chǎn)生判凳仿和處理都在棧中處理,包裝類型是對象,是在堆中產(chǎn)生實(shí)例。
在集合類對象,有對象方面需要的處理適用包裝類型,其他的處理提倡使用基本類型。
7. 慎用synchronized,盡量減小synchronize的方法
都知道,實(shí)現(xiàn)同步是要很大的系統(tǒng)開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。synchronize方法被調(diào)用時,直接會把當(dāng)前對象鎖 了,在方法執(zhí)行完之前其他線程無法調(diào)用當(dāng)前對象的其他方法。所以synchronize的方法盡量小,并且應(yīng)盡量使用方法同步代替代碼塊同步。
8. 盡量使用StringBuilder和StringBuffer進(jìn)行字符串連接
這個就不多講了。
9. 盡量不要使用finalize方法
實(shí)際上,將資源清理放在finalize方法中完成是非常掘纖不好的選擇,由于GC的工作量很大,尤其是回收Young代內(nèi)存時,大都會引起應(yīng)用程序暫停,所以再選擇使用finalize方法進(jìn)行資源清理,會導(dǎo)致GC負(fù)擔(dān)更大,程序運(yùn)行效率更差。
10. 盡量使用基本數(shù)據(jù)類型代替對象
String str = "hello";
上面這種方式會創(chuàng)建一個"hello"字符串,而且JVM的字符緩存池還會緩存這個字符串;
String str = new String("hello");
此時程序除創(chuàng)建字符串外,str所引用的String對象底層還包含一個char[]數(shù)組,這個char[]數(shù)組依次存放了h,e,l,l,o
11. 單線程應(yīng)盡量使用HashMap、ArrayList
HashTable、Vector等使用了同步機(jī)制,降低了性能。
12. 盡量合理的創(chuàng)建HashMap
當(dāng)你要創(chuàng)建一個比較大的hashMap時,充分利用另一個構(gòu)造函數(shù)
public HashMap(int initialCapacity, float loadFactor)
避免HashMap多次進(jìn)行了hash重構(gòu),擴(kuò)容是一件很耗費(fèi)性能的事,在默認(rèn)中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能準(zhǔn)確的估計你所需要的最佳大小,同樣的Hashtable,Vectors也是一樣的道理。
13. 盡量減少對變量的重復(fù)計算
并且在循環(huán)中應(yīng)該避免使用復(fù)雜的表達(dá)式,在循環(huán)中,循環(huán)條件會被反復(fù)計算,如果不使用復(fù)雜表達(dá)式,而使循環(huán)條件值不變的話,程序?qū)\(yùn)行的更快。
14. 盡量避免不必要的創(chuàng)建
15. 盡量在finally塊中釋放資源
程序中使用到的資源應(yīng)當(dāng)被釋放,以避免資源泄漏。這最好在finally塊粗祥中去做。不管程序執(zhí)行的結(jié)果如何,finally塊總是會執(zhí)行的,以確保資源的正確關(guān)閉。
16. 盡量使用移位來代替'a/b'的操作
"/"是一個代價很高的操作,使用移位的操作將會更快和更有效
17.盡量使用移位來代替'a*b'的操作
同樣的,對于'*'操作,使用移位的操作將會更快和更有效
18. 盡量確定StringBuffer的容量
StringBuffer 的構(gòu)造器會創(chuàng)建一個默認(rèn)大小(通常是16)的字符數(shù)組。在使用中,如果超出這個大小,就會重新分配內(nèi)存,創(chuàng)建一個更大的數(shù)組,并將原先的數(shù)組復(fù)制過來,再 丟棄舊的數(shù)組。在大多數(shù)情況下,你可以在創(chuàng)建 StringBuffer的時候指定大小,這樣就避免了在容量不夠的時候自動增長,以提高性能。
19. 盡量早釋放無用對象的引用
大部分時,方法局部引用變量所引用的對象 會隨著方法結(jié)束而變成垃圾,因此,大部分時候程序無需將局部,引用變量顯式設(shè)為null.
20. 盡量避免使用二維數(shù)組
二維數(shù)據(jù)占用的內(nèi)存空間比一維數(shù)組多得多,大概10倍以上。
21. 盡量避免使用split
除非是必須的,否則應(yīng)該避免使用split,split由于支持正則表達(dá)式,所以效率比較低,如果是頻繁的幾十,幾百萬的調(diào)用將會耗費(fèi)大量資源,如果確實(shí)需 要頻繁的調(diào)用split,可以考慮使用apache的StringUtils.split(string,char),頻繁split的可以緩存結(jié)果。
22. ArrayList LinkedList
一 個是線性表,一個是鏈表,一句話,隨機(jī)查詢盡量使用ArrayList,ArrayList優(yōu)于LinkedList,LinkedList還要移動指 針,添加刪除的操作LinkedList優(yōu)于ArrayList,ArrayList還要移動數(shù)據(jù),不過這是理論性分析,事實(shí)未必如此,重要的是理解好2 者得數(shù)據(jù)結(jié)構(gòu),對癥下藥。
23. 盡量使用System.arraycopy ()代替通過來循環(huán)復(fù)制數(shù)組
System.arraycopy() 要比通過循環(huán)來復(fù)制數(shù)組快的多
24. 盡量緩存經(jīng)常使用的對象
盡可能將經(jīng)常使用的對象進(jìn)行緩存,可以使用數(shù)組,或HashMap的容器來進(jìn)行緩存,但這種方式可能導(dǎo)致系統(tǒng)占用過多的緩存,性能下降,推薦可以使用一些第三方的開源工具,如EhCache,Oscache進(jìn)行緩存,他們基本都實(shí)現(xiàn)了FIFO/FLU等緩存算法。
25. 盡量避免非常大的內(nèi)存分配
有時候問題不是由當(dāng)時的堆狀態(tài)造成的,而是因?yàn)榉峙涫≡斐傻?。分配的?nèi)存塊都必須是連續(xù)的,而隨著堆越來越滿,找到較大的連續(xù)塊越來越困難。
26. 慎用異常
當(dāng)創(chuàng)建一個異常時,需要收集一個棧跟蹤(stack track),這個棧跟蹤用于描述異常是在何處創(chuàng)建的。構(gòu)建這些棧跟蹤時需要為運(yùn)行時棧做一份快照,正是這一部分開銷很大。當(dāng)需要創(chuàng)建一個 Exception 時,JVM 不得不說:先別動,我想就您現(xiàn)在的樣子存一份快照,所以暫時停止入棧和出棧操作。棧跟蹤不只包含運(yùn)行時棧中的一兩個元素,而是包含這個棧中的每一個元素。
如 果您創(chuàng)建一個 Exception ,就得付出代價。好在捕獲異常開銷不大,因此可以使用 try-catch 將核心內(nèi)容包起來。從技術(shù)上講,您甚至可以隨意地拋出異常,而不用花費(fèi)很大的代價。招致性能損失的并不是 throw 操作--盡管在沒有預(yù)先創(chuàng)建異常的情況下就拋出異常是有點(diǎn)不尋常。真正要花代價的是創(chuàng)建異常。幸運(yùn)的是,好的編程習(xí)慣已教會我們,不應(yīng)該不管三七二十一就 拋出異常。異常是為異常的情況而設(shè)計的,使用時也應(yīng)該牢記這一原則。
(1)。 用Boolean.valueOf(boolean b)代替new Boolean()
包裝類的內(nèi)存占用是很恐怖的,它是基本類型內(nèi)存占用的N倍(N2),同時new一個對象也是性能的消耗。
(2)。 用Integer.valueOf(int i)代替new Integer()
和Boolean類似,java開發(fā)中使用Integer封裝int的場合也非常多,并且通常用int表示的數(shù)值都非常小。SUN SDK中對Integer的實(shí)例化進(jìn)行了優(yōu)化,Integer類緩存了-128到127這256個狀態(tài)的Integer,如果使用 Integer.valueOf(int i),傳入的int范圍正好在此內(nèi),就返回靜態(tài)實(shí)例。這樣如果我們使用Integer.valueOf代替new Integer的話也將大大降低內(nèi)存的占用。
(3)。 用StringBuffer的append方法代替"+"進(jìn)行字符串相加。
這個已經(jīng)被N多人說過N次了,這個就不多說了。
(4)。 避免過深的類層次結(jié)構(gòu)和過深的方法調(diào)用。
因?yàn)檫@兩者都是非常占用內(nèi)存的(特別是方法調(diào)用更是堆??臻g的消耗大戶)。
(5)。 變量只有在用到它的時候才定義和實(shí)例化。
這是初學(xué)者最容易犯的錯,合理的使用變量,并且只有在用到它的時候才定義和實(shí)例化,能有效的避免內(nèi)存空間和執(zhí)行性能上的浪費(fèi),從而提高了代碼的效率。
(6)。 避免在循環(huán)體中聲明創(chuàng)建對象,即使該對象占用內(nèi)存空間不大。
這種情況在我們的實(shí)際應(yīng)用中經(jīng)常遇到,而且我們很容易犯類似的錯誤
采用上面的第二種編寫方式,僅在內(nèi)存中保存一份對該對象的引用,而不像上面的第一種編寫方式中代碼會在內(nèi)存中產(chǎn)生大量的對象引用,浪費(fèi)大量的內(nèi)存空間,而且增大了垃圾回收的負(fù)荷。因此在循環(huán)體中聲明創(chuàng)建對象的編寫方式應(yīng)該盡量避免。
(7)。 如果if判斷中多個條件用'||'或者''連接,請將出現(xiàn)頻率最高的條件放在表達(dá)式最前面。
這個小技巧往往能有效的提高程序的性能,尤其是當(dāng)if判斷放在循環(huán)體里面時,效果更明顯。
1.JVM管理兩種類型的內(nèi)存:堆內(nèi)存(heap),棧內(nèi)存(stack),堆內(nèi)在主要用來存儲程序在運(yùn)行時創(chuàng)建或?qū)嵗膶ο笈c變量。而棧內(nèi)存則是用來存儲程序代碼中聲明為靜態(tài)(static)(或非靜態(tài))的方法。
2.JVM中對象的生命周期,創(chuàng)建階段,應(yīng)用階段,不可視階段,不可到達(dá)階段,可收集階段,終結(jié)階段,釋放階段
3.避免在循環(huán)體中創(chuàng)建對象,即使該對象點(diǎn)用內(nèi)存空間不大。
4.軟引用的主要特點(diǎn)是具有較強(qiáng)的引用功能。只有當(dāng)內(nèi)存不夠的時候,才回收這類內(nèi)存,因此在內(nèi)存足夠的時候,它們通常不被回收。它可以用于實(shí)現(xiàn)一些常用資源的緩存,實(shí)現(xiàn)Cache的功能
5.弱引用對象與Soft引用對象最大不同就在于:GC在進(jìn)行回收時,需要通過算法檢查是否回收Soft引用對象,而對于Weak引用對象,GC總是進(jìn)行回收。
6.共享靜態(tài)變量存儲空間
7.有時候我們?yōu)榱颂岣呦到y(tǒng)性能,避免重復(fù)耗時的操作,希望能夠重用一些創(chuàng)建完成的對象,利用對象池實(shí)現(xiàn)。類似JDBC連接池。
8.瞬間值,序列化對象大變量時,如果此大變量又沒有用途,則使用transient聲明,不序列化此變量。同時網(wǎng)絡(luò)傳輸中也不傳輸。
9.不要提前創(chuàng)建對象
10 .(1)最基本的建議就是盡早釋放無用對象的引用
A a = new A();
a = null; //當(dāng)使用對象a之后主動將其設(shè)置為空
(2)盡量少用finalize函數(shù)。
(3) 如果需要使用經(jīng)常用到的圖片展,可以使用軟引用。
(4) 注意集合數(shù)據(jù)類型,包括數(shù)組,樹等數(shù)據(jù),這些數(shù)據(jù)結(jié)構(gòu)對GC來說,回收更為復(fù)雜,
(5) 盡量避免在類的默認(rèn)構(gòu)造器中創(chuàng)建,初始化大量的對象,防止在調(diào)用其自類的構(gòu)造器時造成不必要的內(nèi)存資源浪費(fèi)。
(6) 盡量避免強(qiáng)制系統(tǒng)做垃圾內(nèi)存回收。
(7) 盡量避免顯式申請數(shù)組空間。
(8) 盡量在合適的場景下使用對象池技術(shù)以提高系統(tǒng)性能,縮減系統(tǒng)內(nèi)存開銷。
11.當(dāng)做數(shù)組拷貝操作時,采用System.arraycopy()方法完成拷貝操作要比采用循環(huán)的辦法完成數(shù)組拷貝操作效率高
12. 盡量避免在循環(huán)體中調(diào)用方法,因?yàn)榉椒ㄕ{(diào)用是比較昂貴的。
13. 盡量避免在循環(huán)體中使用try-catch 塊,最好在循環(huán)體外使用try--catch塊以提高系統(tǒng)性能。
14. 在多重循環(huán)中,如果有可能,盡量將最長的循環(huán)放在最內(nèi)層,最短的循環(huán)放在最外層,以減少循環(huán)層間的變換次數(shù)。
15. 在需要線程安全的情況下,使用List list = Collections.synchronizedList(new ArrayList());
16. 如果預(yù)知長度,就設(shè)置ArrayList的長度。
17. ArrayList 與 LinkedList 選擇,熟悉底層的實(shí)現(xiàn)原理,選擇適當(dāng)?shù)娜萜鳌?/p>
18. 字符串累加采用StringBuffer.
19. 系統(tǒng)I/O優(yōu)化,采用緩沖和壓縮技術(shù)。優(yōu)化性能。
20. 避免在類在構(gòu)造器的初始化其他類
21 盡量避免在構(gòu)造中對靜態(tài)變量做賦值操作
22. 不要在類的構(gòu)造器中創(chuàng)建類的實(shí)例
23. 組合優(yōu)化繼承
24. 最好通過Class.forname() 動態(tài)的裝載類
25. JSP優(yōu)化,采用out 對象中的print方法代替println()方法
26 .采用ServletOutputStream 對象代替JSPWriter對象
27. 采用適當(dāng)?shù)闹党跏蓟痮ut 對象緩沖區(qū)的大小
28. 盡量采用forward()方法重定向新的JSP
29. 利用線程池技術(shù)處理客戶請求
30.Servlet優(yōu)化
(1) 通過init()方法來緩存一些靜態(tài)數(shù)據(jù)以提高應(yīng)用性能。
(2) 用print() 方法取代println()方法。
(3) 用ServletOutputStream 取代 PrintWriter.
(4) 盡量縮小同步代碼數(shù)量
31. 改善Servlet應(yīng)用性能的方法
(1)不要使用SingleThreadModel
(2)使用線程池ThreadPool
32. EJB優(yōu)化
實(shí)體EJB:
(1)實(shí)體EJB中常用數(shù)據(jù)緩存與釋放
(2)采用延遲加載的方式裝載關(guān)聯(lián)數(shù)據(jù)
(3)盡可能地應(yīng)用CMP類型實(shí)體EJB
(4)直接采用JDBC技術(shù)處理大型數(shù)據(jù)
33. 優(yōu)化JDBC連接
(1)設(shè)置合適的預(yù)取行值
(2)采用連接池技術(shù)
(3)全合理應(yīng)用事務(wù)
(4)選擇合適的事務(wù)隔離層與及時關(guān)閉連接對象
34. PreparedStatemetn只編譯解析一次,而Statement每次都編譯解析。
35. 盡可能地做批處理更新
36. 通過采用合適的getXXX方法提高系統(tǒng)性能
37. 采用設(shè)計模式。
1、把這些提煉到一個方法里面來完成扒告坦
2、一句sql語句能友談搞定的就用一句sql語句。你寫的查詢多個表java代碼肯定沒有mysql的速度快
3、方法模塊化,把功能盡量小化,然后春桐根據(jù)模塊劃分和封裝
摘要開發(fā)者通過各種各樣的方法來嘗試避免單調(diào)冗余的編程 一些編程的規(guī)則例如繼承 多態(tài)或者設(shè)計模型可以幫助開發(fā)者避免產(chǎn)生多余的代碼 不過由于軟件開發(fā)方面存在著不確定性 因此這些規(guī)則并不能消除代碼維護(hù)和重新編寫的需要 在很多時候維護(hù)都是不可避免的 只有不能運(yùn)作的軟件才是從不需要維護(hù)的 不過 這篇文章介紹了你可以使用Java的Reflection API的功能來減少單調(diào)的代碼編寫 并可以使用活動的代碼產(chǎn)生來克服reflection的限制 數(shù)據(jù)配置(由外部的源頭得到數(shù)據(jù)并且將它裝載到一個Java對象中)可以利用reflection的好處來創(chuàng)建一個可重用的方案 問題是很簡單的 將數(shù)據(jù)由一個文件裝入到一個對象的字段中 現(xiàn)在假設(shè)用作數(shù)據(jù)的目標(biāo)Java類每星期改變一次?有一個很直接的解決方法 不過你必須不斷地維護(hù)載入的過程來反映任何的改變 在更復(fù)雜的環(huán)境下 同樣的問題可能會令系統(tǒng)崩潰掉 對于一個處理過運(yùn)用XML的大型系統(tǒng)的人來說 他就會遇到過這個問題 要編寫一個載入的過程通常是非常單調(diào)乏味的 由于數(shù)據(jù)源或者目標(biāo)Java類的改變 你需要經(jīng)常更新和重新編寫代碼 在這里我要介紹另一個解決方案 那就是使用映射 它通常使用更少的編碼 并且可以在目標(biāo)Java類發(fā)生改變后更新自己 最初 我想介紹一個使用Reflection在運(yùn)枝宏行期間配置數(shù)據(jù)的方案 在開始的時候 一個動態(tài) 基于映射的程序要比一個簡單的方法更有吸引力多了 隨后 我要揭示出運(yùn)行時Reflection的復(fù)雜性和冒險性 這篇文章將介紹由運(yùn)行時的Reflection到活動的代碼產(chǎn)生 由簡單到復(fù)雜我的第一個方案使用一個載入類將數(shù)據(jù)從一個文件載入到對象中 我的源代碼含有對StringTokenizer對象下一節(jié)點(diǎn)方法的多次調(diào)用 在修改多次后 我的編碼邏輯變得非常的直接 系統(tǒng)化 該類構(gòu)造了專用的代碼 在這個初始方案中 我只需要使用 個基本的對象 Strings Objects Arrays of objects你可以影射類的對象來產(chǎn)生代碼塊 如下表所示 被影射來產(chǎn)生代碼塊的對象 我已經(jīng)使用這個方案作了幾次編碼 因此我在寫代碼之前我已經(jīng)知道該方案和代碼的結(jié)構(gòu) 難點(diǎn)在于該類是變化的 類的名字 成份和結(jié)構(gòu)在任何時候都可能發(fā)生變化 而任何的改變你都要重新編寫代碼 雖然會發(fā)生這些變化 但是結(jié)構(gòu)和下載的流程仍然是一樣的 在寫代碼前 我仍然知道代碼的結(jié)構(gòu)和成份 我需要一個方法 來將頭腦中的編碼流程轉(zhuǎn)換為一個可重用的 自動的形式 由于我是一個有效率的編程者 我很快就厭倦了編寫幾乎一樣的代碼 這時我想到了映射 數(shù)據(jù)配置通常需要一個源到目的數(shù)據(jù)的影射 影射可以是一個圖解 DTD(document type definition 文檔類型定義) 文件格式等 在這個例子中 映射將一個對象的類定義解釋為我們要映射的流程 映射可以在運(yùn)行時復(fù)制代碼的功能 在需要重寫代猛缺冊碼時 我將載入的過程用映射來代替 它所需要的時間和重寫是一樣的 載入的工程可以概括為以下幾步 解釋 一個影射決定你在構(gòu)造一個對象時需要些什么 請求數(shù)據(jù) 要滿足構(gòu)造的需要 要進(jìn)行一個調(diào)用來得到數(shù)據(jù) 拖 數(shù)據(jù)由源中得到 推 數(shù)據(jù)被填充入一個對象的新實(shí)例 如果必要的話 重復(fù)步驟 你需要以下的類來滿足以上的步驟 .?dāng)?shù)據(jù)類(Data classes) 由ASCII文件中的數(shù)據(jù)實(shí)例化 類定義提供數(shù)據(jù)的影射 數(shù)據(jù)類必須滿足以下的條件 它們必須包含有一個構(gòu)造器來接收全部必需的參數(shù) 以使用一個有效的狀態(tài)來構(gòu)造對象 它們必須由對象構(gòu)成 這些對象是reflective過程知道如何處理的.對象裝載器(Object loader) 使用reflection和數(shù)據(jù)類作為一個影射來載入數(shù)據(jù) 產(chǎn)生數(shù)據(jù)請求 .載入管理器(Load manager) 作為對象裝載器和數(shù)據(jù)源的扮派中介層 將對數(shù)據(jù)的請求轉(zhuǎn)換為一個數(shù)據(jù)指定的調(diào)用 這可以令對象載入器做到與數(shù)據(jù)源無關(guān) 通過它的接口和一個可載入的類對象通信 .?dāng)?shù)據(jù)循環(huán)接口(Data iterator interface) 載入管理器和載入類對象使用這個接口來由數(shù)據(jù)源中得到數(shù)據(jù) 一旦你創(chuàng)建了支持的類 你就可以使用以下的聲明來創(chuàng)建和影射一個對象 FooFileIterator iter = new FooFileIterator(fileLocation log);LoadManager manager = new FooFileLoadManager(iter);SubFooObject obj = (SubFooObject)ReflectiveObjectLoader initializeInstance(SubFooObject class manager log); 通過這個處理 你就創(chuàng)建了一個包含有文件內(nèi)容的SubFooObject實(shí)例 局限開發(fā)者必須決定使用哪個方案來解決問題是最好的 通常做出這個決定是最困難的部分 在考慮使用reflection作數(shù)據(jù)配置時 你要考慮到以下一些限制 不要令一個簡單的問題復(fù)雜化 reflection是比較復(fù)雜的 因此在必要的時候才使用它 一旦開發(fā)者明白了reflection的能力 他就想使用它來解決所有的問題 如果你有更快 更簡單的方案來解決問題時 你就不應(yīng)該使用reflection(即使這個更好的方案可能使用更多的代碼) reflection是強(qiáng)大的 但也有一些風(fēng)險 考慮性能 reflection對性能的影響比較大 因?yàn)橐谶\(yùn)行時發(fā)現(xiàn)和管理類屬性需要時間和內(nèi)存 重新評估方案如上所述 使用運(yùn)行時reflection的第一個限制是 不要令簡單的問題復(fù)雜化 在使用reflection時 這是不可避免的 將reflection和遞歸結(jié)合起來是一個令人頭痛的問題 重新看代碼也是一件可怕的事情 而準(zhǔn)確決定代碼的功能也是非常復(fù)雜的 要知道代碼的準(zhǔn)確作用的唯一方法是使用一些取樣數(shù)據(jù) 逐行地看 就象運(yùn)行時一樣 不過 對于每個可能的數(shù)據(jù)組合都使用這種方式幾乎是不可能的 在這種情況下 使用單元測試代碼可能有些幫助 不過也很可能出現(xiàn)錯誤 幸運(yùn)的是 還有一個可選的方法 可選的方法由上面列出的限制可以看到 在某些情況下 使用reflective載入過程可能是得不償失的 代碼產(chǎn)生提供了一個通用的選擇方法 你也可以使用reflection來檢查一個類并且為載入過程產(chǎn)生代碼 Andrew Hunt和David Thomas介紹了兩類的代碼產(chǎn)生器 見The Pragmatic Programmer( /jwl#resources) Passive(被動) 被動的代碼產(chǎn)生器在實(shí)現(xiàn)代碼時需要人工的干預(yù) 許多的IDE(集成開發(fā)環(huán)境)都提供相應(yīng)的向?qū)韺?shí)現(xiàn) Active(主動) 主動的代碼產(chǎn)生指的是代碼一旦創(chuàng)建 就不再需要修改了 如果有問題產(chǎn)生 這個問題也應(yīng)該在代碼產(chǎn)生器中解決 而不是在產(chǎn)生的源文件中解決 在理想的情況下 這個過程應(yīng)該包含在編譯的處理過程中 從而確保類不會過期 代碼產(chǎn)生的優(yōu)點(diǎn)和缺點(diǎn)包含有以下方面 優(yōu)點(diǎn) .簡單 產(chǎn)生的代碼通常是更便于開發(fā)者閱讀和調(diào)試 .編譯過程的錯誤 Reflexive在運(yùn)行時出現(xiàn)錯誤的機(jī)會要比編譯的期間多 例如 改變被載入的對象將有可能令產(chǎn)生的載入類拋出一個編譯的錯誤 不過reflexive過程將不會看到任何的區(qū)別 直到在運(yùn)行時遇到這個類 缺點(diǎn) .維護(hù) 使用被動的代碼產(chǎn)生 修改被載入的對象將需要更新或者重新產(chǎn)生載入的類 如果該類被重新產(chǎn)生 那么自定義的東西就會丟失 回頭再來看看主動代碼產(chǎn)生的好處在這里我們可以看到在運(yùn)行時使用reflection是不可以接受的 主動的代碼產(chǎn)生有著reflection的全部好處 但是沒有它的限制 還可以繼續(xù)使用reflection 不過只是在代碼的產(chǎn)生過程 而不是運(yùn)行的過程 理由如下 更少冒險 運(yùn)行時的reflection明顯是更冒險的 特別是問題變得復(fù)雜的時候 基于單元測試 但并不是編譯器 多功能性 產(chǎn)生的代碼有著runtime reflection的全部好處 而且有著runtime reflection沒有的好處 更易懂 雖然經(jīng)過多次的處理 但是將遞歸和reflection結(jié)合仍然是很復(fù)雜的 產(chǎn)生源代碼的方式更加容易解釋和理解 代碼產(chǎn)生過程需要遞歸和reflection 但得到的結(jié)果是可查看的源代碼 而不是難以理解的東西 寫代碼產(chǎn)生器要寫一個代碼產(chǎn)生器 在思考的時候 你不能只是簡單地編寫一個方案來解決一個問題 你應(yīng)該看得更遠(yuǎn) 代碼產(chǎn)生器(以及reflection)需要你作更多的思考 如果你只是使用runtime reflection 你就不得不在運(yùn)行時概念化問題 而不是使用簡單 兼容性好的源代碼來解決問題 代碼產(chǎn)生要求你從兩個方面來查看問題 代碼產(chǎn)生過程會將抽象的概念轉(zhuǎn)變?yōu)閷?shí)際的源代碼 Runtime reflection則一直是抽象的 代碼產(chǎn)生過程將你的思考過程轉(zhuǎn)變?yōu)榇a 然后產(chǎn)生并且編譯代碼 編譯器會讓你知道你的思考過程在語法上是否正確 單元測試則可以驗(yàn)證代碼在運(yùn)行時的行為 就動態(tài)特性方面 runtime reflection就不能達(dá)到這個級別的安全性 代碼產(chǎn)生器在經(jīng)歷后幾次失敗的設(shè)計后 我認(rèn)為最簡單的方法是 在載入過程中 為每一種需要實(shí)例化的類產(chǎn)生一個方法 一個方法工廠產(chǎn)生每個特別類的正確方法 一個代碼編譯對象緩沖來自代碼工廠的方法請求 以產(chǎn)生最終源代碼文件的內(nèi)容 MethodCode對象是代碼產(chǎn)生過程的核心 以下就是一個int的代碼產(chǎn)生對象的例子 public class MethodForInt extends MethodCode {private final static MethodParameter param = new MethodParameter(SimpleFileIterator class parser );public MethodForInt(Class type CodeBuilder builder){super(type builder);}public MethodParameter[] getInputParameters(){return new MethodParameter[]{param};} lishixinzhi/Article/program/Java/hx/201311/25959