多年的收藏

程序員珍藏的東西會是什麼?呵呵,除了平時寫的代碼,就是那些百看不厭的電子書了。

昨天很鬱悶,我用了5年的移動硬盤,莫名奇妙的壞掉了。裏面40G的資料全部報銷了。
爲了不再重蹈覆轍,我決定把重要的電子書都放到網絡硬盤上去備份。索性將這些資料的下載方式公佈出來,與大家分享,一定會有你想要的!

下載的兄弟注意了,點擊下載後,可以在url中看到後綴名:),如果把後綴名改錯了就看不了了,所有的資料都有人下載過了,應該都能看。



Python相關的資料還可以看:http://jythoner.javaeye.com/blog/569987



新書區

Python源碼剖析:下載文件 Python源碼剖析.chm (670.21 KB)

Python黑客:下載文件 Gray Hat Python Python Programming for Hackers and Reverse Engineers.pdf (3.30 MB)

上一本書的源碼:下載文件 ghpython_src.zip (606.56 KB)

php5手冊:下載文件 php5手冊.chm (5.70 MB)

Google Adsense的祕密:下載文件 《Google Adsense的祕密》中文版.pdf (905.51 KB)

《Google_Cash》快速致富手冊,主要講如何利用Google Adwords網賺:下載文件 《Google_Cash》快速致富手冊.pdf (2.23 MB)

Google cash補充,Day job killer中文版:下載文件 跟打工生涯說再見.pdf (749.96 KB)

Java

Java API 1.6中文版:下載文件 JDK API 1.6.0 zh_CN.CHM (35.12 MB)

下載文件 《java編程思想》第三版 第四版包括習題答案(8.92 MB)

下載文件 Java Collections.pdf (1.33 MB)

下載文件 Java_Collections-src.zip (150.21 KB)

下載文件 Java IO.chm (2.76 MB)

下載文件 Java NIO.pdf (1.40 MB)

下載文件 IO.gif (36.00 KB)

下載文件 JDBC Recipes A Problem Solution Approach.pdf (5.23 MB)

下載文件 Java Network Programming.chm (1.97 MB)

下載文件 Servlets and JavaServer Pages The J2EE Tier.pdf  (4.73 MB)

英文版:下載文件 Java.Threads.3rd.Edition.chm (685.45 KB)

中文版:下載文件 java線程.pdf (20.26 MB)

Java與模式絕對高清版:下載文件 Java與模式.pdf (39.64 MB)

爲什麼要看上面的那些書?請看我以前 帖子:Java 推薦讀物與源代碼閱讀:http://jythoner.javaeye.com/blog/311434

Java程序員必備的書籍,比API更有用:下載文件 The Java Developers Almanac 1.4.chm (679.90 KB)

找工作必備:下載文件 125條常見的java面試筆試題大彙總.pdf  (95.17 KB)

一本Java實現的數據結構書籍:下載文件 Java數據結構與算法.pdf (25.35 MB)

學Struts,Hibernate,Spring,如果不懂反射的原理,就不用談了:下載文件 Java Reflection In Action.pdf (1.70 MB)

JMX,Jboss的基礎,jdk5後被納入進來:下載文件 JMX In Action.pdf (4.76 MB)

Junit絕對經典書籍:下載文件 Junit in action.pdf (15.64 MB)

一本專門講jdk1.5新特性的書,英文版:下載文件 Java 1.5 Tiger A Developer's Notebook.chm(411.57 KB)

中文版:下載文件 Java 1.5 Tiger A Developer's Notebook.pdf (7.23 MB)

源代碼:下載文件 Java 1.5 Tiger A Developer's Notebook.zip (38.18 KB)

下載文件 Java極限編程.pdf (23.96 MB)

下載文件 uml distilled.chm (1.52 MB)

下載文件 Expert One-on-One J2EE Design and Development.chm (10.66 MB)

下載文件 測試驅動開發.pdf (6.89 MB)

如果不知道上面4本書的作者,那麼基本上你的Java算白學了

Ant手冊:下載文件 Apache Ant Manual 1.7.chm (949.48 KB)

英文版:下載文件 UML for Java Programmers.pdf (1.77 MB)

中文版:下載文件 UML for Java Programmers中文版.pdf (2.51 MB)

源代碼:下載文件 UML for Java Programmers.rar (465.36 KB)

下載文件 Java實用系統開發指南.pdf (57.82 MB)

下載文件 JAVA優化編程.pdf (13.58 MB)

下載文件 Java and XML(英文第三版).chm (3.79 MB)

下載文件 Apress.Pro.XML.Development.with.Java.Technology.pdf (12.83 MB)



Eclipse插件開發

一個高手推薦的4本必讀書:

中文版:下載文件 Contributing to Eclipse Principles, Patterns and PlugIns.pdf (23.29 MB)

英文版:下載文件 Contributing to Eclipse Principles, Patt ... (4.93 MB)

下載文件 Eclipse Building Commercial-Quality Plug-ins.chm (20.11 MB)

下載文件 Eclipse Modeling Framework.chm (3.20 MB)

下載文件 Eclipse Rich Client Platform Designing Coding and Packaging Java Applications.chm(4.90 MB)

下載文件 SWT-A Developer's Note Book.chm (1.53 MB)

API:下載文件 swt jface API.pdf (7.59 MB)


Linux

中國Linuxer應該沒人不知道鳥哥,這本書是基礎版與網絡版的合集:下載文件 鳥哥的Linux私房菜.pdf (36.43 MB)

命令大全,支持查找:下載文件 Linux命令大全(修改版).chm (345.84 KB)

無意間發現的,裏面記載了很多實用的命令:下載文件 Unix Toolbox.pdf (350.31 KB)

學習shell編程必讀,裏面包括一份詳細的學習筆記:下載文件 LINUX與UNIX SHELL編程指南.zip (19.22 MB)

Sed和Awk唯一的書:下載文件 Sed and Awk.pdf 中文版(6.89 MB)

下載文件 AWK單行腳本快速參考.doc (52.50 KB)

下載文件 SED單行腳本快速參考.doc (91.00 KB)

一張RE圖表:下載文件 regular-expressions-cheat-sheet-v2.pdf (647.55 KB)

Linux+認證書籍:下載文件 McGraw.Hill.Linux.plus.Certification.Study Guide.pdf (28.60 MB)

下載文件 O'Reilly.Bash.Cookbook.pdf (3.16 MB)

下載文件 A Practical Guide to Linux Commands, Edi ... (3.61 MB)



Oracle


Oracle9i OCP官方培訓教程:
下載文件 sql.zip (3.34 MB)

下載文件 dba1.zip (1.78 MB)

下載文件 dba2.zip (2.95 MB)

下載文件 Perf.zip (6.90 MB)

Oracle 10教程:
下載文件 Oracle.Database.10g.Administration.Workshop.II.Student.Guide.pdf (4.74 MB)

下載文件 Oracle.Database.10g.Administration.Workshop.I.Student.Guide.pdf (5.66 MB)

下載文件 Sybex.OCA.Oracle.10g.Administration.I.Study.Guide.pdf (18.20 MB)

下載文件 Sybex.OCP.Oracle.10g.Administration.II.Study.Guide.pdf (15.39 MB)

Oracle 11g官方培訓教程:
下載文件 d49996gc10_ppt Oracle Database 11g SQL Fundamentals I.rar (2.26 MB)

下載文件 d49994gc10_ppt Oracle Database 11g SQL Fundamentals II.rar (1.78 MB)

下載文件 d50102gc10_ppt Oracle Database 11g Administration Workshop I.rar (11.00 MB)

下載文件 d50079gc10_ppt Oracle Database 11g Administration Workshop II.rar (6.31 MB)

下載文件 d50317gc10_ppt Oracle Database 11g Performance Tuning.rar (3.63 MB)

英文版:下載文件 d50081gc10_ppt Oracle Database 11g New Features for Administrators.rar(6.64 MB)

中文版:下載文件 d50081cn11_ppt Oracle Database 11g - New Features for Administrators.rar (6.58 MB)



下載文件 d46592gc11_ppt Oracle Database 10g Managing Oracle on Linux for System Administrators.rar (1.25 MB)

下載文件 d50311gc10_ppt Oracle Database 11g RAC Administration.rar (7.80 MB)



下載文件 Oracle Database 10g.chm (2.43 MB)

下載文件 ORACLE.10G入門與實踐.pdf (39.58 MB)

下載文件 Oracle.Database.10g實用培訓教程.pdf (47.49 MB)

下載文件 精通ORACLE.10G備份與恢復.pdf (23.90 MB)



Python
BASIC:

A Byte of Python(Python 3.0) 下載文件 A Byte of Python.pdf (564.61 KB)

A Byte of Python中文版 下載文件 Python簡明教程.pdf (784.85 KB)

下載文件 Dive into Python.zip (763.71 KB)

下載文件 Dive into Python 中文版.zip (3.51 MB)

下載文件 Python Essential Reference 4th Edition.pdf (4.80 MB)

下載文件 Python精要參考.pdf (678.65 KB)

下載文件 Learning Python.pdf (4.80 MB)

下載文件 Core Python Programming 2nd Edition.chm (3.45 MB)

高清完整版 下載文件 Python核心編程第二版.pdf (5.16 MB)

下載文件 Python Standard Library.chm (355.63 KB)

下載文件 Python Standard Library中文版.pdf (1.00 MB)

下載文件 Python Cookbook.chm (1.00 MB)

下載文件 Python Cookbook Collection.chm (2.53 MB)

Guido 2007年Python大會ppt,關於python3.0新特性 下載文件 Py3k2007PyCon.ppt (134.00 KB)



GUI:

下載文件 wxPython In Action.rar (9.24 MB)

wxPython in Action中文版 下載文件 wxPython實戰(中文版).pdf (3.54 MB)

下載文件 wxPythonInAction_src.zip (333.41 KB)



WEB:

Django Book 收費版下載文件 The Definitive Guide to Django 2nd Edition.pdf (5.92 MB)

下載文件 Practical Django Projects 2nd Edition.pdf (4.89 MB)



GAE:

下載文件 Google App Engine 入門.pdf (227.23 KB)

下載文件 Google App Engine 開發人員指南.pdf (855.70 KB)

下載文件 Using Google App Engine.pdf (3.20 MB)

下載文件 Developing With Google App Engine.pdf (3.35 MB)



Other:

下載文件 Twisted Network Programming Essentials Python.chm (1.24 MB)

下載文件 Python for Unix and Linux System Administration.pdf (3.41 MB)

下載文件 Text Processing in Python.chm (871.68 KB)

下載文件 Python Programming on Win32.chm (2.10 MB)

下載文件 Jython for Java Programmers.chm (713.20 KB)



English


下載文件 古典 1677超核心詞表.pdf (1.34 MB)

下載文件 古典 1677超核心詞表.rm (3.41 MB)

下載文件 新東方李玉技老師的734條高頻詞組.pdf (77.00 KB)

下載文件 英語常用短語詞典.chm (2.31 MB)



Perl

下載文件 Perl Cook Book.pdf (9.22 MB)

英文版:下載文件 Learning.Perl.4ed.En.chm (699.96 KB)

中文版:下載文件 Learning.Perl.4ed.Cn.pdf (1.19 MB)

一本講用perl進行automation測試的好書:下載文件 Perl Testing.chm (640.57 KB)



Other


下載文件 Agile Web Development with Rails 3rdEdition.pdf (10.87 MB)

譚浩強那本:下載文件 C語言程序設計.pdf (9.95 MB)

下載文件 C語言趣味編程百例.pdf (4.72 MB)

下載文件 數據庫系統概論(第三版).pdf (10.16 MB)

下載文件 php5手冊.chm (5.70 MB)

精通正則表達式:下載文件 Mastering Regular Expressions.chm (1.45 MB)
程序員珍藏的東西會是什麼?呵呵,除了平時寫的代碼,就是那些百看不厭的電子書了。

昨天很鬱悶,我用了5年的移動硬盤,莫名奇妙的壞掉了。裏面40G的資料全部報銷了。
爲了不再重蹈覆轍,我決定把重要的電子書都放到網絡硬盤上去備份。索性將這些資料的下載方式公佈出來,與大家分享,一定會有你想要的!

Java Linux Oracle Perl相關的資料請看:http://jythoner.javaeye.com/blog/570792

BASIC:

A Byte of Python(Python 3.0) 下載文件 A Byte of Python.pdf (564.61 KB)

A Byte of Python中文版 下載文件 Python簡明教程.pdf (784.85 KB)

下載文件 Dive into Python.zip (763.71 KB)

下載文件 Dive into Python 中文版.zip (3.51 MB)

下載文件 Python Essential Reference 4th Edition.pdf (4.80 MB)

下載文件 Python精要參考.pdf (678.65 KB)

下載文件 Learning Python.pdf (4.80 MB)

下載文件 Core Python Programming 2nd Edition.chm (3.45 MB)

高清完整版 下載文件 Python核心編程第二版.pdf (5.16 MB)

下載文件 Python Standard Library.chm (355.63 KB)

下載文件 Python Standard Library中文版.pdf (1.00 MB)

下載文件 Python Cookbook.chm (1.00 MB)

下載文件 Python Cookbook Collection.chm (2.53 MB)

Guido 2007年Python大會ppt,關於python3.0新特性 下載文件 Py3k2007PyCon.ppt (134.00 KB)



GUI:

下載文件 wxPython In Action.rar (9.24 MB)

wxPython in Action中文版 下載文件 wxPython實戰(中文版).pdf (3.54 MB)

下載文件 wxPythonInAction_src.zip (333.41 KB)



WEB:

Django Book 收費版下載文件 The Definitive Guide to Django 2nd Edition.pdf (5.92 MB)

下載文件 Practical Django Projects 2nd Edition.pdf (4.89 MB)



GAE:

下載文件 Google App Engine 入門.pdf (227.23 KB)

下載文件 Google App Engine 開發人員指南.pdf (855.70 KB)

下載文件 Using Google App Engine.pdf (3.20 MB)

下載文件 Developing With Google App Engine.pdf (3.35 MB)



Other:

下載文件 Twisted Network Programming Essentials Python.chm (1.24 MB)

下載文件 Python for Unix and Linux System Administration.pdf (3.41 MB)

下載文件 Text Processing in Python.chm (871.68 KB)

下載文件 Python Programming on Win32.chm (2.10 MB)

下載文件 Jython for Java Programmers.chm (713.20 KB)
1、HTML靜態化其實大家都知道,效率最高、消耗最小的就是純靜態化的html頁面,所以我們儘可能使我們的網站上的頁面採用靜態頁面來實現,這個最簡 單的方法其實也是最有效的方法。但是對於大量內容並且頻繁更新的網站,我們無法全部手動去挨個實現,於是出現了我們常見的信息發佈系統CMS,像我們常訪 問的各個門戶站點的新聞頻道,甚至他們的其他頻道,都是通過信息發佈系統來管理和實現的,信息發佈系統可以實現最簡單的信息錄入自動生成靜態頁面,還能具 備頻道管理、權限管理、自動抓取等功能,對於一個大型網站來說,擁有一套高效、可管理的CMS是必不可少的。除了門戶和信息發佈類型的網站,對於交互性要 求很高的社區類型網站來說,儘可能的靜態化也是提高性能的必要手段,將社區內的帖子、文章進行實時的靜態化,有更新的時候再重新靜態化也是大量使用的策 略,像Mop的大雜燴就是使用了這樣的策略,網易社區等也是如此。同時,html靜態化也是某些緩存策略使用的手段,對於系統中頻繁使用數據庫查詢但是內 容更新很小的應用,可以考慮使用html靜態化來實現,比如論壇中論壇的公用設置信息,這些信息目前的主流論壇都可以進行後臺管理並且存儲再數據庫中,這 些信息其實大量被前臺程序調用,但是更新頻率很小,可以考慮將這部分內容進行後臺更新的時候進行靜態化,這樣避免了大量的數據庫訪問請求。
2、圖片服務器分離大家知道,對於Web服務器來說,不管是Apache、IIS還是其他容器,圖片是最消耗資源的,於是我們有必要將圖片與頁面 進行分離,這是基本上大型網站都會採用的策略,他們都有獨立的圖片服務器,甚至很多臺圖片服務器。這樣的架構可以降低提供頁面訪問請求的服務器系統壓力, 並且可以保證系統不會因爲圖片問題而崩潰,在應用服務器和圖片服務器上,可以進行不同的配置優化,比如apache在配置ContentType的時候可 以儘量少支持,儘可能少的LoadModule,保證更高的系統消耗和執行效率。

3、數據庫集羣和庫表散列大型網站都有複雜的應用,這些應用必須使用數據庫,那麼在面對大量訪問的時候,數據庫的瓶頸很快就能顯現出來,這時一臺 數據庫將很快無法滿足應用,於是我們需要使用數據庫集羣或者庫表散列。在數據庫集羣方面,很多數據庫都有自己的解決方案,Oracle、Sybase等都 有很好的方案,常用的MySQL提供的Master/Slave也是類似的方案,您使用了什麼樣的DB,就參考相應的解決方案來實施即可。上面提到的數據 庫集羣由於在架構、成本、擴張性方面都會受到所採用DB類型的限制,於是我們需要從應用程序的角度來考慮改善系統架構,庫表散列是常用並且最有效的解決方 案。我們在應用程序中安裝業務和應用或者功能模塊將數據庫進行分離,不同的模塊對應不同的數據庫或者表,再按照一定的策略對某個頁面或者功能進行更小的數 據庫散列,比如用戶表,按照用戶ID進行表散列,這樣就能夠低成本的提升系統的性能並且有很好的擴展性。sohu的論壇就是採用了這樣的架構,將論壇的用 戶、設置、帖子等信息進行數據庫分離,然後對帖子、用戶按照板塊和ID進行散列數據庫和表,最終可以在配置文件中進行簡單的配置便能讓系統隨時增加一臺低 成本的數據庫進來補充系統性能。

4、緩存緩存一詞搞技術的都接觸過,很多地方用到緩存。網站架構和網站開發中的緩存也是非常重要。這裏先講述最基本的兩種緩存。高級和分佈式的緩 存在後面講述。架構方面的緩存,對Apache比較熟悉的人都能知道Apache提供了自己的緩存模塊,也可以使用外加的Squid模塊進行緩存,這兩種 方式均可以有效的提高Apache的訪問響應能力。網站程序開發方面的緩存,Linux上提供的Memory Cache是常用的緩存接口,可以在web開發中使用,比如用Java開發的時候就可以調用MemoryCache對一些數據進行緩存和通訊共享,一些大 型社區使用了這樣的架構。另外,在使用web語言開發的時候,各種語言基本都有自己的緩存模塊和方法,PHP有Pear的Cache模塊,Java就更多 了,.net不是很熟悉,相信也肯定有。

5、鏡像鏡像是大型網站常採用的提高性能和數據安全性的方式,鏡像的技術可以解決不同網絡接入商和地域帶來的用戶訪問速度差異,比如 ChinaNet和EduNet之間的差異就促使了很多網站在教育網內搭建鏡像站點,數據進行定時更新或者實時更新。在鏡像的細節技術方面,這裏不闡述太 深,有很多專業的現成的解決架構和產品可選。也有廉價的通過軟件實現的思路,比如Linux上的rsync等工具。
6、負載均衡負載均衡將是大型網站解決高負荷訪問和大量併發請求採用的終極解決辦法。負載均衡技術發展了多年,有很多專業的服務提供商和產品可以選擇,我個人接觸過一些解決方法,其中有兩個架構可以給大家做參考。

7、硬件四層交換第四層交換使用第三層和第四層信息包的報頭信息,根據應用區間識別業務流,將整個區間段的業務流分配到合適的應用服務器進行處 理。 第四層交換功能就象是虛 IP,指向物理服務器。它傳輸的業務服從的協議多種多樣,有HTTP、FTP、NFS、Telnet或其他協議。這些業務在物理服務器基礎上,需要複雜的 載量平衡算法。在IP世界,業務類型由終端TCP或UDP端口地址來決定,在第四層交換中的應用區間則由源端和終端IP地址、TCP和UDP端口共同決 定。在硬件四層交換產品領域,有一些知名的產品可以選擇,比如Alteon、F5等,這些產品很昂貴,但是物有所值,能夠提供非常優秀的性能和很靈活的管 理能力。Yahoo中國當初接近2000臺服務器使用了三四臺Alteon就搞定了

。8、軟件四層交換大家知道了硬件四層交換機的原理後,基於OSI模型來實現的軟件四層交換也就應運而生,這樣的解決方案實現的原理一致,不過性 能稍差。但是滿足一定量的壓力還是遊刃有餘的,有人說軟件實現方式其實更靈活,處理能力完全看你配置的熟悉能力。軟件四層交換我們可以使用Linux上常 用的LVS來解決,LVS就是Linux Virtual Server,他提供了基於心跳線heartbeat的實時災難應對解決方案,提高系統的魯棒性,同時可供了靈活的虛擬VIP配置和管理功能,可以同時滿 足多種應用需求,這對於分佈式的系統來說必不可少。一個典型的使用負載均衡的策略就是,在軟件或者硬件四層交換的基礎上搭建squid集羣,這種思路在很 多大型網站包括搜索引擎上被採用,這樣的架構低成本、高性能還有很強的擴張性,隨時往架構裏面增減節點都非常容易。這樣的架構我準備空了專門詳細整理一下 和大家探討。對於大型網站來說,前面提到的每個方法可能都會被同時使用到,我這裏介紹得比較淺顯,具體實現過程中很多細節還需要大家慢慢熟悉和體會,有時 一個很小的squid參數或者apache參數設置,對於系統性能的影響就會很大,希望大家一起討論,達到拋磚引玉之效。


用squid做web cache server,而apache在squid的後面提供真正的web服務。當然使用這樣的架構必須要保證主頁上大部分都是靜態頁面。這就需要程序員的配合將頁面在反饋給客戶端之前將頁面全部轉換成靜態頁面。
基本看出sina和sohu對於頻道等欄目都用了相同的技術,即squid來監聽這些IP的80端口,而真正的web server來監聽另外一個端口。從用戶的感覺上來說不會有任何的區別,而相對於將web server直接和客戶端連在一起的方式,這樣的方式明顯的節省的帶寬和服務器。用戶訪問的速度感覺也會更快。
http://www.dbanotes.net/arch/yupoo_arch.html

帶寬:4000M/S (參考)
服務器數量:60 臺左右
Web服務器:Lighttpd, Apache, nginx
應用服務器:Tomcat
其他:Python, Java, MogileFS 、ImageMagick 等

關於 Squid 與 Tomcat

Squid 與 Tomcat 似乎在 Web 2.0 站點的架構中較少看到。我首先是對 Squid 有點疑問,對此阿華的解釋是"目前暫時還沒找到效率比 Squid 高的緩存系統,原來命中率的確很差,後來在 Squid 前又裝了層 Lighttpd, 基於 url 做 hash, 同一個圖片始終會到同一臺 squid 去,所以命中率徹底提高了"

對於應用服務器層的 Tomcat,現在 Yupoo! 技術人員也在逐漸用其他輕量級的東西替代,而 YPWS/YPFS 現在已經用 Python 進行開發了。

名次解釋:

· YPWS--Yupoo Web Server YPWS 是用 Python開發的一個小型 Web 服務器,提供基本的 Web 服務外,可以增加針對用戶、圖片、外鏈網站顯示的邏輯判斷,可以安裝於任何有空閒資源的服務器中,遇到性能瓶頸時方便橫向擴展。

· YPFS--Yupoo File System 與 YPWS 類似,YPFS 也是基於這個 Web 服務器上開發的圖片上傳服務器。


【Updated: 有網友留言質疑 Python 的效率,Yupoo 老大劉平陽在 del.icio.us 上寫到 "YPWS用Python自己寫的,每臺機器每秒可以處理294個請求, 現在壓力幾乎都在10%以下"】

圖片處理層

接下來的 Image Process Server 負責處理用戶上傳的圖片。使用的軟件包也是 ImageMagick,在上次存儲升級的同時,對於銳化的比率也調整過了(我個人感覺,效果的確好了很多)。”Magickd“ 是圖像處理的一個遠程接口服務,可以安裝在任何有空閒 CPU資源的機器上,類似 Memcached的服務方式。

我們知道 Flickr 的縮略圖功能原來是用 ImageMagick 軟件包的,後來被雅虎收購後出於版權原因而不用了(?);EXIF 與 IPTC Flicke 是用 Perl 抽取的,我是非常建議 Yupoo! 針對 EXIF 做些文章,這也是潛在產生受益的一個重點。

圖片存儲層

原來 Yupoo! 的存儲採用了磁盤陣列櫃,基於 NFS 方式的,隨着數據量的增大,”Yupoo! 開發部從07年6月份就開始着手研究一套大容量的、能滿足 Yupoo! 今後發展需要的、安全可靠的存儲系統“,看來 Yupoo! 系統比較有信心,也是滿懷期待的,畢竟這要支撐以 TB 計算的海量圖片的存儲和管理。我們知道,一張圖片除了原圖外,還有不同尺寸的,這些圖片統一存儲在 MogileFS 中。

對於其他部分,常見的 Web 2.0 網站必須軟件都能看到,如 MySQL、Memcached 、Lighttpd 等。Yupoo! 一方面採用不少相對比較成熟的開源軟件,一方面也在自行開發定製適合自己的架構組件。這也是一個 Web 2.0 公司所必需要走的一個途徑。

非常感謝一下 Yupoo! 阿華對於技術信息的分享,技術是共通的。下一個能爆料是哪家?

--EOF--

lighttpd+squid這套緩存是放在另外一個機房作爲cdn的一個節點使用的,圖中沒描繪清楚,給大家帶來不便了。
squid前端用lighttpd沒用nginx,主要是用了這麼久,沒出啥大問題,所以就沒想其他的了。
URL Hash的擴展性的確不好,能做的就是不輕易去增減服務器,我們目前是5臺服務器做一組hash.

我們現在用Python寫的Web Server,在效率方面,我可以給個測試數據,根據目前的訪問日誌模擬訪問測試的結果是1臺ypws,平均每秒處理294個請求(加載所有的邏輯判斷)。
在可靠性上,還不沒具體的數據,目前運行1個多月還沒有任何異常。

lvs每個節點上都裝nginx,主要是爲了反向代理及處理靜態內容,不過apache已顯得不是那麼必需,準備逐漸去掉。

我們處理圖片都是即時的,我們目前半數以上的服務器都裝了magickd服務,用來分擔圖片處理請求。



http://www.dbanotes.net/review/tailrank_arch.html

每天數以千萬計的 Blog 內容中,實時的熱點是什麼? Tailrank 這個 Web 2.0 Startup 致力於回答這個問題。

專門爆料網站架構的 Todd Hoff 對 Kevin Burton 進行了採訪。於是我們能瞭解一下 Tailrank 架構的一些信息。每小時索引 2400 萬的 Blog 與 Feed,內容處理能力爲 160-200Mbps,IO 寫入大約在10-15MBps。每個月要處理 52T 之多的原始數據。Tailrank 所用的爬蟲現在已經成爲一個獨立產品:spinn3r。

服務器硬件

目前大約 15 臺服務器,CPU 是 64 位的 Opteron。每臺主機上掛兩個 SATA 盤,做 RAID 0。據我所知,國內很多 Web 2.0 公司也用的是類似的方式,SATA 盤容量達,低廉價格,堪稱不二之選。操作系統用的是 Debian Linux 。Web 服務器用 Apache 2.0,Squid 做反向代理服務器。

數據庫

Tailrank 用 MySQL 數據庫,聯邦數據庫形式。存儲引擎用 InnoDB, 數據量 500GB。Kevin Burton 也指出了 MySQL 5 在修了一些 多核模式下互斥鎖的問題(This Bug?)。到數據庫的JDBC 驅動連接池用 lbpool 做負載均衡。MySQL Slave 或者 Master的複製用 MySQLSlaveSync 來輕鬆完成。不過即使這樣,還要花費 20%的時間來折騰 DB。

其他開放的軟件

任何一套系統都離不開合適的 Profiling 工具,Tailrank 也不利外,針對 Java 程序的 Benchmark 用 Benchmark4j。Log 工具用 Log5j(不是 Log4j)。Tailrank 所用的大部分工具都是開放的。

Tailrank 的一個比較大的競爭對手是 Techmeme,雖然二者暫時看面向內容的側重點有所不同。其實,最大的對手還是自己,當需要挖掘的信息量越來越大,如果精準並及時的呈現給用戶內容的 成本會越來越高。從現在來看,Tailrank 離預期目標還差的很遠。期待羅馬早日建成


YouTube架構學習

關鍵字: YouTube

原文: YouTube Architecture

YouTube發展迅速,每天超過1億的視頻點擊量,但只有很少人在維護站點和確保伸縮性。

平臺
Apache
Python
Linux(SuSe)
MySQL
psyco,一個動態的Python到C的編譯器
lighttpd代替Apache做視頻查看

狀態
支持每天超過1億的視頻點擊量
成立於2005年2月
於2006年3月達到每天3千萬的視頻點擊量
於2006年7月達到每天1億的視頻點擊量
2個系統管理員,2個伸縮性軟件架構師
2個軟件開發工程師,2個網絡工程師,1個DBA

處理飛速增長的流量

Java代碼

1. while (true)

2. {

3.  identify_and_fix_bottlenecks();

4.  drink();

5.  sleep();

6.  notice_new_bottleneck();

7. }

while (true)

{

  identify_and_fix_bottlenecks();

  drink();

  sleep();

  notice_new_bottleneck();

}


每天運行該循環多次

Web服務器
1,NetScaler用於負載均衡和靜態內容緩存
2,使用mod_fast_cgi運行Apache
3,使用一個Python應用服務器來處理請求的路由
4,應用服務器與多個數據庫和其他信息源交互來獲取數據和格式化html頁面
5,一般可以通過添加更多的機器來在Web層提高伸縮性
6,Python的Web層代碼通常不是性能瓶頸,大部分時間阻塞在RPC
7,Python允許快速而靈活的開發和部署
8,通常每個頁面服務少於100毫秒的時間
9,使用psyco(一個類似於JIT編譯器的動態的Python到C的編譯器)來優化內部循環
10,對於像加密等密集型CPU活動,使用C擴展
11,對於一些開銷昂貴的塊使用預先生成並緩存的html
12,數據庫裏使用行級緩存
13,緩存完整的Python對象
14,有些數據被計算出來併發送給各個程序,所以這些值緩存在本地內存中。這是個使用不當的策略。應用服務器裏最快的緩存將預先計算的值發送給所有服務器也花不了多少時間。只需弄一個代理來監聽更改,預計算,然後發送。

視頻服務
1,花費包括帶寬,硬件和能源消耗
2,每個視頻由一個迷你集羣來host,每個視頻被超過一臺機器持有
3,使用一個集羣意味着:
-更多的硬盤來持有內容意味着更快的速度
-failover。如果一臺機器出故障了,另外的機器可以繼續服務
-在線備份
4,使用lighttpd作爲Web服務器來提供視頻服務:
-Apache開銷太大
-使用epoll來等待多個fds
-從單進程配置轉變爲多進程配置來處理更多的連接
5,大部分流行的內容移到CDN:
-CDN在多個地方備份內容,這樣內容離用戶更近的機會就會更高
-CDN機器經常內存不足,因爲內容太流行以致很少有內容進出內存的顛簸
6,不太流行的內容(每天1-20瀏覽次數)在許多colo站點使用YouTube服務器
-長尾效應。一個視頻可以有多個播放,但是許多視頻正在播放。隨機硬盤塊被訪問
-在這種情況下緩存不會很好,所以花錢在更多的緩存上可能沒太大意義。
-調節RAID控制並注意其他低級問題
-調節每臺機器上的內存,不要太多也不要太少

視頻服務關鍵點
1,保持簡單和廉價
2,保持簡單網絡路徑,在內容和用戶間不要有太多設備
3,使用常用硬件,昂貴的硬件很難找到幫助文檔
4,使用簡單而常見的工具,使用構建在Linux裏或之上的大部分工具
5,很好的處理隨機查找(SATA,tweaks)

縮略圖服務
1,做到高效令人驚奇的難
2,每個視頻大概4張縮略圖,所以縮略圖比視頻多很多
3,縮略圖僅僅host在幾個機器上
4,持有一些小東西所遇到的問題:
-OS級別的大量的硬盤查找和inode和頁面緩存問題
-單目錄文件限制,特別是Ext3,後來移到多分層的結構。內核2.6的最近改進可能讓Ext3允許大目錄,但在一個文件系統裏存儲大量文件不是個好主意
-每秒大量的請求,因爲Web頁面可能在頁面上顯示60個縮略圖
-在這種高負載下Apache表現的非常糟糕
-在Apache前端使用squid,這種方式工作了一段時間,但是由於負載繼續增加而以失敗告終。它讓每秒300個請求變爲20個
-嘗試使用lighttpd但是由於使用單線程它陷於困境。遇到多進程的問題,因爲它們各自保持自己單獨的緩存
-如此多的圖片以致一臺新機器只能接管24小時
-重啓機器需要6-10小時來緩存
5,爲了解決所有這些問題YouTube開始使用Google的BigTable,一個分佈式數據存儲:
-避免小文件問題,因爲它將文件收集到一起
-快,錯誤容忍
-更低的延遲,因爲它使用分佈式多級緩存,該緩存與多個不同collocation站點工作
-更多信息參考Google Architecture,GoogleTalk Architecture和BigTable

數據庫
1,早期
-使用MySQL來存儲元數據,如用戶,tags和描述
-使用一整個10硬盤的RAID 10來存儲數據
-依賴於信用卡所以YouTube租用硬件
-YouTube經過一個常見的革命:單服務器,然後單master和多read slaves,然後數據庫分區,然後sharding方式
-痛苦與備份延遲。master數據庫是多線程的並且運行在一個大機器上所以它可以處理許多工作,slaves是單線程的並且通常運行在小一些的服務器上並且備份是異步的,所以slaves會遠遠落後於master
-更新引起緩存失效,硬盤的慢I/O導致慢備份
-使用備份架構需要花費大量的money來獲得增加的寫性能
-YouTube的一個解決方案是通過把數據分成兩個集羣來將傳輸分出優先次序:一個視頻查看池和一個一般的集羣
2,後期
-數據庫分區
-分成shards,不同的用戶指定到不同的shards
-擴散讀寫
-更好的緩存位置意味着更少的IO
-導致硬件減少30%
-備份延遲降低到0
-現在可以任意提升數據庫的伸縮性

數據中心策略
1,依賴於信用卡,所以最初只能使用受管主機提供商
2,受管主機提供商不能提供伸縮性,不能控制硬件或使用良好的網絡協議
3,YouTube改爲使用colocation arrangement。現在YouTube可以自定義所有東西並且協定自己的契約
4,使用5到6個數據中心加CDN
5,視頻來自任意的數據中心,不是最近的匹配或其他什麼。如果一個視頻足夠流行則移到CDN
6,依賴於視頻帶寬而不是真正的延遲。可以來自任何colo
7,圖片延遲很嚴重,特別是當一個頁面有60張圖片時
8,使用BigTable將圖片備份到不同的數據中心,代碼查看誰是最近的

學到的東西
1,Stall for time。創造性和風險性的技巧讓你在短期內解決問題而同時你會發現長期的解決方案
2,Proioritize。找出你的服務中核心的東西並對你的資源分出優先級別
3,Pick your battles。別怕將你的核心服務分出去。YouTube使用CDN來分佈它們最流行的內容。創建自己的網絡將花費太多時間和太多money
4,Keep it simple!簡單允許你更快的重新架構來回應問題
5,Shard。Sharding幫助隔離存儲,CPU,內存和IO,不僅僅是獲得更多的寫性能
6,Constant iteration on bottlenecks:
-軟件:DB,緩存
-OS:硬盤I/O
-硬件:內存,RAID
7,You succeed as a team。擁有一個跨越條律的瞭解整個系統並知道系統內部是什麼樣的團隊,如安裝打印機,安裝機器,安裝網絡等等的人。With a good team all things are possible。

http://hideto.javaeye.com/blog/130815

Google架構學習

關鍵字: Google

原文:Google Architecture

Google是伸縮性的王者。Google一直的目標就是構建高性能高伸縮性的基礎組織來支持它們的產品。

平臺
Linux
大量語言:Python,Java,C++

狀態
在2006年大約有450,000臺廉價服務器
在2005年Google索引了80億Web頁面,現在沒有人知道數目
目前在Google有超過200個GFS集羣。一個集羣可以有1000或者甚至5000臺機器。成千上萬的機器從運行着5000000000000000字節存儲的GFS集羣獲取數據,集羣總的讀寫吞吐量可以達到每秒40兆字節
目前在Google有6000個MapReduce程序,而且每個月都寫成百個新程序
BigTable伸縮存儲幾十億的URL,幾百千千兆的衛星圖片和幾億用戶的參數選擇

堆棧
Google形象化它們的基礎組織爲三層架構:
1,產品:搜索,廣告,email,地圖,視頻,聊天,博客
2,分佈式系統基礎組織:GFS,MapReduce和BigTable
3,計算平臺:一羣不同的數據中心裏的機器
4,確保公司裏的人們部署起來開銷很小
5,花費更多的錢在避免丟失日誌數據的硬件上,其他類型的數據則花費較少

可信賴的存儲機制GFS(Google File System)
1,可信賴的伸縮性存儲是任何程序的核心需求。GFS就是Google的核心存儲平臺
2,Google File System - 大型分佈式結構化日誌文件系統,Google在裏面扔了大量的數據
3,爲什麼構建GFS而不是利用已有的東西?因爲可以自己控制一切並且這個平臺與別的不一樣,Google需要:
-跨數據中心的高可靠性
-成千上萬的網絡節點的伸縮性
-大讀寫帶寬的需求
-支持大塊的數據,可能爲上千兆字節
-高效的跨節點操作分發來減少瓶頸
4,系統有Master和Chunk服務器
-Master服務器在不同的數據文件裏保持元數據。數據以64MB爲單位存儲在文件系統中。客戶端與Master服務器交流來在文件上做元數據操作並且找到包含用戶需要數據的那些Chunk服務器
-Chunk服務器在硬盤上存儲實際數據。每個Chunk服務器跨越3個不同的Chunk服務器備份以創建冗餘來避免服務器崩潰。一旦被Master服務器指明,客戶端程序就會直接從Chunk服務器讀取文件
6,一個上線的新程序可以使用已有的GFS集羣或者可以製作自己的GFS集羣
7,關鍵點在於有足夠的基礎組織來讓人們對自己的程序有所選擇,GFS可以調整來適應個別程序的需求

使用MapReduce來處理數據
1,現在你已經有了一個很好的存儲系統,你該怎樣處理如此多的數據呢?比如你有許多TB的數據存儲在1000臺機器上。數據庫不能伸縮或者伸縮到這種級別花費極大,這就是MapReduce出現的原因
2,MapReduce是一個處理和生成大量數據集的編程模型和相關實現。用戶指定一個map方法來處理一個鍵/值對來生成一箇中間的鍵/值對, 還有一個reduce方法來合併所有關聯到同樣的中間鍵的中間值。許多真實世界的任務都可以使用這種模型來表現。以這種風格來寫的程序會自動並行的在一個 大量機器的集羣裏運行。運行時系統照顧輸入數據劃分、程序在機器集之間執行的調度、機器失敗處理和必需的內部機器交流等細節。這允許程序員沒有多少並行和 分佈式系統的經驗就可以很容易使用一個大型分佈式系統資源
3,爲什麼使用MapReduce?
-跨越大量機器分割任務的好方式
-處理機器失敗
-可以與不同類型的程序工作,例如搜索和廣告。幾乎任何程序都有map和reduce類型的操作。你可以預先計算有用的數據、查詢字數統計、對TB的數據排序等等
4,MapReduce系統有三種不同類型的服務器
-Master服務器分配用戶任務到Map和Reduce服務器。它也跟蹤任務的狀態
-Map服務器接收用戶輸入並在其基礎上處理map操作。結果寫入中間文件
-Reduce服務器接收Map服務器產生的中間文件並在其基礎上處理reduce操作
5,例如,你想在所有Web頁面裏的字數。你將存儲在GFS裏的所有頁面拋入MapReduce。這將在成千上萬臺機器上同時進行並且所有的調整、工作調度、失敗處理和數據傳輸將自動完成
-步驟類似於:GFS -> Map -> Shuffle -> Reduction -> Store Results back into GFS
-在MapReduce裏一個map操作將一些數據映射到另一箇中,產生一個鍵值對,在我們的例子裏就是字和字數
-Shuffling操作聚集鍵類型
-Reduction操作計算所有鍵值對的綜合併產生最終的結果
6,Google索引操作管道有大約20個不同的map和reduction。
7,程序可以非常小,如20到50行代碼
8,一個問題是掉隊者。掉隊者是一個比其他程序慢的計算,它阻塞了其他程序。掉隊者可能因爲緩慢的IO或者臨時的CPU不能使用而發生。解決方案是運行多個同樣的計算並且當一個完成後殺死所有其他的
9,數據在Map和Reduce服務器之間傳輸時被壓縮了。這可以節省帶寬和I/O。

在BigTable裏存儲結構化數據
1,BigTable是一個大伸縮性、錯誤容忍、自管理的系統,它包含千千兆的內存和1000000000000000的存儲。它可以每秒鐘處理百萬的讀寫
2,BigTable是一個構建於GFS之上的分佈式哈希機制。它不是關係型數據庫。它不支持join或者SQL類型查詢
3,它提供查詢機制來通過鍵訪問結構化數據。GFS存儲存儲不透明的數據而許多程序需求有結構化數據
4,商業數據庫不能達到這種級別的伸縮性並且不能在成千上萬臺機器上工作
5,通過控制它們自己的低級存儲系統Google得到更多的控制權來改進它們的系統。例如,如果它們想讓跨數據中心的操作更簡單這個特性,它們可以內建它
6,系統運行時機器可以自由的增刪而整個系統保持工作
7,每個數據條目存儲在一個格子裏,它可以通過一個行key和列key或者時間戳來訪問
8,每一行存儲在一個或多個tablet中。一個tablet是一個64KB塊的數據序列並且格式爲SSTable
9,BigTable有三種類型的服務器:
-Master服務器分配tablet服務器,它跟蹤tablet在哪裏並且如果需要則重新分配任務
-Tablet服務器爲tablet處理讀寫請求。當tablet超過大小限制(通常是100MB-200MB)時它們拆開tablet。當一個Tablet服務器失敗時,則100個Tablet服務器各自挑選一個新的tablet然後系統恢復。
-Lock服務器形成一個分佈式鎖服務。像打開一個tablet來寫、Master調整和訪問控制檢查等都需要互斥
10,一個locality組可以用來在物理上將相關的數據存儲在一起來得到更好的locality選擇
11,tablet儘可能的緩存在RAM裏

硬件
1,當你有很多機器時你怎樣組織它們來使得使用和花費有效?
2,使用非常廉價的硬件
3,A 1,000-fold computer power increase can be had for a 33 times lower cost if you you use a failure-prone infrastructure rather than an infrastructure built on highly reliable components. You must build reliability on top of unreliability for this strategy to work.
4,Linux,in-house rack design,PC主板,低端存儲
5,Price per wattage on performance basis isn't getting better. Have huge power and cooling issues
6,使用一些collocation和Google自己的數據中心

其他
1,迅速更改而不是等待QA
2,庫是構建程序的卓越方式
3,一些程序作爲服務提供
4,一個基礎組織處理程序的版本,這樣它們可以發佈而不用害怕會破壞什麼東西

Google將來的方向
1,支持地理位置分佈的集羣
2,爲所有數據創建一個單獨的全局名字空間。當前的數據由集羣分離
3,更多和更好的自動化數據遷移和計算
4,解決當使用網絡劃分來做廣闊區域的備份時的一致性問題(例如保持服務即使一個集羣離線維護或由於一些損耗問題)

學到的東西
1,基礎組織是有競爭性的優勢。特別是對Google而言。Google可以很快很廉價的推出新服務,並且伸縮性其他人很難達到。許多公司採取完全不同的方式。許多公司認爲基礎組織開銷太大。Google認爲自己是一個系統工程公司,這是一個新的看待軟件構建的方式
2,跨越多個數據中心仍然是一個未解決的問題。大部分網站都是一個或者最多兩個數據中心。我們不得不承認怎樣在一些數據中心之間完整的分佈網站是很需要技巧的
3,如果你自己沒有時間從零開始重新構建所有這些基礎組織你可以看看Hadoop。Hadoop是這裏很多同樣的主意的一個開源實現
4,平臺的一個優點是初級開發人員可以在平臺的基礎上快速並且放心的創建健全的程序。如果每個項目都需要發明同樣的分佈式基礎組織的輪子,那麼你將陷入困境因爲知道怎樣完成這項工作的人相對較少
5,協同工作不一直是擲骰子。通過讓系統中的所有部分一起工作則一個部分的改進將幫助所有的部分。改進文件系統則每個人從中受益而且是透明的。如果每個項目使用不同的文件系統則在整個堆棧中享受不到持續增加的改進
6,構建自管理系統讓你沒必要讓系統關機。這允許你更容易在服務器之間平衡資源、動態添加更大的容量、讓機器離線和優雅的處理升級
7,創建可進化的基礎組織,並行的執行消耗時間的操作並採取較好的方案
8,不要忽略學院。學院有許多沒有轉變爲產品的好主意。Most of what Google has done has prior art, just not prior large scale deployment.
9,考慮壓縮。當你有許多CPU而IO有限時壓縮是一個好的選擇。



http://blog.daviesliu.net/2006/09/09/010620/

Lighttpd+Squid+Apache搭建高效率Web服務器

架構原理

Apache通常是開源界的首選Web服務器,因爲它的強大和可靠,已經具有了品牌效應,可以適用於絕大部分的應用場合。但是它的強大有時候卻顯 得笨重,配置文件得讓人望而生畏,高併發情況下效率不太高。而輕量級的Web服務器Lighttpd卻是後起之秀,其靜態文件的響應能力遠高於 Apache,據說是Apache的2-3倍。Lighttpd的高性能和易用性,足以打動我們,在它能夠勝任的領域,儘量用它。Lighttpd對 PHP的支持也很好,還可以通過Fastcgi方式支持其他的語言,比如Python。

畢竟Lighttpd是輕量級的服務器,功能上不能跟Apache比,某些應用無法勝任。比如Lighttpd還不支持緩存,而現在的絕大部分站 點都是用程序生成動態內容,沒有緩存的話即使程序的效率再高也很難滿足大訪問量的需求,而且讓程序不停的去做同一件事情也實在沒有意義。首先,Web程序 是需要做緩存處理的,即把反覆使用的數據做緩存。即使這樣也還不夠,單單是啓動Web處理程序的代價就不少,緩存最後生成的靜態頁面是必不可少的。而做這 個是 Squid的強項,它本是做代理的,支持高效的緩存,可以用來給站點做反向代理加速。把Squid放在Apache或者Lighttpd的前端來緩存 Web服務器生成的動態內容,而Web應用程序只需要適當地設置頁面實效時間即可。

即使是大部分內容動態生成的網站,仍免不了會有一些靜態元素,比如圖片、JS腳本、CSS等等,將Squid放在Apache或者Lighttp 前端後,反而會使性能下降,畢竟處理HTTP請求是Web服務器的強項。而且已經存在於文件系統中的靜態內容再在Squid中緩存一下,浪費內存和硬盤空 間。因此可以考慮將Lighttpd再放在Squid的前面,構成 Lighttpd+Squid+Apache的一條處理鏈,Lighttpd在最前面,專門用來處理靜態內容的請求,把動態內容請求通過proxy模塊轉 發給Squid,如果Squid中有該請求的內容且沒有過期,則直接返回給Lighttpd。新請求或者過期的頁面請求交由Apache中Web程序來處 理。經過Lighttpd和Squid的兩級過濾,Apache需要處理的請求將大大減少,減少了Web應用程序的壓力。同時這樣的構架,便於把不同的處 理分散到多臺計算機上進行,由Lighttpd在前面統一把關。

在這種架構下,每一級都是可以進行單獨優化的,比如Lighttpd可以採用異步IO方式,Squid可以啓用內存來緩存,Apache可以啓用MPM 等,並且每一級都可以使用多臺機器來均衡負載,伸縮性很好。
2009 - 10 - 31

Java基礎學習筆記

文章分類:Java編程
1.Java語言的特點:面向對象,跨平臺,多線程

2.Java運行環境:JVM+Java API

3.數據類型:
boolean 1
char 16
byte 8
short 16
int 32
long 64
float 32
double 64

4.面向對象:
封裝:類 
繼承:單一繼承 
多態:重寫(Overridding)與重載(Overloading)
在子類中,方法的參數個數和返回值都與父類相同,稱爲重寫
在同一個類中,方法的參數不同,稱爲重載

5.作用域:
private 子類不能繼承
default 如果不在同一包中,子類不能繼承
protected
public
       
6.垃圾回收原理:有向圖原則(另一種爲計數器類型),可能會有內存泄漏,計數器類型與有向圖類型相比:效率更高,但是精度偏低,因爲它很難發現變量循環引用的問題
會有內存泄漏的代碼:
Vector v=new Vector(10)
for (int i=0;i<10;i++){
    Object o=new Object();
    v.add(o);
    o=null;
}
解決方法:
v=null;

7.棧與堆:原始數據類型存放在棧裏,對象數據類型存放在堆中,棧中存放堆中的地址。

8.變量比較:==比較的是棧,原始數據類型相同,但是引用類型值不等,equals比較的是堆,特例是string,java.lang.String類是final類型的,因此不可以繼承這個類、不能修改這個類。

9.變量複製:原始數據類型複製的是值,引用數據類型複製的是棧中的引用,所以當一個修改的時候,會影響另一個。對象複製:Object.clone()方法

10.引用傳遞和值傳遞:原始數據類型傳遞的是值,引用數據類型傳遞的是棧中的引用

11.異常:(Java.lang.Exception)檢查時異常,(Java.lang.RuntimeException)運行時異常,((java.lang.Error)錯誤,檢查時異常必須處理

12.集合:collection:    set:HashSet TreeSet
                       list:ArrayList LinkedList Vector Stack
        map:HashMap TreeMap HashTable Properties

13.Set裏的元素是不能重複的,什麼方法來區分重複與否呢? 是用==還是
equals()? 它們有何區別?
  Set裏的元素是不能重複的,那麼用iterator()方法來區分重複與否。equals()是判讀兩
個Set是否相等。
   equals()和==方法決定引用值是否指向同一對象equals()在類中被覆蓋,爲的是當兩個
分離的對象的內容和類型相配的話,返回真值

14.ArrayList, Vector, LinkedList的存儲性能和特性
  ArrayList和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據
以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數組元
素移動等內存操作,所以索引數據快而插入數據慢,Vector由於使用了synchronized方
法(線程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實現存儲,按序
號索引數據需要進行前向或後向遍歷,但是插入數據時只需要記錄本項的前後項即
可,所以插入速度較快。

15、HashMap和Hashtable的區別。
   HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,
主要區別在於HashMap允許空(null)鍵值(key),由於非線程安全,效率上可能高於
Hashtable。
HashMap允許將null作爲一個entry的key或者value,而Hashtable不允許。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因爲
contains方法容易讓人引起誤解。
Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問
Hashtable時,不需要自己爲它的方法實現同步,而HashMap 就必須爲之提供外同步。
Hashtable和HashMap採用的hash/rehash算法都大概一樣,所以性能不會有很大的差異。
定時執行任務的三種方法:

1)java.util.Timer.

2)ServletContextListener.

3)org.springframework.scheduling.timer.ScheduledTimerTask

1)java.util.Timer
這個方法應該是最常用的,不過這個方法需要手工啓動你的任務:
        Timer timer=new Timer();
        timer.schedule(new ListByDayTimerTask(),10000,86400000);
這裏的ListByDayTimerTask類必須extends TimerTask裏面的run()方法。

2)ServletContextListener
這個方法在web容器環境比較方便,這樣,在web server啓動後就可以自動運行該任務,不需要手工操作。
將ListByDayListener implements ServletContextListener接口,在contextInitialized方法中加入啓動Timer的代碼,在 contextDestroyed方法中加入cancel該Timer的代碼;然後在web.xml中,加入listener:
<-listener>
<-listener-class>com.qq.customer.ListByDayListener</listener-class>
<-/listener>

3)org.springframework.scheduling.timer.ScheduledTimerTask如果你用spring,那麼你不需要寫Timer類了,在schedulingContext-timer.xml中加入下面的內容就可以了:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="timer" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref local="MyTimeTask1"/>
</list>
</property>
</bean>

<bean id="MyTimeTask" class="com.qq.timer.ListByDayTimerTask"/>

<bean id="MyTimeTask1" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask">
<ref bean="MyTimeTask"/>
</property>
<property name="delay">
<value>10000</value>
</property>
<property name="period">
<value>86400000</value>
</property>
</bean>
</beans>

以上內容轉載自:http://dev.csdn.net/author/xtpdcsse/ec8e8080a5b04fa79e7d4828bc807d3f.html

下面是我的實現。

1)利用java.util.Timer. 代碼如下

<1>StartThread.java

package com.jview.main;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.Logger;
public class StartThread extends Thread {
private static Logger logger = Logger.getLogger("StartThread");
public static final int EXECUTE_CYC = 86400000; //24*60*60*1000毫秒
int startH = 9;
int startM = 52;
private Timer _timer ;
private Date _statDate;
private Date _nowDate;
public StartThread(){
_nowDate = new Date();
_timer = new Timer();
_statDate = new Date(_nowDate.getYear(),_nowDate.getMonth(),_nowDate.getDate(),startH,startM);
}
public void StartUp(){
_timer.schedule(
new TimerTask() {
public void run()
{
logger.info("開始統計...");
try {
Class.forName("com.jview.stat.StatPlan").newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},_statDate,EXECUTE_CYC);
}
public static void main(String[] args) {
StartThread _statUp = new StartThread();
_statUp.StartUp();
}
}

<2>StatPlan.java
package com.jview.stat;
import java.util.Calendar;
import org.apache.log4j.Logger;
public class StatPlan {


private static Logger logger = Logger.getLogger("StatPlan");
private int i = 0;
private StatPlanService _sps ;
public StatPlan(){
_sps = new StatWeekPlan();
statPlan();
}

public void statPlan(){
Calendar _c = Calendar.getInstance();
logger.info("stat plan ... 執行"+ i +"次,時間:"+_c.getTime());
_sps.StatPlan();
i++;
for(int i = 0; i<9999;i++){
if(i==0 || i== 9998){
logger.info(""+i);
}
}
}
}

<3>StatWeekPlan .java
import org.apache.log4j.Logger;

public class StatWeekPlan extends StatPlanService {
private static Logger logger = Logger.getLogger("StatWeekPlan");
public void StatPlan(){
logger.info("this is statWeekPlan");
}
}
<4>StatPlanService .java
public class StatPlanService {
public void StatPlan(){
}
}

2)ServletContextListener.實現
<1> SysStatListener .java
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.Logger;
public class SysStatListener implements ServletContextListener{
private static Logger logger = Logger.getLogger("ListByDayListener");
private StatTask _sTask;
public void contextDestroyed(ServletContextEvent scevent) {
String status = "停止系統統計線程";
scevent.getServletContext().log(status);
logger.info(status);
_sTask.shutDown();
}
public void contextInitialized(ServletContextEvent scevent) {
String status = "啓動系統統計線程";
scevent.getServletContext().log(status);
logger.info(status);
_sTask = new StatTask();
_sTask.startUp();
}
}

<2> StatTask .java
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.Logger;
public class StatTask extends Thread {
private static Logger logger = Logger.getLogger("StartThread");
public static final int EXECUTE_CYC = 86400000;
int startH = 9;
int startM = 52;
private Timer _timer ;
private Date _statDate;
private Date _nowDate;
public StatTask(){
_nowDate = new Date();
_timer = new Timer();
_statDate = new Date(_nowDate.getYear(),_nowDate.getMonth(),_nowDate.getDate(),startH,startM);
}
public void startUp(){
_timer.schedule(
new TimerTask() {
public void run()
{
logger.info("開始統計...");
try {
Class.forName("com.jview.stat.StatPlan").newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},_statDate,EXECUTE_CYC);
}
public void shutDown(){
_timer.cancel();
}

<3>在web.xml中添加下面的內容(注:下面的內容放到<filter-mapping>的後面)
<listener>
      <listener-class>com.jview.auto.stat.SysStatListener </listener-class>
  </listener>

這篇文章是由José M. Aguilar在他卓越的博客中以西班牙語的形式首發,其後Timm Martin在獲得Aguilar先生的授權下,對該文章進行翻譯、修改,並且在DevTopics上發佈。

以下13個小技巧可以使得你的代碼在長時間內依然能夠保持容易理解和維護。

1. 對不同級別的代碼進行註釋

對於不同級別的代碼塊,要使用統一的方法來進行註釋。例如:

對於每一個類,需要包含一段簡明扼要的描述,作者和上一次修改的時間
對於每一個方法,需要包含這個方法的用途,功能,參數以及返回結果
當你在一個團隊裏面的時候,採用一套註釋的標準是非常重要的。當然,使用一種大家都認可的註釋約定和工具(例如C#的XML註釋和Java的Javadoc)在一定程度上能推動這項任務。

2. 使用段落註釋

首先把代碼塊分解成多個“段落”,每一個段落都執行單一的任務;然後在每一個“段落”開始之前添加註釋,告訴閱讀代碼的人接下來的這段代碼是幹什麼用的

// 檢查所有記錄都是正確的
foreach (Record record in records)
{
     if (rec.checkStatus()==Status.OK)
     {
         . . .
     }
}
// 現在開始進行處理
Context ctx = new ApplicationContext();
ctx.BeginTransaction();
. . .
3. 對齊註釋行

對於那些在行末寫有註釋的代碼,應該對齊註釋行來使得方便閱讀

const MAX_ITEMS = 10; // maximum number of packets
const MASK = 0x1F;    // mask bit TCP

有些開發人員使用tab來對齊註釋,而另外一些人會用空格來對齊。由於tab在不同的編輯器和集成開發環境中會有所不同,所以最佳的方法是使用空格來對齊註釋行。

4. 不要侮辱閱讀者的智慧

要避免沒用的註釋,例如

if (a == 5)        //如果a等於5
counter = 0    //把counte設爲0

這不單把時間浪費在寫沒用的註釋上面,同時也在分散讀者的注意力。

5. 要有禮貌

應當避免沒有禮貌的註釋,例如“要注意一些愚蠢的用戶會輸入一個負數”,或者“修正由菜鳥工程師寫的愚蠢得可憐的代碼而導致的副作用”。這樣的注 釋對於代碼的寫註釋的人來說並沒有任何好處,同時你永遠都不會知道將來這些註釋會被誰來閱讀,你的老闆,一個客戶或者是剛纔被你數落的愚蠢得可憐的工程 師。

6. 直截了當

不要在註釋裏面寫過多的廢話。避免在註釋裏面賣弄ASCII藝術,寫笑話,作詩和過於冗長。簡而言之就是保持註釋的簡單和直接。

7. 使用統一的風格

有些人覺得註釋應該讓非程序員也能看懂。另外一些人覺得註釋需要面對的讀者只是程序員。無論如何,正如Successful Strategies for Commenting Code中所說的,最重要的是註釋的風格需要統一,並且總是面向相同的讀者。就自己而論,我懷疑非程序員是否會去讀代碼,所以我覺得註釋應該面向程序員來 寫。

8. 在內部使用特殊的標籤

當你在一個團隊裏工作的時候,採用一組一致的標籤能幫助不同的程序員溝通。例如,很多團隊會採用“TODO”標籤來表示一段尚未完成的代碼

int Estimate(int x, int y)
{
     // TODO: implement the calculations
     return 0;
}

標籤註釋並不會解釋代碼,它們尋求注意或者是傳遞信息。但是如果適當地使用這種技術,要記住跟進這段代碼並且完成該標籤傳遞的任務。

9. 在寫代碼的同時添加註釋

當你在寫代碼而且記憶猶新的同時就添加註釋。如果等到項目後期才添加註釋,會讓你事倍功半。“我沒有時間寫註釋”,“我的時間很緊迫”和“項目已經延遲了”,這些都是不寫註釋的常見藉口。有些工程師覺最佳的解決方法是“註釋先行”。例如:

public void ProcessOrder()
{
    // Make sure the products are available
    // Check that the customer is valid
    // Send the order to the store
    // Generate bill
}

10. 把自己想象爲註釋的讀者(事實上就是如此)

當你正在給代碼寫註釋的時候,不僅僅爲日後維護你的代碼的開發者考慮,同時也設想一下如果自己就是註釋的讀者。Phil Haack曾經說過:

“一旦一行代碼被敲到文件中, 你就已經要開始維護那一行代碼了。”

所以,我們自己就是好(或者壞)註釋的第一個受益者(或者受害者)。

11. 更新代碼的時候要更新註釋

如果註釋沒有隨着代碼的修改而更新,那麼這些註釋將是毫無意義的。代碼和註釋需要同步,否則註釋只會讓維護代碼的開發者更加痛苦。需要特別注意的是,一些重構的工具會自動更新代碼,但是卻沒有自動更新註釋,那麼註釋就自然而然地過期作廢了。

12. 良好可讀性代碼是註釋的金科玉律

對於很多開發者來說,一個基本的原則就是:讓代碼自己描述自己。雖然有人懷疑這是由不喜歡寫註釋的程序員所倡導的一場運動,但是無需解釋的代碼有 很大的好處,這些代碼更加容易理解甚至讓註釋變得沒有必要。例如,在我的文章Fluid Interfaces中就給大家展示了什麼是清晰的無需解釋的代碼。

Calculator calc = new Calculator();
calc.Set(0);
calc.Add(10);
calc.Multiply(2);
calc.Subtract(4);
Console.WriteLine( “Result: {0}”, calc.Get() );

在這個例子裏面,註釋就像是違反了第4條技巧那樣,變得毫無必要。要寫出可讀性好的代碼,你需要使用適當的命名方式(在經典的 Ottinger’s Rules中有闡述),保證恰當的縮進,並且採用編碼風格指導。如果代碼不遵守這條技巧,那麼註釋看起來就好像是爲自己不好的代碼的寫道歉信一樣。

13. 跟你的同事分享這些技巧

雖然從第10條技巧中我們已經知道了自己就是好註釋的得益者,但是這些技巧對於所有的開發者來說都是很有幫助的,尤其是整個團隊都有相同共識的情況下。因此,大方地跟你的同事去分享這些技巧,讓我們寫出更加容易理解和維護的代碼。
今天試着用了一下log4j來處理java中的日誌,感覺良好,順便記錄一下log4j的配置文件log4j.properties各語句的含義。

這是一個數據庫配置文件

#這是一個配置文件實例,PropertyConfigurator將使用這個文件 :
#聲明一個appender變量名爲JDBC
log4j.rootLogger=DEBUG, JDBC

#JDBC是一個JDBCAppender類,這個類可以寫消息到數據庫
log4j.appender.JDBC=com.benqguru.palau.log.jdbc.test.JDBCAppender

#1.連接數據庫的數據庫選項
log4j.appender.JDBC.url=jdbc:mysql://localhost:3306/logtest
log4j.appender.JDBC.username=root
log4j.appender.JDBC.password=

#2.指定你自己的JDBCConnectionHandler的連接器選項
log4j.appender.JDBC.connection_class=com.benqguru.palau.log.jdbc.test.MyConnectionHandler

#3.指定一個靜態的SQL語句的SQL選項,這個語句將在每次消息事件發生時被執行
log4j.appender.JDBC.sql=INSERT INTO LOGTEST (id, msg, created_on, created_by) VALUES (1, @MSG@, sysdate, 'me')

#4. 指定數據庫中一個表的表選項。
log4j.appender.JDBC.table=logtest

#5.描述表的重要列的列選項(非空列是必須被描述的)
log4j.appender.JDBC.columns=id_seq~EMPTY id~ID~MyIDHandler msg~MSG created_on~TIMESTAMP created_by~STATIC~Thomas Fenner

#6.定義消息佈局器的佈局器選項(可選)
log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
log4j.appender.JDBC.layout.ConversionPattern=%m

#7.定義消息事件緩衝器的大小的緩衝器選項(可選)
log4j.appender.JDBC.buffer_size=1

#8.定義自動提交的提交選項(可選)
log4j.appender.JDBC.docommit=N

##########下面是英文說明#############
#Date - %d{DATE}[slf5s.DATE]
#Priority - %p[slf5s.PRIORITY]
#NDC - %x[slf5s.NDC]
#Thread - %t[slf5s.THREAD]
#Category - %c[slf5s.CATEGORY]
#Location - %l[slf5s.LOCATION]
#Message - %m[slf5s.MESSAGE]
#
#log4j.appender.R.layout.ConversionPattern=[slf5s.start]%d{DATE}[slf5s.DATE]%n/
#   %p[slf5s.PRIORITY]%n%x[slf5s.NDC]%n%t[slf5s.THREAD]%n/
#   %c[slf5s.CATEGORY]%n%l[slf5s.LOCATION]%n%m[slf5s.MESSAGE]%n%n
##########下面是中文說明#############
#%m 輸出代碼中指定的消息
#%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL
#%r 輸出自應用啓動到輸出該log信息耗費的毫秒數
#%c 輸出所屬的類目,通常就是所在類的全名
#%t 輸出產生該日誌事件的線程名
#%n 輸出一個回車換行符,Windows平臺爲“/r/n”,Unix平臺爲“/n”
#%d 輸出日誌時間點的日期或時間,默認格式爲ISO8601,也可以在其後指定格式,
#比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
#%l 輸出日誌事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。舉例:Testlog4.main(TestLog4.java:10)


這是一個普通的配置文件

#log4j會解析這個文件
log4j.debug=false
#暫時還不清楚這兩個屬性的作用
log4j.disableOverride=true
log4j.disable=INFO
#設置記錄所有類的日誌的優先級別
log4j.rootLogger=DEBUG,dest1,dest2
#設置這個包記錄日誌爲假的話
#dist1,dist2就不會記錄com.benqguru.commons.logging.test.LoggingSample的日誌,只有dist3會記錄.
#反之,會記錄,這樣就會重複記錄
log4j.additivity.com.benqguru.commons.logging.test.LoggingSample=false
#特別指定某個特殊包的日誌級別和目標設備
log4j.category.com.benqguru.commons.logging.test.LoggingSample=WARN, dest3
#這個目標設備用來debug
log4j.appender.dest1=org.apache.log4j.ConsoleAppender
#log4j.appender.dest1.layout=org.apache.log4j.SimpleLayout
log4j.appender.dest1.layout=org.apache.log4j.PatternLayout
#%-4r %-5p [%t] %37c %3x - %m%n
log4j.appender.dest1.layout.ConversionPattern=%d %p %c - <%m> (%F.%M:%L) %t%n

#這個目標設備用來trace
log4j.appender.dest2=org.apache.log4j.RollingFileAppender
#該文件記錄日誌的級別(INFO以下的級別不記錄)
log4j.appender.dest2.Threshold=INFO
#文件保存路徑
log4j.appender.dest2.File=c:/log4jlog.htm
#是否往文件追加信息
log4j.appender.dest2.Append=true
#設置文件最大值
log4j.appender.dest2.MaxFileSize=5KB
#設置備份文件的最大數量
log4j.appender.dest2.MaxBackupIndex=10
#使用一個html格式來記錄日誌
log4j.appender.dest2.layout=org.apache.log4j.HTMLLayout
#是否打印該消息的代碼行
log4j.appender.dest2.layout.LocationInfo=true
#設置該日誌的html的標題
log4j.appender.dest2.layout.Title=My app title

#這個目標設備用來trace指定類或包
log4j.appender.dest3=org.apache.log4j.DailyRollingFileAppender
#log4j.appender.dest3.Threshold=DEBUG
log4j.appender.dest3.File=c:/SpecPackageLog.htm
log4j.appender.dest3.Append=false
log4j.appender.dest3.layout=org.apache.log4j.HTMLLayout
log4j.appender.dest3.layout.LocationInfo=true
log4j.appender.dest3.layout.Title=My app title

在Sun的API中對在對 “最大匹配Greedy”“最小匹配Reluctant”“完全匹配Possessive”的描述,不能讓我明白他們有什麼區別,現在將我對這三種匹配模式的理解寫出來,供大家參考。


1、Greediness(貪心)匹配:

X?、X*、X+、X{n,}都是最大匹配。例如你要用“<.+>”去匹配“a<tr>aava </tr>abb”,也許你所期待的結果是想匹配“<tr>”,但是實際結果卻會匹配到“<tr>aava </tr>”。這是爲什麼呢?下面我們跟蹤下最大匹配的匹配過程。

①“<”匹配字符串的“<”。②“.+”匹配字符串的“tr>aava </tr>ab”,在進行最大匹配時,它把兩個“>”都匹配了,它匹配了所有字符,直到文本的最後字符“b” ③這時,發現不能成功匹配“>”,開始按原路回退,用“a”與“>”匹配,直到“ab”前面的“>”匹配成功。


2、Reluctant(Laziness)最小匹配

     X?、X*、X+、X{n,}都是最大匹配。好,加個?就成了Laziness匹配。例如X??、X*?、X+?、X{n,}?都是最小匹配,其實X{n,m}?和X{n }?有些多餘。

最小匹配意味者,.+? 匹配一個字符後,馬上試一試>的匹配可能,失敗了,則.+? 再匹配一個字符,再馬上試一試>的匹配可能。JDK文檔中Greedy 和 Reluctant,它是以eat一口來隱喻的,所以翻譯成貪喫和(勉強的)厭食最貼切了。不過我喜歡最大匹配、最小匹配的說法。


3、Possessive完全匹配

與最大匹配不同,還有一種匹配形式:X?+、X*+、X++、X{n,}+等,成爲完全匹配。它和最大匹配一樣,一直匹配所有的字符,直到文本的最後,但它不由原路返回。也就是說,一口匹配,搞不定就算了,到也乾脆,偶喜歡。

Use a possessive quantifier for situations where you want to seize all of something without ever backing off; it will outperform the equivalent greedy quantifier in cases where the match is not immediately found.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegularExpression {

public static void main(String[] args) {
// 簡單認識正則表達式的概念

// p("abc".matches("..."));
// p("a8729a".replaceAll("//d", "-"));
// Pattern p = Pattern.compile("[a-z]{3}");
// Matcher m = p.matcher("fgh");
// p(m.matches());
// p("aaas".matches("[a-z]{3,}"));

// 初步認識. * + ?

// p("a".matches("."));
// p("aa".matches("aa"));
// p("aaaa".matches("a*"));
// p("aaaa".matches("a+"));
// p("".matches("a*"));
// p("aaaa".matches("a?"));
// p("".matches("a?"));
// p("a".matches("a?"));
// p("214523145234532".matches("//d{3,100}"));
// p("192.168.0.231".matches("//d{1,3}//.//d{1,3}//.//d{1,3}//.//d{1,3}"));
// p("192".matches("[0-2][0-9][0-9]"));

// 範圍

// p("a".matches("[abc]"));
// p("a".matches("[^abc]"));
// p("A".matches("[a-zA-Z]"));
// p("a".matches("[a-z]|[A-Z]"));
// p("A".matches("[a-z[A-Z]]"));
// p("R".matches("[A-Z&&[RFG]]"));

// 認識/s /w /d /

// p(" /n/r/t".matches("//s{4}"));
// p(" ".matches("//S"));
// p("a_8".matches("//w{3}"));
// p("abc888&^%".matches("[a-z]{1,3}//d+[&^#%]+"));
// p("//".matches("////"));

// POSIX Style

// p("a".matches("//p{Lower}"));

// boundary

// p("hello sir".matches("^h.*"));
// p("hello sir".matches(".*ir$"));
// p("hello sir".matches("^h[a-z]{1,3}o//b.*"));
// p("hellosir".matches("^h[a-z]{1,3}o//b.*")); // whilte lines
// p("/n".matches("^[//s&&[^//n
// p("aaa 8888c".matches(".*//d{4}."));
// p("aaa8888c".matches(".*//b//d{4}."));
// p("aaa8888c".matches(".*//d{4}."));
// p("aaa 8888c".matches(".*//b//d{4}."));

// email

// p("[email protected]".matches("[//w[.-]]+@[//w[.-]]+//.[//w]+"));

// matches find lookingAt

// Pattern p = Pattern.compile("//d{3,5}");
// String s = "123-34345-234-00";
// Matcher m = p.matcher(s);
// p(m.matches());
// m.reset();
// p(m.find());
// p(m.start() + "-" + m.end());
// p(m.find());
// p(m.start() + "-" + m.end());
// p(m.find());
// p(m.start() + "-" + m.end());
// p(m.find());
// //p(m.start() + "-" + m.end());
// p(m.lookingAt());
// p(m.lookingAt());
// p(m.lookingAt());
// p(m.lookingAt());

// replacement

// Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
// Matcher m = p
// .matcher("java Java JAVa JaVa IloveJAVA you hateJava afasdfasdf");
// StringBuffer buf = new StringBuffer();
// int i = 0;
// while (m.find()) {
// i++;
// if (i % 2 == 0) {
// m.appendReplacement(buf, "java");
// } else {
// m.appendReplacement(buf, "JAVA");
// }
// }
// m.appendTail(buf);
// p(buf);

// group

// Pattern p = Pattern.compile("(//d{3,5})([a-z]{2})");
// String s = "123aa-34345bb-234cc-00";
// Matcher m = p.matcher(s);
// while (m.find()) {
// p(m.group());
// }

// qulifiers

// Pattern p = Pattern.compile(".{3,10}+[0-9]");
// String s = "aaaa5bbbb68";
// Matcher m = p.matcher(s);
// if (m.find())
// p(m.start() + "-" + m.end());
// else
// p("not match!");

// non-capturing groups

// Pattern p = Pattern.compile(".{3}(?=a)");
// String s = "444a66b";
// Matcher m = p.matcher(s);
// while (m.find()) {
// p(m.group());
// }

// back refenrences

// Pattern p = Pattern.compile("(//d(//d))//2");
// String s = "122";
// Matcher m = p.matcher(s);
// p(m.matches());

// flags的簡寫
Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
p("Java".matches("(?i)(java)"));
}

public static void p(Object o) {
System.out.println(o);
}

}
2009 - 02 - 06

Java snippets02

			if (Character.isLowerCase(ch[i])) {
char temp = Character.toUpperCase(ch[i]);
ch[i] = temp;
} else if (Character.isUpperCase(ch[i])) {
char temp = Character.toLowerCase(ch[i]);
ch[i] = temp;
}

			while (true) {
flag = 0;
result = tc.getNum();

input = Integer.parseInt(br.readLine());

while (flag == 0) {
if (input == result) {
System.out.println("very good!");
flag = 1;
} else {
flag = 0;
System.out.println("no,please try again.");
input = Integer.parseInt(br.readLine());
}
}
}

		L1: while (true) {
int question = new Times().question();
L2: while (true) {
int answer = scanner.nextInt();
if (answer == question) {
System.out.println("very good!");
continue L1;
} else {
System.out.println("no,please try again.");
continue L2;
}
}
}

char[] c1 = s1.toCharArray();

		Map<Integer, String> m = new HashMap<Integer, String>();
m.put(1, "one");
m.put(2, "two");
m.put(3, "three");
Object o[] = m.values().toArray();

GregorianCalendar ca = new GregorianCalendar();
System.out.println(ca.get(GregorianCalendar.AM_PM));

2009 - 02 - 06

Java snippets01

	for (int i = 0; i < number.length; i++) {
for (int j = 0; j < number.length - i - 1; j++) {
if (number[j] < number[j + 1]) {
int temp = number[j];
number[j] = number[j + 1];
number[j + 1] = temp;
}
}
}

BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
String str = buffer.readLine();

Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();


InputStreamReader in = null;
OutputStreamWriter out = null;
BufferedReader br = null;

in = new InputStreamReader(new FileInputStream(System
.getProperty("user.dir")
+ "//old.txt"), "UTF-8");
br = new BufferedReader(in);
out = new OutputStreamWriter(new FileOutputStream(
"C://WINDOWS//new.txt"), "UTF-8");

String[] temp;
temp = text.split("//s{1,}");// 按照空格分割字符串,多個空格作爲一個空格對字符串進行分割

String s = String.valueOf(1);
if (s.charAt(i) == '1'){}

System.nanoTime();

		SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
String date = sdt.format(System.currentTimeMillis());

DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
df.applyPattern("00");

		Calendar current_time = new GregorianCalendar();
Calendar target_time = new GregorianCalendar(2009, Calendar.MAY, 1);
long diffMillis = target_time.getTimeInMillis()
- current_time.getTimeInMillis();
long diffDays = diffMillis / (24 * 60 * 60 * 1000) + 1;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD");

System.out.println("距" + sdf.format(target_time.getTimeInMillis())
+ "還有:" + diffDays + "天");

Arrays.sort(array);

StringBuilder s1 = new StringBuilder(temp);
// StringBuffer s1 = new StringBuffer(temp);
System.out.println(s1.reverse());

我是個彩民,特別喜歡買雙色球。最近看了幾種算法,寫了一個很簡單的雙色球的算號器,分享給大家,僅供娛樂,呵呵
package com.tester.luckly;

import java.util.Random;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class DoubleBall {
private Set<Integer> hs;
private static boolean flag = true;

public enum oddOrEven {
Odd, Even
}

public enum aOrBOrC {
A, B, C
}

public static void main(String[] args) {
DoubleBall db = new DoubleBall();
System.out
.println("====================Red Balls============================");
String url1 = "http://map.zhcw.com/ssq//html/h7fenqu_ascstr=20.html";
System.out.println();
System.err.println(url1);
Scanner scanner1 = new Scanner(System.in);
System.out.println("Please select:1.Input your own two numbers");
System.out
.println(" 2.Input the range of the two numbers");
int select = scanner1.nextInt();
if (select == 1) {
flag = false;
} else {
flag = true;
}
System.out.println("Please input two numbers like this: 1 2");
scanner1.nextLine();
String[] str = scanner1.nextLine().split(" ");
Set<Integer> redBall = db.calcRedBall(Integer.parseInt(str[0]), Integer
.parseInt(str[1]));

System.out
.println("====================Blue Ball============================");
String url2 = "http://sports.sohu.com/s2007/0445/s252476794/";
System.out.println();
System.err.println(url2);
Scanner scanner2 = new Scanner(System.in);

System.out.println("1.Please select:" + oddOrEven.Odd + " or "
+ oddOrEven.Even);
String select1 = scanner2.nextLine();

System.out.println("2.Please select:" + aOrBOrC.A + " or " + aOrBOrC.B
+ " or " + aOrBOrC.C);
String select2 = scanner2.nextLine();

int blueBall = db.calcBlueBall(select1, select2);

System.out
.println("====================The Result============================");
System.out.println();
for (int i : redBall) {
System.err.print(i + " ");
}
System.err.println("| " + blueBall);
String url3 = "http://www.bwlc.net/dhtz/";
System.err.println(url3);
}

public Set<Integer> calcRedBall(int begin, int end) {
hs = new TreeSet<Integer>();

/*
* 固定恆碼:就是每期都必備的號碼,通常爲2-3個,如02,13,27。 這2-3個號碼長期備選(至少50期)。
*/
hs.add(10);
hs.add(27);

/*
* 邊緣撿“膽”:就是在邊緣碼“05、10、15、20、25、30”及“01、
* 06、11、16、21、26、31”共13個號碼中巧妙地撿出膽碼。之所以 把邊緣碼作爲“膽”碼的一種選取方法,是因爲從歷史中獎號碼來看,
* 幾乎每一期都會在具備這種特性的號碼中出現2-3個。
*/
int[] array = { 5, 15, 20, 25, 30, 01, 06, 11, 16, 21, 26, 31 };
for (int i = 0; i < 2; i++) {
Random random = new Random();
hs.add(array[random.nextInt(array.length)]);
}

/*
* 重碼追鄰:在上上期出號的左右選取的上期號碼,這話不好理解,現舉例說明:雙色球2007109期開01 04 07 08 13 14;
* 110期開02 04 07 15 24 28;其中這期的04
* 07,剛好是109期二、三位的重碼,那麼111期的重碼該選取哪個呢?重碼追鄰就是在110期的04 07 的左右選取,110期04 07
* 的左右是02 15。所以111期的備選號就是02 15 了。實際上111期重碼剛好開的是02。重碼追鄰一般選取2-3個號碼。
*/
/* ========= 或者========= */
/* 旺區落“膽”。就是在最近幾期熱號區選擇膽碼。比如,如果最近的5期內,在中區12~22出號比較密集,那麼就要在這個區域裏選取3個膽碼。這樣選擇的理由是熱碼恆熱原理,即號碼總是在某個區域相對集中出現。 */
if (flag == true) {
hs.add(begin);
hs.add(end);
} else {
Random random = new Random();
hs.add(begin + random.nextInt(end - begin + 1));
}
/* Luck number! */
while (hs.size() < 6) {
Random random = new Random();
hs.add(1 + random.nextInt(33));
}

return hs;
}

public int calcBlueBall(String select1, String select2) {
int begin = 1;
int end = 16;

if (select2.equals(aOrBOrC.A.toString())) {
begin = 1;
end = 5;
} else if (select2.equals(aOrBOrC.B.toString())) {
begin = 6;
end = 10;
} else {
begin = 11;
end = 16;
}

Random random = new Random();
int blueBall = begin + random.nextInt(end - begin + 1);
if (select1.equals(oddOrEven.Odd.toString())) {
while (blueBall % 2 == 0) {
blueBall = begin + random.nextInt(end - begin + 1);
}
} else {
while (blueBall % 2 == 1) {
blueBall = begin + random.nextInt(end - begin + 1);
}
}

return blueBall;
}
}

今天遇到了一個極其鬱悶的問題,想寫一段代碼,可以給windows自動安裝一種字體。
原理就是將4個ttf字體文件複製到C://WINDOWS//Fonts//目錄下。本來以爲很簡單,但用java I/O複製過去的字體不能使用(將記事本的字體改成DejaVuSansMono,如果有效果變化,就是正常的),直接手動複製同樣的文件過去,就可以使 用。不知道問題出在哪裏?
哪位朋友幫忙看看,萬分感謝,字體文件在附件中,代碼如下:
package com.test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

public class FontInstall {

public static void main(String[] args) {
try {
String[] fonts = { "DejaVuSansMono-Oblique.ttf",
"DejaVuSansMono-BoldOblique.ttf", "DejaVuSansMono.ttf",
"DejaVuSansMono-Bold.ttf" };
System.out.println();
for (int i = 0; i < fonts.length; i++) {
// Create channel on the source
FileChannel srcChannel = new FileInputStream(System
.getProperty("user.dir")
+ "//" + fonts[i]).getChannel();

// Create channel on the destination
FileChannel dstChannel = new FileOutputStream(
"C://WINDOWS//Fonts//" + fonts[i]).getChannel();

// Copy file contents from source to destination
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());

// Close the channels
srcChannel.close();
dstChannel.close();
}
} catch (IOException e) {
}
}
}

用另一種寫法試了下,也是不行,複製過去的文件大小是相同的,用比較工具比較也沒問題。
package com.test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FontInstall2 {

public static void main(String[] args) {
try {
String[] fonts = { "DejaVuSansMono-Oblique.ttf",
"DejaVuSansMono-BoldOblique.ttf", "DejaVuSansMono.ttf",
"DejaVuSansMono-Bold.ttf" };
System.out.println();
for (int i = 0; i < fonts.length; i++) {
InputStream in = new FileInputStream(System
.getProperty("user.dir")
+ "//" + fonts[i]);
OutputStream out = new FileOutputStream("C://WINDOWS//Fonts//"
+ fonts[i]);

// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
} catch (IOException e) {
}
}
}


java.util就相當於c++的STL,是Java的一個非常重要的包,有很多常用的數據類型,不同數據類型有不同的用途,而有些數據類似乎很相似,怎樣選擇應用,就需要對它們進行辨析。
下面列出了這些數據類型的特點,根據這些特點,就可以有針對性的選用
 
* 藍色爲接口,綠色爲具體實現類
* 縮進的層次結構,就是implement或extend的層次關係
* 每個接口或類都具備其所有上層接口、類的特性
 
Collection
........|--------List
........|..........|----------ArrayList
........|..........|----------Vector
........|..........|.............|-----Stack
........|..........|----------LinkedList
........|--------Set
...................|----------HashSet.
...................|.............|-----LinkedHashSet
...................|----------SortedSet
.................................|-----TreeSet
 
Iterator
.....|-------ListIterator
 
Map
.....|------Hashtable
.....|..........|------Properties
.....|------HashMap
.....|..........|------LinkedHashMap
.....|------WeakHashMap
.....|------SortedMap
................|------TreeMap

 
Collection.
●..實現該接口及其子接口的所有類都可應用clone()方法,並是序列化類.

.....List.
.....●..可隨機訪問包含的元素
.....●..元素是有序的
.....●..可在任意位置增、刪元素
.....●..不管訪問多少次,元素位置不變
.....●..允許重複元素
.....●..用Iterator實現單向遍歷,也可用ListIterator實現雙向遍歷

..........ArrayList
..........●..用數組作爲根本的數據結構來實現List
..........●..元素順序存儲
..........●..新增元素改變List大小時,內部會新建一個數組,在將添加元素前將所有數據拷貝到新數組中
..........●..隨機訪問很快,刪除非頭尾元素慢,新增元素慢而且費資源
..........●..較適用於無頻繁增刪的情況
..........●..比數組效率低,如果不是需要可變數組,可考慮使用數組
..........●..非線程安全
.
..........Vector.
..........●..另一種ArrayList,具備ArrayList的特性
..........●..所有方法都是線程安全的(雙刃劍,和ArrayList的主要區別)
..........●..比ArrayList效率低

...............Stack
...............●..LIFO的數據結構

..........LinkedList.
..........●..鏈接對象數據結構(類似鏈表)
..........●..隨機訪問很慢,增刪操作很快,不耗費多餘資源
..........●..非線程安全

.....Set.
.....●..不允許重複元素,可以有一個空元素
.....●..不可隨機訪問包含的元素
.....●..只能用Iterator實現單向遍歷

..........HashSet
..........●..用HashMap作爲根本數據結構來實現Set
..........●..元素是無序的
..........●..迭代訪問元素的順序和加入的順序不同
..........●..多次迭代訪問,元素的順序可能不同
..........●..非線程安全

...............LinkedHashSet
...............●..基於HashMap和鏈表的Set實現
...............●..迭代訪問元素的順序和加入的順序相同
...............●..多次迭代訪問,元素的順序不便
...............●..因此可說這是一種有序的數據結構
...............●..性能比HashSet差
...............●..非線程安全

..........SortedSet
..........●..加入SortedSet的所有元素必須實現Comparable接口
..........●..元素是有序的

...............TreeSet.
...............●..基於TreeMap實現的SortedSet
...............●..排序後按升序排列元素
...............●..非線程安全

-----------------------------------
 
Iterator..
●..對Set、List進行單向遍歷的迭代器

..........ListIterator.
..........●..對List進行雙向遍歷的迭代器

-----------------------------------

Map
●..鍵值對,鍵和值一一對應
●..不允許重複的鍵.

.....Hashtable.
.....●..用作鍵的對象必須實現了hashcode()、equals()方法,也就是說只有Object及其子類可用作鍵
.....●..鍵、值都不能是空對象
.....●..多次訪問,映射元素的順序相同
.....●..線程安全的

..........Properties
..........●..鍵和值都是字符串

.....HashMap
.....●..鍵和值都可以是空對象
.....●..不保證映射的順序
.....●..多次訪問,映射元素的順序可能不同
.....●..非線程安全

...............LinkedHashMap
...............●..多次訪問,映射元素的順序是相同的
...............●..性能比HashMap差

.....WeakHashMap..
.....●..當某個鍵不再正常使用時,垃圾收集器會移除它,即便有映射關係存在
.....●..非線程安全

.....SortedMap.
.....●..鍵按升序排列
.....●..所有鍵都必須實現.Comparable.接口.

...............TreeMap.
...............●..基於紅黑樹的SortedMap實現
...............●..非線程安全
正則表達式是一種通用的標準,大部分計算機語言都支持正則表達式,包括as3,這裏轉摘出了一些常用的正則表達式語句,大家用到的時候就不用自己寫了

^/d+$  //匹配非負整數(正整數 + 0)
^[0-9]*[1-9][0-9]*$  //匹配正整數
^((-/d+)|(0+))$  //匹配非正整數(負整數 + 0)
^-[0-9]*[1-9][0-9]*$  //匹配負整數
^-?/d+$    //匹配整數
^/d+(/./d+)?$  //匹配非負浮點數(正浮點數 + 0)
^(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*))$  //匹配正浮點數
^((-/d+(/./d+)?)|(0+(/.0+)?))$  //匹配非正浮點數(負浮點數 + 0)
^(-(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*)))$  //匹配負浮點數
^(-?/d+)(/./d+)?$  //匹配浮點數
^[A-Za-z]+$  //匹配由26個英文字母組成的字符串
^[A-Z]+$  //匹配由26個英文字母的大寫組成的字符串
^[a-z]+$  //匹配由26個英文字母的小寫組成的字符串
^[A-Za-z0-9]+$  //匹配由數字和26個英文字母組成的字符串
^/w+$  //匹配由數字、26個英文字母或者下劃線組成的字符串
^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$    //匹配email地址
^[a-zA-z]+://匹配(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$  //匹配url

匹配中文字符的正則表達式: [/u4e00-/u9fa5]
匹配雙字節字符(包括漢字在內):[^/x00-/xff]
匹配空行的正則表達式:/n[/s| ]*/r
匹配HTML標記的正則表達式:/<(.*)>.*<//>|<(.*) //>/
匹配首尾空格的正則表達式:(^/s*)|(/s*$)
匹配Email地址的正則表達式:/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
匹配網址URL的正則表達式:^[a-zA-z]+://(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$
匹配帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
匹配國內電話號碼:(/d{3}-|/d{4}-)?(/d{8}|/d{7})?
匹配騰訊QQ號:^[1-9]*[1-9][0-9]*$
下表是元字符及其在正則表達式上下文中的行爲的一個完整列表:
/ 將下一個字符標記爲一個特殊字符、或一個原義字符、或一個後向引用、或一個八進制轉義符。
^ 匹配輸入字符串的開始位置。如果設置了 RegExp 對象的Multiline 屬性,^ 也匹配 ’/n’ 或 ’/r’ 之後的位置。
$ 匹配輸入字符串的結束位置。如果設置了 RegExp 對象的Multiline 屬性,$ 也匹配 ’/n’ 或 ’/r’ 之前的位置。
* 匹配前面的子表達式零次或多次。
+ 匹配前面的子表達式一次或多次。+ 等價於 {1,}。
? 匹配前面的子表達式零次或一次。? 等價於 {0,1}。
{n} n 是一個非負整數,匹配確定的n 次。
{n,} n 是一個非負整數,至少匹配n 次。
{n,m} m 和 n 均爲非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。在逗號和兩個數之間不能有空格。
? 當該字符緊跟在任何一個其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 後面時,匹配模式是非貪婪的。非貪婪模式儘可能少的匹配所搜索的字符串,而默認的貪婪模式則儘可能多的匹配所搜索的字符串。
. 匹配除 "/n" 之外的任何單個字符。要匹配包括 ’/n’ 在內的任何字符,請使用象 ’[./n]’ 的模式。
(pattern) 匹配pattern 並獲取這一匹配。
(?:pattern) 匹配pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供以後使用。
(?=pattern) 正向預查,在任何匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以後使用。
(?!pattern) 負向預查,與(?=pattern)作用相反
x|y 匹配 x 或 y。
[xyz] 字符集合。
[^xyz] 負值字符集合。
[a-z] 字符範圍,匹配指定範圍內的任意字符。
[^a-z] 負值字符範圍,匹配任何不在指定範圍內的任意字符。
/b 匹配一個單詞邊界,也就是指單詞和空格間的位置。
/B 匹配非單詞邊界。
/cx 匹配由x指明的控制字符。
/d 匹配一個數字字符。等價於 [0-9]。
/D 匹配一個非數字字符。等價於 [^0-9]。
/f 匹配一個換頁符。等價於 /x0c 和 /cL。
/n 匹配一個換行符。等價於 /x0a 和 /cJ。
/r 匹配一個回車符。等價於 /x0d 和 /cM。
/s 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於[ /f/n/r/t/v]。
/S 匹配任何非空白字符。等價於 [^ /f/n/r/t/v]。
/t 匹配一個製表符。等價於 /x09 和 /cI。
/v 匹配一個垂直製表符。等價於 /x0b 和 /cK。
/w 匹配包括下劃線的任何單詞字符。等價於’[A-Za-z0-9_]’。
/W 匹配任何非單詞字符。等價於 ’[^A-Za-z0-9_]’。
/xn 匹配 n,其中 n 爲十六進制轉義值。十六進制轉義值必須爲確定的兩個數字長。
/num 匹配 num,其中num是一個正整數。對所獲取的匹配的引用。
/n 標識一個八進制轉義值或一個後向引用。如果 /n 之前至少 n 個獲取的子表達式,則 n 爲後向引用。否則,如果 n 爲八進制數字 (0-7),則 n 爲一個八進制轉義值。
/nm 標識一個八進制轉義值或一個後向引用。如果 /nm 之前至少有is preceded by at least nm 個獲取得子表達式,則 nm 爲後向引用。如果 /nm 之前至少有 n 個獲取,則 n 爲一個後跟文字 m 的後向引用。如果前面的條件都不滿足,若 n 和 m 均爲八進制數字 (0-7),則 /nm 將匹配八進制轉義值 nm。
/nml 如果 n 爲八進制數字 (0-3),且 m 和 l 均爲八進制數字 (0-7),則匹配八
【程序1】
題目:古典問題:有一對兔子,從出生後第3個月起每個月都生一對兔子,小兔子長到第三個月後每個月又生一對兔子,假如兔子都不死,問每個月的兔子總數爲多少?
1.程序分析: 兔子的規律爲數列1,1,2,3,5,8,13,21....

【程序2】
題目:判斷101-200之間有多少個素數,並輸出所有素數。
1.程序分析:判斷素數的方法:用一個數分別去除2到sqrt(這個數),如果能被整除,
則表明此數不是素數,反之是素數。

【程序3】
題目:打印出所有的"水仙花數",所謂"水仙花數"是指一個三位數,其各位數字立方和等於該數本身。例如:153是一個"水仙花數",因爲153=1的三次方+5的三次方+3的三次方。
1.程序分析:利用for循環控制100-999個數,每個數分解出個位,十位,百位。

【程序4】
題目:將一個正整數分解質因數。例如:輸入90,打印出90=2*3*3*5。
程序分析:對n進行分解質因數,應先找到一個最小的質數k,然後按下述步驟完成:
(1)如果這個質數恰等於n,則說明分解質因數的過程已經結束,打印出即可。
(2)如果n<>k,但n能被k整除,則應打印出k的值,並用n除以k的商,作爲新的正整數你n,重複執行第一步。
(3)如果n不能被k整除,則用k+1作爲k的值,重複執行第一步。

【程序5】
題目:利用條件運算符的嵌套來完成此題:學習成績>=90分的同學用A表示,60-89分之間的用B表示,60分以下的用C表示。
1.程序分析:(a>b)?a:b這是條件運算符的基本例子。

【程序6】
題目:輸入兩個正整數m和n,求其最大公約數和最小公倍數。
1.程序分析:利用輾除法。

【程序7】
題目:輸入一行字符,分別統計出其中英文字母、空格、數字和其它字符的個數。
1.程序分析:利用while語句,條件爲輸入的字符不爲'/n'.

【程序8】
題目:求s=a+aa+aaa+aaaa+aa...a的值,其中a是一個數字。例如2+22+222+2222+22222(此時共有5個數相加),幾個數相加有鍵盤控制。
1.程序分析:關鍵是計算出每一項的值。

【程序9】
題目:一個數如果恰好等於它的因子之和,這個數就稱爲"完數"。例如6=1+2+3.編程 找出1000以內的所有完數。

【程序10】
題目:一球從100米高度自由落下,每次落地後反跳回原高度的一半;再落下,求它在 第10次落地時,共經過多少米?第10次反彈多高?

【程序11】
題目:有1、2、3、4個數字,能組成多少個互不相同且無重複數字的三位數?都是多少?
1.程序分析:可填在百位、十位、個位的數字都是1、2、3、4。組成所有的排列後再去 掉不滿足條件的排列。

【程序12】
題目:企業發放的獎金根據利潤提成。利潤(I)低於或等於10萬元時,獎金可提10%;利潤高於10萬元,低於20萬元時,低於10萬元的部分按 10%提成,高於10萬元的部分,可可提成7.5%;20萬到40萬之間時,高於20萬元的部分,可提成5%;40萬到60萬之間時高於40萬元的部分, 可提成3%;60萬到100萬之間時,高於60萬元的部分,可提成1.5%,高於100萬元時,超過100萬元的部分按1%提成,從鍵盤輸入當月利潤I, 求應發放獎金總數?
1.程序分析:請利用數軸來分界,定位。注意定義時需把獎金定義成長整型。

【程序13】
題目:一個整數,它加上100後是一個完全平方數,再加上168又是一個完全平方數,請問該數是多少?
1.程序分析:在10萬以內判斷,先將該數加上100後再開方,再將該數加上268後再開方,如果開方後的結果滿足如下條件,即是結果。請看具體分析:

【程序14】
題目:輸入某年某月某日,判斷這一天是這一年的第幾天?
1.程序分析:以3月5日爲例,應該先把前兩個月的加起來,然後再加上5天即本年的第幾天,特殊情況,閏年且輸入月份大於3時需考慮多加一天。

【程序15】
題目:輸入三個整數x,y,z,請把這三個數由小到大輸出。
1.程序分析:我們想辦法把最小的數放到x上,先將x與y進行比較,如果x>y則將x與y的值進行交換,然後再用x與z進行比較,如果x>z則將x與z的值進行交換,這樣能使x最小。

【程序16】
題目:輸出9*9口訣。
1.程序分析:分行與列考慮,共9行9列,i控制行,j控制列。

【程序17】
題目:猴子喫桃問題:猴子第一天摘下若干個桃子,當即吃了一半,還不癮,又多吃了一個 第二天早上又將剩下的桃子喫掉一半,又多吃了一個。以後每天早上都吃了前一天剩下 的一半零一個。到第10天早上想再喫時,見只剩下一個桃子了。求第一天共摘了多少。
1.程序分析:採取逆向思維的方法,從後往前推斷。

【程序18】
題目:兩個乒乓球隊進行比賽,各出三人。甲隊爲a,b,c三人,乙隊爲x,y,z三人。已抽籤決定比賽名單。有人向隊員打聽比賽的名單。a說他不和x比,c說他不和x,z比,請編程序找出三隊賽手的名單。
1.程序分析:判斷素數的方法:用一個數分別去除2到sqrt(這個數),如果能被整除, 則表明此數不是素數,反之是素數。

【程序19】
題目:打印出如下圖案(菱形)
*
***
******
********
******
***
*
1.程序分析:先把圖形分成兩部分來看待,前四行一個規律,後三行一個規律,利用雙重 for循環,第一層控制行,第二層控制列。

【程序20】
題目:有一分數序列:2/1,3/2,5/3,8/5,13/8,21/13...求出這個數列的前20項之和。
1.程序分析:請抓住分子與分母的變化規律。

【程序21】
題目:求1+2!+3!+...+20!的和
1.程序分析:此程序只是把累加變成了累乘。

【程序22】
題目:利用遞歸方法求5!。
1.程序分析:遞歸公式:fn=fn_1*4!

【程序23】
題目:有5個人坐在一起,問第五個人多少歲?他說比第4個人大2歲。問第4個人歲數,他說比第3個人大2歲。問第三個人,又說比第2人大兩歲。問第2個人,說比第一個人大兩歲。最後問第一個人,他說是10歲。請問第五個人多大?
1.程序分析:利用遞歸的方法,遞歸分爲回推和遞推兩個階段。要想知道第五個人歲數,需知道第四人的歲數,依次類推,推到第一人(10歲),再往回推。

【程序24】
題目:給一個不多於5位的正整數,要求:一、求它是幾位數,二、逆序打印出各位數字。

【程序25】
題目:一個5位數,判斷它是不是迴文數。即12321是迴文數,個位與萬位相同,十位與千位相同。

【程序26】
題目:請輸入星期幾的第一個字母來判斷一下是星期幾,如果第一個字母一樣,則繼續 判斷第二個字母。
1.程序分析:用情況語句比較好,如果第一個字母一樣,則判斷用情況語句或if語句判斷第二個字母。

【程序27】
題目:求100之內的素數

【程序28】
題目:對10個數進行排序
1.程序分析:可以利用選擇法,即從後9個比較過程中,選擇一個最小的與第一個元素交換, 下次類推,即用第二個元素與後8個進行比較,並進行交換。

【程序29】
題目:求一個3*3矩陣對角線元素之和
1.程序分析:利用雙重for循環控制輸入二維數組,再將a[i][i]累加後輸出。

【程序30】
題目:有一個已經排好序的數組。現輸入一個數,要求按原來的規律將它插入數組中。
1. 程序分析:首先判斷此數是否大於最後一個數,然後再考慮插入中間的數的情況,插入後此元素之後的數,依次後移一個位置。

【程序31】
題目:將一個數組逆序輸出。
1.程序分析:用第一個與最後一個交換。

【程序32】
題目:取一個整數a從右端開始的4~7位。
程序分析:可以這樣考慮:
(1)先使a右移4位。
(2)設置一個低4位全爲1,其餘全爲0的數。可用~(~0<<4)
(3)將上面二者進行&運算。

【程序33】
題目:打印出楊輝三角形(要求打印出10行如下圖)
1.程序分析:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

【程序34】
題目:輸入3個數a,b,c,按大小順序輸出。
1.程序分析:利用指針方法。

【程序35】
題目:輸入數組,最大的與第一個元素交換,最小的與最後一個元素交換,輸出數組。

【程序36】
題目:有n個整數,使其前面各數順序向後移m個位置,最後m個數變成最前面的m個數

【程序37】
題目:有n個人圍成一圈,順序排號。從第一個人開始報數(從1到3報數),凡報到3的人退出圈子,問最後留下的是原來第幾號的那位。

【程序38】
題目:寫一個函數,求一個字符串的長度,在main函數中輸入字符串,並輸出其長度。

【程序39】
題目:編寫一個函數,輸入n爲偶數時,調用函數求1/2+1/4+...+1/n,當輸入n爲奇數時,調用函數1/1+1/3+...+1/n(利用指針函數)

【程序40】
題目:字符串排序。

【程序41】
題目:海灘上有一堆桃子,五隻猴子來分。第一隻猴子把這堆桃子憑據分爲五份,多了一個,這隻猴子把多的一個扔入海中,拿走了一份。第二隻猴子把剩 下的桃子又平均分成五份,又多了一個,它同樣把多的一個扔入海中,拿走了一份,第三、第四、第五隻猴子都是這樣做的,問海灘上原來最少有多少個桃子?

【程序42】
題目:809*??=800*??+9*??+1 其中??代表的兩位數,8*??的結果爲兩位數,9*??的結果爲3位數。求??代表的兩位數,及809*??後的結果。

【程序43】
題目:求0—7所能組成的奇數個數。

【程序44】
題目:一個偶數總能表示爲兩個素數之和。

【程序45】
題目:判斷一個素數能被幾個9整除

【程序46】
題目:兩個字符串連接程序

【程序47】
題目:讀取7個數(1—50)的整數值,每讀取一個值,程序打印出該值個數的*。

【程序48】
題目:某個公司採用公用電話傳遞數據,數據是四位的整數,在傳遞過程中是加密的,加密規則如下:每位數字都加上5,然後用和除以10的餘數代替該數字,再將第一位和第四位交換,第二位和第三位交換。

【程序49】
題目:計算字符串中子串出現的次數

【程序50】
題目:有五個學生,每個學生有3門課的成績,從鍵盤輸入以上數據(包括學生號,姓名,三門課成績),計算出平均成績,況原有的數據和計算出的平均分數存放在磁盤文件"stud"中。
在實際工作中,常常需要設定數字的輸出格式,如以百分比的形式輸出,或者設定小數位數等,現稍微總結如下。
主要使用的類:java.text.DecimalFormat
1。實例化對象,可以用如下兩種方法:
      DecimalFormat df=(DecimalFormat)NumberFormat.getInstance();
      DecimalFormat df1=(DecimalFormat) DecimalFormat.getInstance();
     因爲DecimalFormat繼承自NumberFormat。
2。設定小數位數
系統默認小數位數爲3,如:
    DecimalFormat df=(DecimalFormat)NumberFormat.getInstance();
    System.out.println(df.format(12.3456789));
輸出:12.346
現在可以通過如下方法把小數爲設爲兩位:
  df.setMaximumFractionDigits(2);
    System.out.println(df.format(12.3456789));
則輸出爲:12.35
3。將數字轉化爲百分比輸出,有如下兩種方法:
(1)
  df.applyPattern("##.##%");
    System.out.println(df.format(12.3456789));
    System.out.println(df.format(1));
    System.out.println(df.format(0.015));
輸出分別爲:1234.57%    100%      1.5%
(2)
    df.setMaximumFractionDigits(2);
    System.out.println(df.format(12.3456789*100)+"%");
    System.out.println(df.format(1*100)+"%");
    System.out.println(df.format(0.015*100)+"%");
輸出分別爲:
1,234.57%     100%     1.5%
4。設置分組大小
     DecimalFormat df1=(DecimalFormat) DecimalFormat.getInstance();
df1.setGroupingSize(2);
    System.out.println(df1.format(123456789));
輸出:1,23,45,67,89
還可以通過df1.setGroupingUsed(false);來禁用分組設置,如:
     DecimalFormat df1=(DecimalFormat) DecimalFormat.getInstance();
    df1.setGroupingSize(2);
df1.setGroupingUsed(false);
    System.out.println(df1.format(123456789));
輸出:123456789
5。設置小數爲必須爲2位
    DecimalFormat df2=(DecimalFormat) DecimalFormat.getInstance();
  df2.applyPattern("0.00");
    System.out.println(df2.format(1.2));
輸出:1.20

java.text.DecimalFormat學習筆記


例子:
import java.text.*;

public class Untitled1    {
   public static void main(String[] args) {

     //---------------------------------------------
     //定義一個數字格式化對象,格式化模板爲".##",即保留2位小數.
     DecimalFormat a = new DecimalFormat(".##");
     String s= a.format(333.335);
     System.err.println(s);
     //說明:如果小數點後面不夠2位小數,不會補零.參見Rounding小節
     //---------------------------------------------

     //-----------------------------------------------
     //可以在運行時刻用函數applyPattern(String)修改格式模板
     //保留2位小數,如果小數點後面不夠2位小數會補零
     a.applyPattern(".00");
     s = a.format(333.3);
     System.err.println(s);
     //------------------------------------------------

     //------------------------------------------------
     //添加千分號
     a.applyPattern(".##/u2030");
     s = a.format(0.78934);
     System.err.println(s);//添加千位符後,小數會進三位並加上千位符
     //------------------------------------------------

     //------------------------------------------------
     //添加百分號
     a.applyPattern("#.##%");
     s = a.format(0.78645);
     System.err.println(s);
     //------------------------------------------------

    //------------------------------------------------
     //添加前、後修飾字符串,記得要用單引號括起來
     a.applyPattern("'這是我的錢$',###.###'美圓'");
     s = a.format(33333443.3333);
     System.err.println(s);
     //------------------------------------------------

      //------------------------------------------------
     //添加貨幣表示符號(不同的國家,添加的符號不一樣
     a.applyPattern("/u00A4");
     s = a.format(34);
     System.err.println(s);
     //------------------------------------------------

     //-----------------------------------------------
     //定義正負數模板,記得要用分號隔開
      a.applyPattern("0.0;'@'-#.0");
      s = a.format(33);
      System.err.println(s);
      s = a.format(-33);
      System.err.println(s);
      //-----------------------------------------------
   
     //綜合運用,正負數的不同前後綴
     String pattern="'my moneny'###,###.##'RMB';'ur money'###,###.##'US'";
     a.applyPattern(pattern);
     System.out.println(a.format(1223233.456));
   }
}

總結:
要生成一個DecimalFormat對象,一般只要通過NumberFormat類工廠的getInstance()來取得一個 NumberFormat對象再將其轉換成DecimalFormat對象,然後通過DecimalForat對象的applyPattern()來動態 改變數據的現示格式模板,通過format()方法取得格式化後的數字。同時,DecimalFormat提供了許多的方法來返回格式化後的數字的某一部 份,這些方法如:getNegativeSuffix()。這個類的難點主要是在模板的書寫及理解上。其實主要的就是針對一個數字的正負形式來設定不同的 格式顯示。這裏要特別注意的是使用在模板上的特殊字符代表有特殊的意義,如下表所示:
Symbol    Description
0    a digit
#    a digit, zero shows as absent
.    placeholder for decimal separator
,    placeholder for grouping separator
E   separates mantissa and exponent for exponential formats
;    separates formats
-    default negative prefix
%    multiply by 100 and show as percentage
?    multiply by 1000 and show as per mille
¤    currency sign; replaced by currency symbol; if doubled, replaced by international currency symbol; if present in a pattern, the monetary decimal separator is used instead of the decimal separator 
X    any other characters can be used in the prefix or suffix
'    used to quote special characters in a prefix or suffix

例如:如果模板中含有#,意思是指這個#號可代表一個或多個數字如果該位的數字是零的話則省略該位。另:注意“#,##0.0#;(#)”這個模板的意思是指數字的負數形式跟正數的一樣。
經常需要運行一些打成jar文件格式的Java程序,每次都需要切換到DOS下運行命令:java -jar FileName.jar ,非常的麻煩。

其實可以將jar文件的默認打開方式設置成jre中的javaw,設置好後可以雙擊jar文件運行。但這樣的話,需要查看包中內容的時候又非常麻煩,需要將jar文件拖到解壓縮工具中。

今天突發奇想,改寫了一個批處理文件,可以將java -jar命令加到鼠標右鍵中:
reg add "HKCR/*/shell/Run_Jar" /ve /d Run_Jar /f
reg add "HKCR/*/shell/Run_Jar/command" /ve /d "java -jar %%1" /f
reg add "HKCR/Folder/shell/Run_Jar" /ve /d Run_Jar /f
reg add "HKCR/Folder/shell/Run_Jar/command" /ve /d "java -jar %%1" /f

將上面的代碼保存爲bat文件,然後雙擊執行,執行後,鼠標右鍵中會出現Run_Jar選項。
這下你就可以在你想運行的jar文件上點擊右鍵,然後Run_Jar,怎麼樣,比較方便吧:)

稍微解釋一下上面的命令:
reg add "HKCR/*/shell/Run_Jar"
在註冊表中的HKEY_CLASSES_ROOT/*shell/ 目錄下添加鍵值,後面參數的意思分別是:
/ve      爲註冊表項添加空白值名<無名稱>
/d       要分配給添加的註冊表 ValueName 的數據
/f       不用提示就強行改寫現有註冊表項
開講。

做一個Web遊戲外掛需要的準備知識:
1) 需要有耐心
2) 熟悉HTML, JavaScript,特別是FORM
3) 熟悉HTTP協議,特別是Cookie, URL的編碼方式和POST, GET內容格式
4) 熟悉遊戲本身,能抽象出最優的賺錢/升級的數學模型
5) 掌握一門語言,白菜蘿蔔都可以,我比較喜歡用Python和C#
6) 需要一些抓包的工具,比如Fiddler

好了,來個例子,開心網爭車位.

首先,我們看看一個正常用戶玩的時候是怎麼玩的。
1) 瀏覽器輸入 www.kaixin001.com ,輸入用戶名,密碼,點登陸
2) 登陸後選擇左側的“爭車位”,進入到爭車位
3) 看看誰在我的車位裏,一一貼條
4) 看看自己的車哪些停車時間操作15分鐘了,一一找個空的不免費的車位挪過去
5) 登出開心網,關閉瀏覽器

看看讓程序怎麼來實現1-6。
1) 登陸開心網
在Fiddler的幫助下,我們知道登陸是把FORM提交到/login/login.php,POST內容是url=%2F&[email protected]&password=xxx
用C#可以方便的完成這個POST操作,然後得到服務器的返回,然後根據返回的內容裏找一個關鍵字就可以判斷這次登陸操作是否成功了。(比如我找的就是"<title>我的首頁 - 開心網</title>")

2) 登陸爭車位
這次是一個GET操作,URL是/app/app.php?aid=1040。
需要說明一下的是,這裏沒有提供用戶名密碼,服務器怎麼能知道是哪個用戶呢?Cookie在這裏就發揮了它的作用。
C#裏存放Cookie的方法是new 一個CookieContainer,然後所有的HttpWebRequest的CookieContainer都用它。
好了,取得這個頁面以後,我們能得到很多信息:(這些信息是JSON格式)
a) 好友列表,每個好友的狀態(在線/車位滿)
b) 自己的車庫信息,停了那些好友的哪些車,分別賺了多少錢
c) 自己的汽車信息,多少輛車,分別停在哪裏,賺了多少錢
根據這些信息,我們可以得到一個停放的列表(車位不滿的好友列表)

3) 貼條
貼條是一個POST操作,URL是/parking/post.php,內容是verify=xxx&parkid=yyy&p=1&_=
parkid很好理解,車庫信息裏直接可以取到,那麼verify怎麼得到的呢?
我當初的第一反應是Cookie數據通過某種運算得到的,不過後來我看了登陸爭車位的html後才發現原來這個verify是這樣寫的:
...
<script language=javascript>
var fs2_pars = "f1";
var g_verify = "383639_1040_383639_1221703779_49963b942199e94b88e405d0f7b1651d";
var g_first = parseInt("0");
var g_touid = parseInt("0");
var g_checkswf = 0;
.....
很好,直接去這個從HTML取得的值就好了。

4) 挪車位
這個操作稍微複雜了一點點,具體的HTTP請求大家可以去分析一下,我分析的結果如下:
a) 是否是免費車位
在JavaScript裏有代碼:
v_park_free = (v_parkid >> 16) & 0xff;
      if (v_park_free)
      {
        v_mycar += '免費車位';
      }
      else
      {
        v_mycar += '私家車位';
      }
c) 讀取鄰居家車庫信息
URL: /parking/neighbor.php
POST內容: verify=xxx&puid=yyy&_=
d) 讀取鄰居家車庫信息
URL: /parking/user.php
POST內容: verify=xxx&puid=yyy&_=
e) 停車
URL: /parking/park.php
POST內容: verify=xxx&park_uid=xxx&parkid=xxx&carid=xxx&neighbor=xxx&a=1&first_fee_parking=0&_=

5) 登出
GET URL: /login/logout.php

恭喜你,基本的操作你都明白了。

時間晚了,該睡覺了,一些高級主題改天再寫~

--------------Google Code 分割線-------------
http://code.google.com/p/kaixin/
給學習J2EE的朋友一些值得研究的開源項目
江蘇 無錫 繆小東

       這篇文章寫在我研究J2SE、J2EE近三年後。前3年我研究了J2SE的Swing、Applet、Net、RMI、Collections、IO、 JNI......研究了J2EE的JDBC、Sevlet、JSP、JNDI…..不久我發現這些好像太浮淺了:首先,我發現自己知道的僅僅是java 提供的大量的API,根本不能很好地使用它;其次,我根本就沒有學到任何有助於寫程序的知識,此時我也只不過能寫個幾頁的小程序。出於這個幼稚的想法我研 究了JDK中Collections、Logger、IO…..的源代碼,發現這個世界真的很神奇,竟然有如此的高手――利用java語言最最基本的語 法,創造了這些優秀的Framework。從此一發不可收拾,我繼續研究了J2EE的部分,又發現這是一個我根本不能理解的方向(曾經有半年停滯不前), 爲什麼只有接口沒有實現啊!後來由於一直使用Tomcat、Derby等軟件突然發現:哦!原來J2EE僅僅是一個標準,只是一個架構。真正的實現是不同 提供商提供的。接着我研究了MOM4J、OpenJMS、Mocki、HSQLD……發現這些就是J2EE的實現啊!原來軟件竟會如此複雜,竟會如此 做….規範和實現又是如何成爲一體的呢?通過上面的研究發現:原來J2EE後面竟然有太多太多理念、太多太多的相似!這些相似就是其背後的理念――設計模 式!(很幸運,在我學java的時候,我一般學java的一個方向就會讀一些關於設計模式的書!很幸運,到能領略一點的時候能真正知道這是爲什麼!)其實 模式就是一種思維方式、就是一種理念……模式是要運用到程序中的,只有從真正的項目中才能領會模式的含義……

       學得越多,發現懂得越少!在學習過程中發現一些很有用,很值得學習的開源項目,今天在此推薦給大家。

一、              JavaServlet和JSP方向
       很多人都是從Servlet和JSP步入J2EE的。它就是J2EE的表現層,用於向客戶呈現服務器上的內容。J2EE很重要的方面。不羅嗦了!大家都知道的!下面就開始推薦吧!

1. Jakarta Tomcat       
       Apache基金會提供的免費的開源的Serlvet容器,它是的Jakarta項目中的一個核心項目,由Apache、Sun和其它一些公司(都是IT 界的大鱷哦)及個人共同開發而成,全世界絕大部分Servlet和Jsp的容器都是使用它哦!由於Sun的參與和支持,最新的Servlet和Jsp規範 總能在Tomcat中得到體現。

       不過它是一個非常非常全的Serlvet容器,全部源碼可能有4000頁,對於初學者或者一般的老手可能還是比較大了!在你有能力時推薦研究!下載地址:http://jakarta.apache.org/tomcat/index.html

       下面推薦兩個小一點的吧!

2. Jetty        
       Jetty是一個開放源碼的HTTP服務器和Java serverlet容器。源代碼只有1000頁左右,很值得研究。有興趣可以去http://jetty.mortbay.com/下載看看。我曾經翻了 一下,只是目前沒有時間。(都化在博客上了,等博客基本定型,且內容完整了,再幹我熱衷的事件吧!)

3. Jigsaw   
       Jigsaw是W3C開發的HTTP,基於Java 的服務器,提供了未來 Web 技術發展的藍圖。W3C知道吧!(太有名氣了,很多標準都是它制訂的!有空經常去看看吧!)下載網址:http://www.w3.org/Jigsaw 代碼僅僅1000頁左右。

4. Jo!   
       Jo!是一個純Java的實現了Servlet API 2.2, JSP 1.1, 和HTTP/1.1的Web服務器。它的特性包括支持servlet tag,支持SSI,高級線程管理,虛擬主機,數據緩存,自動壓縮text或HTML文件進行傳輸,國際化支持,自動重新加載Servlet、Jsp,自 動重新加載web工程文件(WARs),支持WAR熱部署和一個Swing控制檯。jo!可以被用做jboss和jakarta avalon-phoenix的web容器。下載地址http://www.tagtraum.com/ 。我極力推薦大家在研究Tomcat之前研究該軟件,主要是其比Tomcat小多了,且開發者提供比較全的手冊。該方向研究這兩個也就可以了!

二、              JDBC方向
       很多人都喜歡JDBC,數據庫嗎!很深奧的東西,一聽就可以糊弄人。其實等你真正研究了數據庫的實現後發現,接口其實真的太簡單,太完美了!要想設計如此優秀的框架還是需要學習的。下面就推薦幾個數據庫的實現吧!

1. Hypersonic SQL
       Hypersonic SQL開源數據庫方向比較流行的純Java開發的關係型數據庫。好像不是JDBC兼容的,JDBC的很多高級的特性都沒有支持,不過幸好支持ANSI- 92 標準 SQL語法。我推薦它主要是它的代碼比較少1600頁左右,如此小的數據庫值得研究,而且他佔的空間很小,大約只有160K,擁有快速的數據庫引擎。推薦 你的第一個開源數據庫。下載地址:http://hsqldb.sourceforge.net/。



2. Mckoi DataBase
       McKoiDB 和Hypersonic SQL差不多,它是GPL 的license的純Java開發的數據庫。他的 JDBC Driver 是使用 JDBC version 3 的 Specifaction。 他也是遵循 SQL-92 的標準,也儘量支持新的 SQL 特色, 並且支持 Transaction 的功能。兩個可以選一個吧!下載地址:http://mckoi.com/database/。



3. Apache Derby 
       學Java的數據庫我建議使用Apache Derby ,研究數據庫想成爲一個數據庫的高手我建議你先研究Apache Derby。Apache Derby是一個高質量的、純 Java開發的嵌入式關係數據庫引擎,IBM® 將其捐獻給Apache開放源碼社區,同時IBM的產品CloudSpace是它對應的產品。Derby是基於文件系統,具有高度的可移植性,並且是輕量 級的,這使得它非常便於發佈。主要是沒有商業用戶的很好的界面,沒有其太多的功能。不過對於我們使用數據庫、研究數據庫還是極其有用的。對於中小型的企業 說老實話你也不要用什麼Oracle、SqlServer了,用Derby就可以了,何況是開源的呢!只要能發揮其長處也不容易啊!下載地 址:http://incubator.apache.org/derby。

       不過在沒有足夠的能力前,不要試圖讀懂它!註釋和源代碼15000頁左右,我一年的閱讀量!能讀下來並且能真正領會它,絕對高手!你能讀完Derby的源 代碼只有兩種可能:1.你成爲頂尖的高手――至少是數據庫這部分;2.你瘋了。選擇吧!!!!作爲我自己我先選擇Hypersonic SQL這樣的數據庫先研究,能過這一關,再繼續研究Derby!不就是一年的閱讀量嗎!我可以化3年去研究如何做一個數據庫其實還是很值得的!有的人搞 IT一輩子自己什麼都沒有做,也根本沒有研究別人的東西!

       作爲一個IT落後於別國若干年的、從事IT的下游產業“外包”的國家的IT從業人員,我認爲還是先研究別人的優秀的東西比較好!可以先研究別人的,然後消化,學爲己用!一心閉門造車實在遺憾!





三、              JMS方向
       JMS可能對大家來說是一個比較陌生的方向!其實JMS是一個比較容易理解,容易上手的方向。主要是Java消息服務,API也是相當簡單的。不過在企業應用中相當廣泛。下面就介紹幾個吧!

1. MOM4J
       MOM4J是一個完全實現JMS1.1規範的消息中間件並且向下兼容JMS1.0與1.02。它提供了自己的消息處理存儲使它獨立於關係數據與語言,它的 客戶端可以用任何語言開發。它可以算是一個小麻雀,很全實現也比較簡單!它包含一個命名服務器,一個消息服務器,同時提供自己的持續層。設計也相當的巧 妙,完全利用操作系統中文件系統設計的觀念。代碼也很少,250頁左右,最近我在寫該實現的源代碼閱讀方面的書,希望明年年中能與大家見面!下載地 址:http://mom4j.sourceforge.net/index.html。



2. OpenJMS  
       OpenJMS是一個開源的Java Message Service API 1.0.2 規範的實現,它包含有以下特性:

1.        它既支持點到點(point-to-point)(PTP)模型和發佈/訂閱(Pub/Sub)模型。

2.        支持同步與異步消息發送 。

3.        JDBC持久性管理使用數據庫表來存儲消息 。

4.        可視化管理界面。

5.        Applet支持。

6.        能夠與Jakarta Tomcat這樣的Servlet容器結合。

7.        支持RMI, TCP, HTTP 與SSL協議。

8.        客戶端驗證 。

9.        提供可靠消息傳輸、事務和消息過濾。

       很好的JMS方向的開源項目!我目前也在研究它的源代碼!學習它可以順便研究JNDI的實現、以及網絡通信的細節。這是我JMS方向研究的第二個開源項 目。代碼量1600頁左右吧!下載地址:http://openjms.sourceforge.net/index.html



3. ActiveMQ  
       ActiveMQ是一個開放源碼基於Apache 2.0 licenced 發佈並實現了JMS 1.1。它能夠與Geronimo,輕量級容器和任Java應用程序無縫的給合。主要是Apache的可以任意的使用和發佈哦!個人比較喜歡Apache 的源代碼!下載地址:http://activemq.codehaus.org/



4. JORAM
       JORAM一個類似於openJMS分佈在ObjectWeb之下的JMS消息中間件。ObjectWeb的產品也是非常值得研究的!下面我還會給大家另外一個ObjectWeb的產品。下載地址:http://joram.objectweb.org/

       我個人推薦:OpenJMS和ActiveMQ!



四、              EJB方向
       EJB一個比較“高級”的方向。Sun公司曾經以此在分佈式計算領域重拳出擊。不過自從出現了Spring、Hibernation……後似乎沒落了!這 個方向單獨開源的也比較少,主要EJB是和JNDI、JDBC、JMS、JTS、JTA結合在一起的是以很少有單獨的。下面推薦兩個不過好像也要下載其它 類庫。

1. EasyBeans
       ObjectWeb的一個新的項目,一個輕量級的EJB3容器,雖然還沒有正式發佈,但是已經可以從它們的subversion倉庫中檢出代碼。代碼量比 較小600頁左右,熟讀它可以對網絡編程、架構、RMI、容器的狀態設計比較瞭解了!即學會EJB又能學習其它設計方法何樂而不爲哦!下載地 址:http://easybeans.objectweb.org/



2. OpenEJB
       OpenEJB是一個預生成的、自包含的、可移植的EJB容器系統,可以被插入到任意的服務器環境,包括應用程序服務器,Web服務器,J2EE平臺, CORBA ORB和數據庫等等。OpenEJB 被用於 Apple的WebObjects。聽起來很好,我目前沒有研究過。不知道我就不推薦了。下載地址:http://www.openejb.org/



五、              J2EE容器
       上面談了這麼多,都是J2EE的各個方向的。其實J2EE是一個規範,J2EE的產品一般要求專業提供商必須提供它們的實現。這些實現本身就是J2EE容器。市場上流行的J2EE容器很多,在開源領域流行的只有很少,很少。其中最著名的是JBoss。

1. JBoss

       在J2EE應用服務器領域,Jboss是發展最爲迅速的應用服務器。由於Jboss遵循商業友好的LGPL授權分發,並且由開源社區開發,這使得Jboss廣爲流行。另外,Jboss應用服務器還具有許多優秀的特質。

其一,它將具有革命性的JMX微內核服務作爲其總線結構;

其二,它本身就是面向服務的架構(Service-Oriented Architecture,SOA);

其三,它還具有統一的類裝載器,從而能夠實現應用的熱部署和熱卸載能力。因此,它是高度模塊化的和松耦合的。Jboss用戶的積極反饋告訴我 們,Jboss應用服務器是健壯的、高質量的,而且還具有良好的性能。爲滿足企業級市場日益增長的需求,Jboss公司從2003年開始就推出了 24*7、專業級產品支持服務。同時,爲拓展Jboss的企業級市場,Jboss公司還簽訂了許多渠道合作伙伴。比如,Jboss公司同HP、 Novell、Computer Associates、Unisys等都是合作伙伴。

      在2004年6月,Jboss公司宣佈,Jboss應用服務器通過了Sun公司的J2EE認證。這是Jboss應用服務器發展史上至今爲止最重要的里程 碑。與此同時,Jboss一直在緊跟最新的J2EE規範,而且在某些技術領域引領J2EE規範的開發。因此,無論在商業領域,還是在開源社區,Jboss 成爲了第一個通過J2EE 1.4認證的主流應用服務器。現在,Jboss應用服務器已經真正發展成具有企業強度(即,支持關鍵級任務的應用)的應用服務器。

       Jboss 4.0作爲J2EE認證的重要成果之一,已經於2004年9月順利發佈了。同時,Jboss 4.0還提供了Jboss AOP(Aspect-Oriented Programming,面向方面編程)組件。近來,AOP吸引了大量開發者的關注。它提供的新的編程模式使得用戶能夠將方面(比如,事務)從底層業務邏 輯中分離出來,從而能夠縮短軟件開發週期。用戶能夠單獨使用Jboss AOP,即能夠在Jboss應用服務器外部使用它。或者,用戶也可以在應用服務器環境中使用它。Jboss AOP 1.0已經在2004年10月發佈了。 很有名吧!可以下載一個用一下,下載地址:http://www.jboss.org/

       關於JBoss的使用資料也非常多,甚至比商業軟件的還多。有機會研究吧!

2. JOnAS
       JOnAS是一個開放源代碼的J2EE實現,在ObjectWeb協會中開發。整合了Tomcat或Jetty成爲它的Web容器,以確保符合 Servlet 2.3和JSP 1.2規範。JOnAS服務器依賴或實現以下的Java API:JCA、JDBC、JTA 、JMS、JMX、JNDI、JAAS、JavaMail 。下載地址:http://jonas.objectweb.org/



3.Apache Geronimo
       Apache Geronimo 是 Apache 軟件基金會的開放源碼J2EE服務器,它集成了衆多先進技術和設計理念。 這些技術和理念大多源自獨立的項目,配置和部署模型也各不相同。 Geronimo能將這些項目和方法的配置及部署完全整合到一個統一、易用的模型中。作爲符合J2EE標準的服務器,Geronimo提供了豐富的功能集 和無責任 Apache 許可,具備“立即部署”式J2EE 1.4容器的各種優點,其中包括:

1.        符合J2EE1.4標準的服務器 。

2.        預集成的開放源碼項目 。

3.        統一的集成模型 。

4.        可伸縮性、可管理性和配置管理功能。

       我一直比較推薦Apache的產品。主要是可以任意自由地使用。下載地址:http://incubator.apache.org/projects/geronimo/



六、              其它
       講了這麼多大家可能很厭煩了!是不是很多很多啊!其實不然,我們不會的太多太多了!不會的太多太多了。不管你是不是J2EE高手,還是J2SE高手,有些 東西你要絕對很精明的。例如:1.Java的Collections Framework就是java的數據結構了,不僅要喫透它,還要能按照需要擴展它,利用其思想創建一個自己的數據結構。2.網絡編程肯定要會吧,現在以 及以後很多程序都是不在同一臺機器上的,不會網絡怎麼行哦!3.IO肯定要會的吧!你的程序難道不用輸入輸出數據啊!整個IO包加NIO也有600多頁的 源代碼哦!4.JDBC你要會吧!數據庫都不會,在你的企業應用中你的數據又保存到哪裏啊!文件中――太落後了吧!典型的沒有學過J2EE。儘管數據庫背 後也是採用文件保存的。5.Serverlet、JSp你要是做網頁做網站,肯定要做到。問你一個簡單的問題,網頁中如何實現分頁啊!有具體方法的就在本 文章後發言吧!6. Ant要會吧!java語言中發佈的工具,類似與c中的make工具。7.JUnit用過吧!單元測試軟件。你不要啊!你的軟件就沒有bug!你牛!(建 議大家研究研究其源代碼,很有用的框架,包含大量的設計模式,源代碼不到100頁!看了只能感嘆――高手就是高手)細心的朋友可以看到在你使用的很多 IDE工具中都有JUnit哦!就是它。

       一切的一切纔剛剛開始!有興趣,有需要你可以研究數據庫連接池的框架,如:C3P0、Jakarta DBCP、 DBPool….可以研究J2EE框架Spring……. Web框架Struts……持久層框架Hibernate…..甚至開發工具Eclipse…..Sun領導的點對點通信的JXTA…..報表工具 JFreeChart、JasperReports…..分佈式網絡編程的CORBA、網絡通信的JGROUPS、XML解析的xerces…..(在不 經意間開源已經步入你的電腦,不信啊!你JDK的安裝目錄jdk1.6.0 src com sun org apache就是Xerces,一個XML解析的著名的開源 項目)

       不管怎麼樣我還是建議從基本的做起,學精J2SE,熟讀它的源碼,準確瞭解其設計理念,然後分頭擊破J2EE――一口喫不成一個胖子!不要貪多貪廣!腳踏實地就可以了!

      

       假如你是初學者,請你到我的博客看那些我給你推薦的書籍!見《Java 推薦讀物與源代碼閱讀》這篇文章。假如你是一位J2SE高手想進入J2EE方向,請先了解設計模式,然後搞懂其各個方向的API,接着可以研究各個方向的 開源項目提高自己!充實自己!接着就是服務於你的行業,做你想幹的事!謝謝!你已經是高手了,不需要來聽我嘮叨了!不過我還是懇切希望你能到我的博客給我 嘮叨!

Java 推薦讀物與源代碼閱讀
                                                    江蘇無錫  繆小東

1. Java語言基礎
    談到Java語言基礎學習的書籍,大家肯定會推薦Bruce Eckel的《Thinking in Java》。它是一本寫的相當深刻的技術書籍,Java語言基礎部分基本沒有其它任何一本書可以超越它。該書的作者Bruce Eckel在網絡上被稱爲天才的投機者,作者的《Thinking in C++》在1995年曾獲SoftwareDevelopment Jolt Award最佳書籍大獎,《Thinking in Java》被評爲1999年Java World“最愛讀者歡迎圖書”,並且贏得了編輯首選圖書獎。作者從1986年至今,已經發表了超過150篇計算機技術文章,出版了6本書(其中4本是關 於C++的),並且在全世界做了數百次演講。他是《Thinking in Java》、《Thinking in C++》、《C++ Inside & Out》《Using C++》和《Thinking in Patterns》的作者,同時還是《Black Belt C++》文集的編輯。他的書被讀者稱爲“最好的Java參考書……絕對讓人震驚”;“購買Java參考書最明智的選擇”;“我見過的最棒的編程指南”。作 者的非凡才華,極其跨越語言的能力,使作者被選爲Java發展10年間與Java關係最密切的10個人物之一。

    《Thinking in Java》講述了Java語言的方方面面,很多Java語言的老手都評價“這是一本將Java語言講得相當醜陋的書”。該書談及了java語言的很多細節,每一個方面都是相當深刻的。通過本書你可以看到“醜陋的”java語言。

    網絡上關於java語言講解的視頻很多很多,其中不凡有垃圾。《翁愷—JAVA語言》可能是你學習java語言基礎的唯一選擇,該講座基本按照 《Thinking in Java》這本書講解,其中不凡有翁老師的很多有意思的笑話。我很幸運學習就是從此視頻開始的。內容包括30講,我總共看了3遍。

    不過,對於初學者我不太推薦使用《Thinking in Java》,我比較推薦Prentice Hall PTR 的《Core Java 2》國內稱爲《Java 2 核心技術》,目前是第七版。網絡上大家都可以下載到電子版。Oreilly的《Java in a nutshell》也是一個不錯的選擇。讀完以上兩本後,你可以看看翁愷老師的視頻,接着可以研究《Thinking in Java》了。



2. Java數據結構
    市面上關於Java數據結構的書本身就很少很少。大致有APress 的《Java Collections》,Jones 和Bartlett 的《Data Structures in Java》、《Object-oriented Data Structures Using Java》以及Prentice Hall 出版的《Data Structures and Algorithms in Java》 (Dec 19, 2005)還有一本就是《Data Structures And Algorithms With Object-oriented Design Patterns In Java》。很幸運我的第一本英文書就是APress 的《Java Collections》(本書在國內可能根本就沒有中文版――只能下載英文版了),很不錯,講得很有條例、很簡單,是一本完完全全Java Collections API介紹的書籍,其中不凡有擴展API的例子。這是我推薦你學習java數據結構的唯一一本好書。其它的Jones 和Bartlett的那兩本國內好像有一本中文版,想看你也可以看看。

    在學習完API後,你可以看看java.util包中對應的類了。不過只有在學習過設計模式後你纔有可能完全理解整個Java Collections Framework。Java Collections Framework使用了很多著名的設計模式如:迭代器(Iterator)模式,工廠方法模式、裝飾器模式、適配器模式等等。通過研究 java.util包中數據結構的源代碼,你可以知道臭名昭著的Properties類的設計了,同時可能基本具備設計簡單的數據結構的能力了。

    所謂學習無止境,學習完Sun提供了Java Collections Framework後,你可以研究Apche的另一個Java Collections Framework,很有意思哦。互爲補充的兩個Framework。



    在大家學習、研究Java Collections之前,我提示一下Java Collections主要包括以下三部分:接口(Interface)、實現(Implemention)和算法(Algorithm)。

1.     接口主要有List、Set、Queue和 Map。List 、Se t和Queue是 Collection接口的子接口。

2.     實現主要是實現這些接口的具體類。如實現List接口的ArrayList、LinkedList、Stack和Vector;實現Set接口的 HashSet、TreeSet 和LinkedHashSet;實現Queue接口的PriorityQueue、SynchronousQueue等等;實現Map接口的 HashMap、TreeMap、Hashtable、Properties、WeakHashMap等等。

3.     算法主要是由Arrays類和Collections類提供的,它是整個Java Collection Framework算法的核心。支持各種類型的排序,查找等常用操作。

    Java Collections中包含兩個版本的數據結構,主要是原先的支持同步的數據結構和後來不支持同步的數據結構。

    Java Collection Framework在使用Comparator和Comparable接口支持排序。同時提供新舊兩個版本的迭代器Iterator和Enumeraton,以及它們如何轉換等等。

    在java.util包中的Obserable接口和Observer類是考察者模式的核心。

    ……

   

3. Java IO
    市面上關於IO的書籍也僅僅只有Oreilly出版社的兩本,都是Elliotte Rusty Harold的著作。兩本書的風格基本一致,推薦閱讀是第一版的《Jvava I/O》,講得比較淺顯,內容相對比較集中,實例也很多。第二版今年5月國外才出版,很有幸我在網絡上下載了第二版,講得極其詳細――726頁的大塊頭 (我化了兩個星期),這次將NIO和IO和在一起,還包括J2ME部分的,不過串口、並口通信部分好像類庫支持不夠,自己不能實際操作。

    與第一版的《Jvava I/O》一起的Oreilly還有一本《Jvava NIO》,也是很不錯的哦。

    大家在依次閱讀完《Jvava I/O》以及《Jvava NIO》後,可以研究java.io包中的源代碼了。在大家研究源代碼前我給點提示:

    Java的io包主要包括:

1.     兩種流:字節流(byte Stream)和字符流(character stream),這兩種流不存在所謂的誰代替誰、誰比誰高級之說,它們互爲補充,只是側重點不同而已。

2.     兩種對稱:1.字節流、字符流的對稱;2.輸入、輸出的對稱。

3.     一個橋樑:將字節流轉變爲字符流的InputStreamReader和OutputStreamWriter。

    其中必須注意:

1.     PipedInputStream和PipedOutputStrem是兩個比較有趣的類。

2.     支持Buffered的流是我們經常使用的類。

3.     裝飾器(Decorator)模式在java最著名的應用就是用於io的設計。仔細研究各個Filter流與具體流的關係,多看設計模式的書籍。相信你會有所所獲。

4.     學習好io包,是研究net包,rmi包……的基礎哦!



4 . Java數據庫
       數據庫的書籍太多太多了,也是太爛太爛了!這方面的書我基本都研究過,推薦的你就看看Apress的《JDBC Recipes A Problem Solution Approach 》很不錯,國外2005年底纔出版,(國內好像沒有中文版,不過出了中文版也不一定值得看――國內經常將國外的書翻譯得一塌糊塗、不堪入目)不過我們真的 很幸運,網絡上有電子版的。值得一看。推薦我看的第一本比較滿意的――Wiley出版的《Java Database Bible》,講得很不錯!Sun公司自己的關於JDBC API介紹的那一本《JDBC API Tutorial andRefernece》也不錯。我第二本JDBC的就是研究的這套API。

    不過目前這些書都是一些相對比較浮淺的API應用的書籍。有機會我會給大家帶來介紹JDBC API以及JDBC實現內部細節的書!我儘快努力,同時希望得到大家的支持!

    順便給學習JDBC的朋友一點提示:

    JDBC的學習和使用主要是這套API,其使用過程也是極其簡單,下面是使用JDBC的一般流程:

1.     加載某個數據庫的驅動(Driver類),通常使用Class.forName(“驅動的類名“);

2.     連接數據庫――

            Connection con = DriverManager.getConnection(url,username,password);

3.     得到會話――Statement stmt = con.createStatement();

4.     執行操作――Result rs = stmt.executeQuery(“SQL查詢語句”);

5.     處理結果――

    while(rs.next()){

        String col1 = rs.getString(1);

        ……

    }

    簡單吧!整個JDBC中可以變化的一般是:

1.       可以由Connection對象創建Statement、PreparedStatement和CallableStatement創建三種類型的Statement。

2.       可以創建多種類型的ResultSet:支持單向移動和個自由移動;可更新的和不可更新的;支持不同等級的交易的…..

3.       數據輸入的批處理。

4.       結果集中特殊類型(Blob、Clob、Arrary和Ref、Struct)列的操作。

5.       這些特殊類型的錄入數據庫。

6.       javax.sql包中特殊結果集(CachedRowSet、JdbcRowSet、WebRowSet)的操作。

7.       其它的就是一個DataSource了,也很簡單!一個J2EE中的被管理對象

    簡單吧!相信大家很快就會征服JDBC。



5. Java 網絡編程
    網絡編程――一個神祕的、充滿挑戰的方向。不過在談Java網絡編程之前首先感謝Sun公司的開發人員,因爲它們天才的設想,充滿智慧的架構,使廣大java程序員學習java網絡編程變得異常簡單。

    Java網絡編程方面的書,我推薦O'Reilly的《Java Network Programming》,目前已經第三版了,以前的版本市面上肯定有!網絡上早有第三版的電子版,國外2004年出版,706頁哦!講得很全,比較深 入,太深入的可能由於Sun有些東西沒有完全公開,所以也就不好講了,有興趣的可以下載看看!第二本還是O'Reilly 1998年出版的《Java distributed computing 》,基礎部分寫得比較詳細,後面的實例還是值得研究的。

    在大家閱讀這些書之前,給大家一點提示:

    java網絡編程其實相對比較簡單,入門也很快很快。java網絡編程主要包括兩個部分:1.Socket;2.URL部分。不過第二部分也完全建立在第一部分的基礎上。

1.       Socket包括客戶端的Socket和服務器端的ServerSocket。還有就是DatagramSocket和DatagramPacket,它對應於UDP通信協議。 總之,Socket部分是建立其它高級協議的基礎。

2.       URL類是一個網絡資源定位器,通常和具體的網絡協議如HTTP,FTP,Telnet……相關。通過該類可以連接網絡上的資源,通過其 openStream可以以io包中的流(InputStream)的形式讀取網絡資源;通過其OpenConnection方法,可以打開一個連接,在 此連接上可以不僅可以完成讀的操作,還可以完成寫的操作。

    Java的網絡編程大體包括以上兩部分。網絡編程和IO以及多線程部分非常密切,在學習此部分前大家一定對這兩部分了解比較透徹。

    學習了以上部分你可以研究java.net包中的與此相關的源代碼了!研究所有的源代碼還爲時尚早。在整個net包中包 含:ContentHandlerFactory、URLStreamHandlerFactory、URLStreamHandler、 URLClassLoader等輔助類,它們構成了java.net網絡編程的框架,通過研究其源代碼,你不僅可以快速理解java.net包,還可以爲 以後擴展該包打下基礎,甚至可以將此思維方式運用到自己的項目中。

    到此爲止你對java.net包應該才瞭解60%,還有一部分你可以使用JDecompiler之類的反編譯軟件打開你JDK安裝目錄下/jdkxxx /jre/lib目錄中的rt.jar,用WinRAR之類的軟件打開它的sun.net包,反編譯所有的文件,它是URL類工作的細節。當研究完該 sun.net包,你就會對整個網絡編程很熟悉很熟悉了。

    一切看起來我們已經對網絡編程很精通了。其實不然,剛剛開始而已,要想深入,請繼續吧!網絡上很多優秀的網絡編程庫甚至軟件可以爲我們“添加功力”。如 Apache的HttpCore和HTTPConnection 是兩個和HTTP協議相關庫;JGroups是研究分佈式通信、羣組通信的必讀庫;接着我們可以研究P2P的軟件包,如Sun公司的JXTA,它可能是 java平臺點對點通信未來的標準哦!接着你可以研究成熟得不得了,使用極其廣泛得P2P軟件Azureus!www.sourceforge.net可 以下載到!

    千里之行始於足下!Just do it !(目前我也只研究了net包,其它的會在不久的將來繼續深入。Sun公司因爲某些原因沒有公開net的其它實現細節,在其允許將其源代碼以文字的形式加 以研究,以及允許將其沒有公開的實現寫入書中時,我很希望能出一本java網絡編程的書籍,以飧廣大讀者!!)

6. Servlet和JSP
    Servlet、JSP的書也是滿地都是!值得推薦的也僅僅兩三本。實推Addison Wiley的《Servlets and JavaServer pages :The J2EE Technology Web Tier》,又是一本很厚的哦!國外2003年出版、784頁,講得比較全,例子也很多,特別是第八章Filter,舉了幾個不錯的例子。其它所有我看到 的關於Servlet和JSP的書都沒有如此深入的!(可能有我沒有看到而已)。O’reilly的《Java Servlet Programming》和《Java Server Pages》相對比較好懂一些,可以讀讀!

    在大家學習Servlet和Jsp之前我還是要提醒一下:

    本質上說Servlet就是一個實現Servlet接口的、部署於服務器端的服務器端的程序罷了!它可以象寫其它任何java應用程序一樣編寫,它可以操作數據庫、可以操作本地文件、可以連接本地EJB……編寫Servlet程序的一般流程爲:

1.     繼承一個HttpServlet類;

2.     覆蓋其doGet、doPost方法;

3.     在覆蓋方法的內部操作方法參數HttpServletRequest和HttpServletResponse。

4.     讀取請求利用HttpServletRequest。利用HttpServletRequest你可以操作Http協議的協議頭、可以得到請求的操作方 法、可以得到請求的路徑、可以得到請求的字符串、以及和請求客戶相關的信息,更主要的你可以得到Cookie和HttpSession這兩個對象。

5.     利用Cookie你可以操作“甜心”對象或者將其寫入HttpServletResponse中。

6.     向客戶輸出信息可以使用HttpServletResponse。使用HttpServletResponse可以寫入各種類型的協議頭、可以增加Cookie、可以重定向其它URL、可以向客戶發送Http協議的狀態碼。

7.     利用HttpSession在會話內完成你想實現的任何功能。

    同時Servlet還提供了一些事件和事件監聽器(簡單的觀察者模式而已)。還有就是過濾器(Filter)和包裝器(ServletRequestWrapper、ServletResponseWrapper)――簡單的流的使用和裝飾器模式的使用。

    學習Sevlet、JSP必然要部署到服務器中,記住通常文件部署的步驟和參數的設置以及在程序中如何使用就可以了。

    完全理解Servlet後,學習jsp相對比較容易了!Jsp完全建立在Servlet的基礎上,它是爲了迎合那些喜歡在Html文檔中嵌入腳本(如:PHP之類的網頁編程語言)的程序員的需要罷了!學起來也相當的容易!

    一切看起來似乎那麼的風平浪靜,簡單好學!簡單的表象背後有其複雜的機理。要想對Servlet和Jsp徹底研究,你得研究Tomcat等開源軟件的具體 實現。它無非就是一個服務器,在客戶利用網頁通過HTTP協議向服務器發送請求後,服務器將此HTTP請求轉化爲相應的 HttpServletRequest對象,調用你編寫的Servlet罷了,在你的Servlet中你肯定操作了此 HttpServletRequest了吧,同時操作了HttpServletResponse了吧,服務器就將此 HttpServletResponse按照HTTP協議的要求利用HTTP協議發送給你的瀏覽器了!在服務器端的Jsp網頁在被客戶請求 後,Tomcat會利用編譯軟件,使用javax.servlet.jsp包中的模板,編譯此jsp文件,編譯後就是一個Servlet!以後的操作和 Servlet完全一樣哦!

    在Servlet和Jsp的基礎上出現了,所謂的高級技術:JSTL,Struts……無非就是一些標籤和MVC模式的使用。

    繼續前進吧!勝利就在前方!!



7. 多線程
    一個看起來很神祕,卻很容易上手、很難精通的方向!

    我推薦兩本我感覺很好的書籍。首先是我第一本能上手看的這方面的書,Sams 1998年出版的《Java Thread Programming》,寫得暴好,很容易讀懂,我有空還時常看當時的筆記!要知道怎麼好你自己看吧!第二本OReilly三次出版的《Java Threads》,最新是2004版,國內好像有中文版,推薦你還是看英文版的吧!書中談到了與多線程相關的N個方向,如IO、Swing、 Collection等等。

    給大家一點提示吧!java類庫中與多線程相關的類不是很多,主要有:Thread、ThreadGroup以及ThreadLocal和 InheritableThreadLocal四個類和一個Runnable接口;關鍵字synchronize、volatile ;以及Object對象的wait、notify、notifyAll方法!

1          Thread是多線程的核心類,提供了一系列創建和操作多線程的方法。

2          ThreadGroup是一個管理Thread的工具類。

3          ThreadLocal和InheritableThreadLocal爲Thread提供了一個類似保險箱功能的存儲線程對象的類!

4          Runnable不用說了吧!

5          synchronize是同步方法和同步塊的核心哦!多個線程調用此方法時,只有一個線程可以使用此方法,其它方法阻塞,從而保證被操作對象內部狀態完整 性。某個線程調用帶有synchronize的方法或塊時會得到該對象的對象鎖,完成塊中的操作後釋放此對象鎖,從而其它對象可以繼續操作。

6          wait、notify、notifyAll提供了有效的等待/通知機制。Java語言中每一個對象都有一個休息室,任何線程在其操作的對象的狀態不滿足 的情況下,在該對象的休息室中休息,釋放對象鎖;當其它線程操作該對象後,喚醒休息室中的線程,它們再檢查條件,當條件滿足後,執行相應的操作。

    多線程大致就這麼多基礎的!簡單嗎!這對於一個真正的程序員應該是不夠的,真正對多線程要有所掌握,請您研究java.util.concurrent包 吧!大師Doug Lea的作品,原先是一個開源的一致性編程的庫,後來被Sun公司併入java類庫。作者的網站上也有另外一個版本的該類庫!值得研究的好東 西!Hibernation、OpenJMS等開源軟件都使用了此包!

   

8. 設計模式
    談到設計模式很多人多會推薦GOF的那本,該書在Amzon上是五星級的推薦書籍。不過對於學習java沒多久的、特別是java初學者,我很不推薦這本書。主要是該書的例子基本都是C++的,很多細節沒有講述得足夠清楚。

    我給大家推薦的第一本是閻宏博士的《Java 與模式》,它是第一本中國人自己寫的關於設計模式的書籍,寫的比較有趣,融合了很多中華民族的文化和觀念,例子、類圖都比較多,且相對簡單!非常不錯的入門書籍――又是大塊頭哦!

    其次我推薦Wiley出版社出版的《Pattern In Java》一套三本,我纔看了第一本,好像第二本不怎麼樣,第三本還不錯!

    第三本是中文翻譯版的關於多線程模式的(很難得的中文翻譯版)中國鐵道出版社2003年出版的《Java多線程設計模式》,將多線程模式講得非常淺顯,配有大量的圖例,每章都有習題,最後有答案!我研究多線程模式就是由它開始的!

    第四本,今年出版的Head First系列的《Head First Design Pattern》,秉承Head First系列圖書的優點,大量的類圖、豐富的實例、有趣的註解,值得購買!

    其次在J2EE方向你可以研究閱讀Addison Wesley 2002年出版的《Patterns of Enterprise Application Architecture》,衆多大腕的作品,講企業消息集成的!Sun提供的《J2EE PATTERNS SL500》也很好!晚了推薦那一本Amzon 4星半的《Holub on patterns》,大師的作品,提供了,很值得研究的例子,不過對上面四本不是很熟悉的讀者,最好不要讀它!可能會讓你比較累!

    我學習設計模式經過一段很曲折的路線,前前後後大約看了20本,閻宏博士的《Java 與模式》我看了4遍,還排除我第一次基本沒看懂的看!記得研一時老師給我們講了GOF的那本,作爲選修課,我和它們計算機系的碩士、博士們一起,到最後一 個班40-50個人,不超過3個人明白,我也沒有明白任何一點(基礎差吧――主要我對C++語言一點都不瞭解),憑我不伏輸的性格,我認爲我對java語 言理解還可以,我就借了《Java 與模式》,結果還是基本沒看懂。很有幸的是讀研三時,聽過了上交大饒若楠老師關於Java OOP語言的講座,我懂了組合書籍模式等三種設計模式後,對其它模式有了強烈的興趣和要征服它的願望!工作後我買的第一本就是《Java 與模式》,第一遍花了2個月研究了這個1000多頁的大塊頭,後來第三遍15天左右就可以搞定,筆記記了一大本!從此一發不可收拾。

    選對書、埋頭研究。相信很快就會入門的!



    學習Java語言8個簡單的部分,這只是我們研究Java語言的開始!這些都懂了充其量一個java程序員而已,後面的路很長很長!我們可以繼續研究數據 庫實現的源代碼、Servlet服務器的源代碼、RMI、EJB、JNDI、面向方面編程、重構、ANT工具、Eclipse工具、Spring工具、 JBoss、JOnAS、Apache Geronimo等J2EE服務器!研究了這些你可能會成爲一個出色的J2EE Architecture!你可以繼續研究剖析器、編譯器、JNODE(java寫的操作系統)……



    感謝大家有此耐心,聽我羅羅嗦嗦大半天!感謝大家的閱讀,感謝羣裏的朋友!這篇文章主要應羣裏朋友的呼聲――不知道如何選書、不知道從何看起!大半天的功夫完成趕此文章,字句上難免有失誤,同時由於能力有限不凡有錯誤!請閱讀後批評指正!

    上面基本是我研究java語言的順序,以上書籍都是我閱讀過的,不存在替任何出版社宣傳的成分!有的方法可能不適合你,假如你能收穫一點,兩點甚至更多,請你不要吝嗇推薦給你的朋友――共同學習!

    感謝大家的閱讀;感謝互聯網的設計者;感謝java的設計師;感謝www.open-open.com和www.sourceforge.net網站!

一、規範存在的意義

    應用編碼規範對於軟件本身和軟件開發人員而言尤爲重要,有以下幾個原因:

    1、好的編碼規範可以儘可能的減少一個軟件的維護成本 , 並且幾乎沒有任何一個軟件,在其整個生命週期中,均由最初的開發人員來維護;

    2、好的編碼規範可以改善軟件的可讀性,可以讓開發人員儘快而徹底地理解新的代碼;

    3、好的編碼規範可以最大限度的提高團隊開發的合作效率;

    4、長期的規範性編碼還可以讓開發人員養成好的編碼習慣,甚至鍛煉出更加嚴謹的思維;

二、命名規範

    1、一般概念

        1、儘量使用完整的英文描述符

        2、採用適用於相關領域的術語

        3、採用大小寫混合使名字可讀

        4、儘量少用縮寫,但如果用了,必須符合整個工程中的統一定義    

        5、避免使用長的名字(小於 15 個字母爲正常選擇)

        6、避免使用類似的名字,或者僅僅是大小寫不同的名字

        7、避免使用下劃線(除靜態常量等)

   2、標識符類型說明

        1、包( Package )的命名

            Package 的名字應該採用完整的英文描述符,都是由一個小寫單詞組成。並且包名的前綴總是一個頂級域名,通常是com,edu,gov ,mil ,net ,org 等<如:com.yjhmily.test>

        2、類( Class )的命名

            類名應該是個一名詞,採用大小寫混合的方式,每個單詞的首字母大寫。儘量保證類名簡潔而富於描述。使用完整單詞,避免縮寫詞 ( 除非工程內有統一縮寫規範或該縮寫詞被更廣泛使用,像 URL , HTML)<如: FileDescription>

        3、接口( Interface )的命名

            基本與 Class 的命名規範類似。在滿足 Classd 命名規則的基礎之上,保證開頭第一個字母爲 ”I” ,便於與普通的 Class 區別開。其實現類名稱取接口名的第二個字母到最後,且滿足類名的命名規範;<如: IMenuEngine>

        4、枚舉( Enum )的命名

            基本與 Class 的命名規範類似。在滿足 Classd 命名規則的基礎之上,保證開頭第一個字母爲 ”E” ,便於與普通的 Class 區別開。<如: EUserRole>

        5、異常( Exception )的命名

            異常( Exception ) 通常採用字母 e 表示異常,對於自定義的異常類,其後綴必須爲 Exception<如: BusinessException>

        6、方法( Method )的命名

            方法名是一個動詞,採用大小寫混合的方式,第一個單詞的首字母小寫,其後單詞的首字母大寫。方法名儘可能的描述出該方法的動作行爲。返回類型爲 Boolean 值的方法一般由“ is ”或“ has ”來開頭<如: getCurrentUser() 、 addUser() 、 hasAuthority()>

        7、參數( Param )的命名

            第一個單詞的首字母小寫,其後單詞的首字母大寫。參數量名不允許以下劃線或美元符號開頭,雖然這在語法上是允許的。參數名應簡短且富於描述。<如: public UserContext getLoginUser(String loginName);>      

        8、常量字段 ( Constants )的命名

            靜態常量字段( static final ) 全部採用大寫字母,單詞之間用下劃線分隔;<如: public static final Long FEEDBACK;public static Long USER_STATUS;>

三、註釋規範

        一個很好的可遵循的有關注釋的經驗法則是:

            問問你自己,你如果從未見過這段代碼,要在合理的時間內有效地明白這段代碼,你需要一些什麼信息???

        1、一般概念

            1、註釋應該增加代碼的清晰度

            2、保持註釋的簡潔

            3、在寫代碼之前或同時寫註釋

            4、註釋出爲什麼做了一些事,而不僅僅是做了什麼

        2、註釋哪些部分

            1、Java 文件:必須寫明版權信息以及該文件的創建時間和作者;

            2、類:類的目的、即類所完成的功能,以及該類創建的時間和作者名稱;多人一次編輯或修改同一個類時,應在作者名稱處出 現多人的名稱;

            3、接口: 在滿足類註釋的基礎之上,接口註釋應該包含設置接口的目的、它應如何被使用以及如何不被使用。在接口註釋清楚的前提下對應的實現類可以不加註釋;

            4、方法註釋: 對於設置 (Set 方法 ) 與獲取 (Get 方法 ) 成員的方法,在成員變量已有說明的情況下,可以不加註釋;普通 成員方法要求說明完成什麼功能,參數含義是什麼且返回值什麼;另外方法的創建時間必須註釋清楚,爲將來的維護和閱讀 提供寶貴線索;

            5、方法內部註釋: 控制結構,代碼做了些什麼以及爲什麼這樣做,處理順序等,特別是複雜的邏輯處理部分,要儘可能的給出 詳細的註釋;

            6、參數: 參數含義、及其它任何約束或前提條件;

            7、屬性: 字段描述;

            8、局部 ( 中間 ) 變量: 無特別意義的情況下不加註釋;

        3、註釋格式

            遵循工程規定的統一註釋格式,一般情況下會以 codetemplates.xml 格式的文件導入 IDE(Eclipse) 或者用Eclipse默認的;

四、代碼格式規範

            遵循工程規定的統一代碼格式,一般情況下直接使用 IDE(Eclipse) 自帶的默認代碼格式對代碼進行格式化;

五、其他規範

       JSP 文件命名

            採用完整的英文描述說明 JSP 所完成的功能,儘可能包括一個生動的動詞,第一個字母小寫,如: viewMessage.jsp 、 editUser.jsp 等。

六、工程特有命名規範

        1、持久層

            1、 Hibernate 映射文件及實體

                與數據庫表名稱完全對應;

                如: Advertisement.hbm.xml 、 Advertisement.java

            2、數據訪問 DAO

                DAO 接口和實現類名稱必須完全符合正常接口和實現類的命名規則,且最後以 ”DAO” 結尾

                DAO 內的數據訪問方法必須足夠抽象的描述出對數據庫的基本 CRUD 操作;

                如: ICrossAdDAO( 接口 ) 、 CrossAdDAO( 實現類 )         

           3、各種操作數據庫的 HQL 配置文件

                HQL 文件的個數原則上與系統的 Services 層的服務個數相等,且以服務名稱命名 HQL 文件;

                如: resource.hbm.xml

        2、服務層

            1、服務接口和實現

                服務接口和實現類必須完全符合正常接口和實現類的命名規則;以工程定義的服務名爲主體,並統一以 ”Serv” 結尾

                如: IResourceServ( 服務接口 ) 、 ResourceServ( 接口實現類 )

            2、服務接口方法

                方法名是一個動詞,採用大小寫混合的方式,第一個單詞的首字母小寫,其後單詞的首字母大寫。方法名儘可能的描述出該 方法的動作行爲。

                返回類型爲 Boolean 值:用“ is ”或“ has ”來開頭

                得到某數據: get+ 數據描述名詞複數 + 數據類型;

                得到所有數據: get+All+ 數據描述名詞複數 + 數據類型;

                通過 XXX 得到 / 查詢某數據: get/query+ 數據描述名詞複數 + 數據類型 +By+ 條件;

                添加某數據: save/add+ 數據描述名詞 ()

                更新某數據: save/update+ 數據描述名詞;

                刪除某數據: delete/remove+ 數據描述名詞;

            3、業務對象

                業務名稱 +BO

            4、查詢參數對象

                凡是繼承 Abst***QuerySpec 的查詢參數類全部滿足以下規則:

                Query+ 所要查詢的數據描述名詞 +Spec

                作爲參數傳入時,參數名必須爲:所要查詢的數據描述名詞 +Spec

                如: QueryProgramSpec;

        3、MVC 層          

            1、Action 控制層

                Action 類名:功能模塊名稱 +Action ;

                Actoin 方法名稱儘可能的描述出頁面遷移的去向

                如: LoginAction( 登錄用 action) , toWelcome( 轉向歡迎頁的 action 方法 )

            2、資源文件

                系統全局資源文件: globalMessages_+ 字符編碼類型 +.properties

                功能模塊內部的資源文件: package.properties

        4、Spring 配置文件

            1、Action 相關配置文件

                文件目錄: WebRoot/WEB-INF/spring/action/ 功能模塊名稱 +_ApplicationContext.xml

            2、Services 相關配置文件

                文件目錄: WebRoot/WEB-INF/spring/services/Services_ApplicationContext.xml

            3、全局性配置文件

                文件目錄: WebRoot/WEB-INF/spring/工程名+_ApplicationContext.xml

        5、JSP 文件

            採用完整的英文描述說明 JSP 所完成的功能,儘可能包括一個生動的動詞,第一個字母小寫,如: viewMessage.jsp、editUser.jsp 等。
2008 - 12 - 08

Java讀書目錄

關鍵字: java
統計一下,爭取每年能讀3本書

01.《成功通過Sun認證 Java2程序員考試》
02.《Java實例技術手冊》
03.《數據結構與算法分析--JAVA 語言描述》
04.《Junit In Action》
05.《設計模式精解》

06.《SCWCD認證專家應考指南》
07.《精通Struts》
08.《精通Hibernate》
09.《Spring In Action》
10.《Webwork In Action》
11.《J2EE核心模式》

12.《Ajax基礎教程》
13.《Ajax In Action》
14.《應用RAILS進行敏捷WEB開發》

15.《ECLIPSE SWT/JFACE開發實戰精解》
2008 - 12 - 04

我所喜歡的Java書籍作者(國內)

文章分類:IT生活 關鍵字: java 書籍
首先說明,我不是書託,爲了避免這種嫌疑,我只評論一下2007年以前出版的書籍作者。其實那些作者也不需要我這種無名小卒來宣傳,只是我決心以後儘量只看英文電子版和影印版的Java書籍了,所以寫下點東西,留個紀念。

看了很多本Java書籍,其中國內的作者有這樣幾位給我留下了深刻的印象:

    第一位,可以算得上是我Java的入門導師,張洪斌。我在2003年剛開始學習Java的時候,是伴隨着考SCJP認證爲目的的。在學校的圖書館裏翻了很 久,終於找到了一本《成功通過SUN認證 JAVA2程序員考試》,這本書可能是當時僅有的跟SCJP認證有關的書了。認真讀下去,發現張老師的寫作風格非常幽默,講起概念也非常清晰。最後我以高 分通過了SCJP,很有一種以後只買張老師的書的衝動。後來我也又買了一本《例釋JAVA2企業版(J2EE)程序設計》,主要講解的是EJB2.1的內 容,可是實習的時候才發現EJB中除了無狀態會話Bean以外,其他的部分很少有公司用,我只看了幾頁就不得不放到一旁,學習其他更有用的知識了。以後張 老師出的書也都是有關Jboss,Websphere,Weblogic的,而我用的最多的是Tomcat,所以以後也再也沒有買來看。

    第二位,是我在學習Design Pattern的時候,最欽佩的人,彭晨陽。那個時候爲了準備SCJD認證考試,不得不學習Design Pattern,受GoF的影響,我一直覺得Design Pattern就是天書中才該有的內容(誰讓他們用C++去講解設計模式啊,簡直是難上加難)。但是無意中搜到了彭大俠的網站jdon,發現彭大俠可以將 Design Pattern用最通俗易懂的方式講解出來,並融入到自己的jive論壇的設計當中,對彭大俠的崇拜如滔滔江水,連綿不絕(不要扁我)。圖書館中有一本彭 大俠編寫的《JAVA實用系統開發指南》,我借了幾次,都沒有辦法讀完。不是因爲書不好,是因爲書中沒有提供完整的源代碼,而我當時的能力又沒有辦法完全 領悟其中的奧妙,所以只能放棄。後來還是下了一本《JAVA實用系統開發指南》的電子版,留着以後備用。
   
    第三位,也是唯一一位的女作者,孫衛琴。在很多人眼中,女程序員的技術可能比不上男程序員,但孫JJ用她寫的書證明了她技術的功底。我有兩本她寫的書: 《精通Struts》《精通Hibernate》。兩本書都是在2005年Java十年慶典的時候,用Sun論壇上的積分兌換的。(2005年是我的幸運 年,我不但得到了James Gosling的親筆簽名書籍, 而且還和James Gosling合影留念)。正好我2006年開始工作的時候,是用SSH來做項目,所以有機會對兩本書詳細的閱讀了一下。感覺孫JJ的講解非常詳細,而且 在書中也描述了很多在實際項目中會遇到的技術點。唯一遺憾的是《精通Hibernate》中Hibernate的版本是Hibernate2,2006年 的時候,已經出Hibernate3了,而且2和3的變化非常大,所有的包名都變了,我用Hibernate2進行學習,Hibernate3進行開發, 升級步驟讓我頭疼了好一陣。後來孫JJ又出了很多書籍,不過都是一些Java基礎教程,我就沒有購買。
    與孫JJ之間的故事還有一段小插曲,我曾經自己建立了一個Sun公司認證資料的網站,後來因爲2年沒有續費,網站關閉了,很多網友就寫信索求一些難找的資 料。突然有一天,我發現其中的一位居然是我最敬佩的孫JJ,原來孫JJ正在編寫《TOMCAT與JAVA WEB開發技術詳解(第2版)》,其中有EL和JSTL的內容。孫JJ還在信中非常認真的詢問了一下SCWCD認證中JSP2.0的着重點,以及 JSP2.0在企業中的應用是否廣泛(我那時非常認真的告訴她,EL和JSTL用的人太少。。。)從這點可以看出,孫JJ在寫書的時候非常認真的取材,這 讓我對她更增加了幾分敬意。

    最後,不得不提一位我所見過的最爛的Java書籍作者,名字就不提了。本來是想只寫最喜歡的作者的,但是說到了《精通Struts》《精通 Hibernate》,就不得不提一下他,因爲這本書叫做《精通Spring》,與前兩本書是同一出版社。我買下它,是因爲前兩本書真的很不錯,以爲同一 個出版社,質量應該差不多,但買完以後就傻眼了。此書是我有史以來見過的最爛的書!看書還不如直接看Spring的手冊,因爲書的內容大部分都是摘錄的。 更可恨的是,該作者在china-pub書評上自己沒事就給自己打五顆星,增加自己的等級,讀者提出點意見的時候,他居然跑上來與廣大的讀者對 罵。。。。。看來IT界也有素質低的啊!後來,我終於等到了《Spring in Action》的出版,才真正弄明白了什麼是IoC和AOP,有了這次經歷以後,我就決定儘量少買國內作者的書籍了。
   
    大概就這麼多了,其實最近我也又買了一本國人寫的Java書籍,不過爲了證明我不是在做廣告,就先不說了。我希望國內的Java程序員能不斷的推出更好的Java高級編程相關的書籍,讓我們Java界的技術更上一層樓,呵呵。
MD5算法是將數據進行不可逆加密的算法有較好的安全性,在國內如壽信的安全支付平臺就採用此算法。

源代碼如下
/************************************************
MD5 算法的Java Bean
Last Modified:10,Mar,2001
*************************************************/

import java.lang.reflect.*;

/*************************************************
md5 類實現了RSA Data Security, Inc.在提交給IETF
的RFC1321中的MD5 message-digest 算法。
*************************************************/

public class MD5 {
/* 下面這些S11-S44實際上是一個4*4的矩陣,在原始的C實現中是用#define 實現的,
這裏把它們實現成爲static final是表示了只讀,切能在同一個進程空間內的多個
Instance間共享*/
static final int S11 = 7;
static final int S12 = 12;
static final int S13 = 17;
static final int S14 = 22;

static final int S21 = 5;
static final int S22 = 9;
static final int S23 = 14;
static final int S24 = 20;

static final int S31 = 4;
static final int S32 = 11;
static final int S33 = 16;
static final int S34 = 23;

static final int S41 = 6;
static final int S42 = 10;
static final int S43 = 15;
static final int S44 = 21;

static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* 下面的三個成員是MD5計算過程中用到的3個核心數據,在原始的C實現中
   被定義到MD5_CTX結構中

*/
private long[] state = new long[4];  // state (ABCD)
private long[] count = new long[2];  // number of bits, modulo 2^64 (lsb first)
private byte[] buffer = new byte[64]; // input buffer

/* digestHexStr是MD5的唯一一個公共成員,是最新一次計算結果的
  16進制ASCII表示.
*/
public String digestHexStr;

/* digest,是最新一次計算結果的2進制內部表示,表示128bit的MD5值.
*/
private byte[] digest = new byte[16];

/*
  getMD5ofStr是類MD5最主要的公共方法,入口參數是你想要進行MD5變換的字符串
  返回的是變換完的結果,這個結果是從公共成員digestHexStr取得的.
*/
public String getMD5ofStr(String inbuf) {
md5Init();
md5Update(inbuf.getBytes(), inbuf.length());
md5Final();
digestHexStr = "";
for (int i = 0; i < 16; i++) {
digestHexStr += byteHEX(digest[i]);
}
return digestHexStr;

}
// 這是MD5這個類的標準構造函數,JavaBean要求有一個public的並且沒有參數的構造函數
public MD5() {
md5Init();

return;
}



/* md5Init是一個初始化函數,初始化核心變量,裝入標準的幻數 */
private void md5Init() {
count[0] = 0L;
count[1] = 0L;
///* Load magic initialization constants.

state[0] = 0x67452301L;
state[1] = 0xefcdab89L;
state[2] = 0x98badcfeL;
state[3] = 0x10325476L;

return;
}
/* F, G, H ,I 是4個基本的MD5函數,在原始的MD5的C實現中,由於它們是
簡單的位運算,可能出於效率的考慮把它們實現成了宏,在java中,我們把它們
  實現成了private方法,名字保持了原來C中的。 */

private long F(long x, long y, long z) {
return (x & y) | ((~x) & z);

}
private long G(long x, long y, long z) {
return (x & z) | (y & (~z));

}
private long H(long x, long y, long z) {
return x ^ y ^ z;
}

private long I(long x, long y, long z) {
return y ^ (x | (~z));
}

   /*
  FF,GG,HH和II將調用F,G,H,I進行近一步變換
  FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
  Rotation is separate from addition to prevent recomputation.
   */ 

private long FF(long a, long b, long c, long d, long x, long s,
long ac) {
a += F (b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}

private long GG(long a, long b, long c, long d, long x, long s,
long ac) {
a += G (b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long HH(long a, long b, long c, long d, long x, long s,
long ac) {
a += H (b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long II(long a, long b, long c, long d, long x, long s,
long ac) {
a += I (b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
/*
md5Update是MD5的主計算過程,inbuf是要變換的字節串,inputlen是長度,這個
函數由getMD5ofStr調用,調用之前需要調用md5init,因此把它設計成private的
*/
private void md5Update(byte[] inbuf, int inputLen) {

int i, index, partLen;
byte[] block = new byte[64];
index = (int)(count[0] >>> 3) & 0x3F;
// /* Update number of bits */
if ((count[0] += (inputLen << 3)) < (inputLen << 3))
count[1]++;
count[1] += (inputLen >>> 29);

partLen = 64 - index;

// Transform as many times as possible.
if (inputLen >= partLen) {
md5Memcpy(buffer, inbuf, index, 0, partLen);
md5Transform(buffer);

for (i = partLen; i + 63 < inputLen; i += 64) {

md5Memcpy(block, inbuf, 0, i, 64);
md5Transform (block);
}
index = 0;

} else

i = 0;

///* Buffer remaining input */
md5Memcpy(buffer, inbuf, index, i, inputLen - i);

}

/*
  md5Final整理和填寫輸出結果
*/
private void md5Final () {
byte[] bits = new byte[8];
int index, padLen;

///* Save number of bits */
Encode (bits, count, ;

///* Pad out to 56 mod 64.
index = (int)(count[0] >>> 3) & 0x3f;
padLen = (index < 56) ? (56 - index) : (120 - index);
md5Update (PADDING, padLen);

///* Append length (before padding) */
md5Update(bits, ;

///* Store state in digest */
Encode (digest, state, 16);

}

/* md5Memcpy是一個內部使用的byte數組的塊拷貝函數,從input的inpos開始把len長度的
      字節拷貝到output的outpos位置開始
*/

private void md5Memcpy (byte[] output, byte[] input,
int outpos, int inpos, int len)
{
int i;

for (i = 0; i < len; i++)
output[outpos + i] = input[inpos + i];
}

/*
   md5Transform是MD5核心變換程序,有md5Update調用,block是分塊的原始字節
*/
private void md5Transform (byte block[]) {
long a = state[0], b = state[1], c = state[2], d = state[3];
long[] x = new long[16];

Decode (x, block, 64);

/* Round 1 */
a = FF (a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */
d = FF (d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */
c = FF (c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */
b = FF (b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
a = FF (a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */
d = FF (d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */
c = FF (c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */
b = FF (b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */
a = FF (a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */
d = FF (d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */
c = FF (c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */
b = FF (b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */
a = FF (a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */
d = FF (d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */
c = FF (c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */
b = FF (b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */

/* Round 2 */
a = GG (a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */
d = GG (d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */
c = GG (c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */
b = GG (b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
a = GG (a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */
d = GG (d, a, b, c, x[10], S22, 0x2441453L); /* 22 */
c = GG (c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */
b = GG (b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
a = GG (a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */
d = GG (d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */
c = GG (c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */
b = GG (b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */
a = GG (a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */
d = GG (d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
c = GG (c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */
b = GG (b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */

/* Round 3 */
a = HH (a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */
d = HH (d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */
c = HH (c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */
b = HH (b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */
a = HH (a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */
d = HH (d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
c = HH (c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
b = HH (b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */
a = HH (a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */
d = HH (d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */
c = HH (c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */
b = HH (b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */
a = HH (a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */
d = HH (d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */
c = HH (c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
b = HH (b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */

/* Round 4 */
a = II (a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */
d = II (d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */
c = II (c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */
b = II (b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */
a = II (a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */
d = II (d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
c = II (c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */
b = II (b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */
a = II (a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
d = II (d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
c = II (c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */
b = II (b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */
a = II (a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */
d = II (d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */
c = II (c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
b = II (b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */

state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;

}

/*Encode把long數組按順序拆成byte數組,因爲java的long類型是64bit的,
  只拆低32bit,以適應原始C實現的用途
*/
private void Encode (byte[] output, long[] input, int len) {
int i, j;

for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (byte)(input[i] & 0xffL);
output[j + 1] = (byte)((input[i] >>> & 0xffL);
output[j + 2] = (byte)((input[i] >>> 16) & 0xffL);
output[j + 3] = (byte)((input[i] >>> 24) & 0xffL);
}
}

/*Decode把byte數組按順序合成成long數組,因爲java的long類型是64bit的,
  只合成低32bit,高32bit清零,以適應原始C實現的用途
*/
private void Decode (long[] output, byte[] input, int len) {
int i, j;


for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = b2iu(input[j]) |
(b2iu(input[j + 1]) << |
(b2iu(input[j + 2]) << 16) |
(b2iu(input[j + 3]) << 24);

return;
}
  
/*
  b2iu是我寫的一個把byte按照不考慮正負號的原則的"升位"程序,因爲java沒有unsigned運算
*/
public static long b2iu(byte b) {
return b < 0 ? b & 0x7F + 128 : b;
}

/*byteHEX(),用來把一個byte類型的數轉換成十六進制的ASCII表示,
 因爲java中的byte的toString無法實現這一點,我們又沒有C語言中的
  sprintf(outbuf,"%02X",ib)
*/
public static String byteHEX(byte ib) {
char[] Digit = { 0,1,2,3,4,5,6,7,8,9,
A,B,C,D,E,F };
char [] ob = new char[2];
ob[0] = Digit[(ib >>> 4) & 0X0F];
ob[1] = Digit[ib & 0X0F];
String s = new String(ob);
return s;
}
}

注:
倒數第9行我覺得應該是
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F' };
因爲是轉來的,我就不改了
生成有4個隨機數字和雜亂背景的圖片,數字和背景顏色會改變,服務器端刷新(用history.go(-1)也會變)
原型參考ALIBABA  http://china.alibaba.com/member/showimage

------------產生驗證碼圖片的文件-----image.jsp-------------------------------------------


<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %>
<%!
Color getRandColor(int fc,int bc){//給定範圍獲得隨機顏色
        Random random = new Random();
        if(fc>255) fc=255;
        if(bc>255) bc=255;
        int r=fc+random.nextInt(bc-fc);
        int g=fc+random.nextInt(bc-fc);
        int b=fc+random.nextInt(bc-fc);
        return new Color(r,g,b);
        }
%>
<%
//設置頁面不緩存
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);

// 在內存中創建圖象
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 獲取圖形上下文
Graphics g = image.getGraphics();

//生成隨機類
Random random = new Random();

// 設定背景色
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);

//設定字體
g.setFont(new Font("Times New Roman",Font.PLAIN,18));

//畫邊框
//g.setColor(new Color());
//g.drawRect(0,0,width-1,height-1);


// 隨機產生155條幹擾線,使圖象中的認證碼不易被其它程序探測到
g.setColor(getRandColor(160,200));
for (int i=0;i<155;i++)
{
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(12);
        int yl = random.nextInt(12);
        g.drawLine(x,y,x+xl,y+yl);
}

// 取隨機產生的認證碼(4位數字)
String sRand="";
for (int i=0;i<4;i++){
    String rand=String.valueOf(random.nextInt(10));
    sRand+=rand;
    // 將認證碼顯示到圖象中
    g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));// 調用函數出來的顏色相同,可能是因爲種子太接近,所以只能直接生成
    g.drawString(rand,13*i+6,16);
}

// 將認證碼存入SESSION
session.setAttribute("rand",sRand);


// 圖象生效
g.dispose();

// 輸出圖象到頁面
ImageIO.write(image, "JPEG", response.getOutputStream());


%>

---------------使用驗證碼圖片的文件---------a.jsp------------------------------------


<%@ page contentType="text/html;charset=gb2312" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>認證碼輸入頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</head>
<body>
<form method=post action="check.jsp">
<table>
    <tr>
        <td align=left>系統產生的認證碼:</td>
        <td><img border=0 src="image.jsp"></td>
    </tr>
    <tr>
        <td align=left>輸入上面的認證碼:</td>
        <td><input type=text name=rand maxlength=4 value=""></td>
    </tr>
    <tr>
        <td colspan=2 align=center><input type=submit value="提交檢測"></td>
     </tr>
</table>
</form>
</body>
</html>


-----------------驗證的頁面----------check.jsp

<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<html>
<head>
<title>認證碼驗證頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</head>

<body>
<%
String rand = (String)session.getAttribute("rand");
String input = request.getParameter("rand");
%>
系統產生的認證碼爲: <%= rand %><br>
您輸入的認證碼爲: <%= input %><br>
<br>
<%
  if (rand.equals(input)) {
%>
<font color=green>輸入相同,認證成功!</font>
<%
  } else {
%>
<font color=red>輸入不同,認證失敗!</font>
<%
  }
%>
</body>
</html>

注:使用上述代碼時會拋出一個異常:getOutputStream() has already been called for this response
tomcat5下jsp出現getOutputStream() has already been called for this response異常的原因和解決方法

在tomcat5下jsp中出現此錯誤一般都是在jsp中使用了輸出流(如輸出圖片驗證碼,文件下載等),
沒有妥善處理好的原因。
具體的原因就是
在tomcat中jsp編譯成servlet之後在函數_jspService(HttpServletRequest request, HttpServletResponse response)的最後
有一段這樣的代碼
finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
}
這裏是在釋放在jsp中使用的對象,會調用response.getWriter(),因爲這個方法是和
response.getOutputStream()相沖突的!所以會出現以上這個異常。

然後當然是要提出解決的辦法,其實挺簡單的(並不是和某些朋友說的那樣--
將jsp內的所有空格和回車符號所有都刪除掉),

在使用完輸出流以後調用以下兩行代碼即可:
out.clear();
out = pageContext.pushBody();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章