byterat

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            54 隨筆 :: 0 文章 :: 15 評(píng)論 :: 0 Trackbacks

          2007年3月5日 #

          Eclipse及其插件介紹和下載

          0.Eclipse下載
          EMF,GEF - Graphical Editor Framework,UML2,VE - Visual Editor都在這里下載
          http://www.eclipse.org/downloads/index.php

          0.5.lomboz J2EE插件,開發(fā)JSP,EJB
          http://forge.objectweb.org/projects/lomboz
          1.MyEclipse J2EE開發(fā)插件,支持SERVLET/JSP/EJB/數(shù)據(jù)庫(kù)操縱等
          http://www.myeclipseide.com

          2.Properties Editor 編輯java的屬性文件,并可以自動(dòng)存盤為Unicode格式
          http://propedit.sourceforge.jp/index_en.html

          3.Colorer Take 為上百種類型的文件按語法著色
          http://colorer.sourceforge.net/

          4.XMLBuddy 編輯xml文件
          http://www.xmlbuddy.com

          5.Code Folding 加入多種代碼折疊功能(比eclipse自帶的更多)
          http://www.coffee-bytes.com/servlet/PlatformSupport

          6.Easy Explorer 從eclipse中訪問選定文件、目錄所在的文件夾
          http://easystruts.sourceforge.net/

          7.Fat Jar 打包插件,可以方便的完成各種打包任務(wù),可以包含外部的包等
          http://fjep.sourceforge.net/

          8.RegEx Test 測(cè)試正則表達(dá)式
          http://brosinski.com/stephan/archives/000028.php

          9.JasperAssistant 報(bào)表插件(強(qiáng),要錢的)
          http://www.jasperassistant.com/

          10.Jigloo GUI Builder JAVA的GUI編輯插件
          http://cloudgarden.com/jigloo/

          11.Profiler 性能跟蹤、測(cè)量工具,能跟蹤、測(cè)量BS程序
          http://sourceforge.net/projects/eclipsecolorer/

          12.AdvanQas 提供對(duì)if/else等條件語句的提示和快捷幫助(自動(dòng)更改結(jié)構(gòu)等)
          http://eclipsecolorer.sourceforge.net/advanqas/index.html

          13.Log4E Log4j插件,提供各種和Log4j相關(guān)的任務(wù),如為方法、類添加一個(gè)logger等
          http://log4e.jayefem.de/index.php/Main_Page

          14.VSSPlugin VSS插件
          http://sourceforge.net/projects/vssplugin

          15.Implementors 提供跳轉(zhuǎn)到一個(gè)方法的實(shí)現(xiàn)類,而不是接中的功能(實(shí)用!)
          http://eclipse-tools.sourceforge.net/implementors/
          16.Call Hierarchy 顯示一個(gè)方法的調(diào)用層次(被哪些方法調(diào),調(diào)了哪些方法)
          http://eclipse-tools.sourceforge.net/call-hierarchy/index.html

          17.EclipseTidy 檢查和格式化HTML/XML文件
          http://eclipsetidy.sourceforge.net/

          18.Checkclipse 檢查代碼的風(fēng)格、寫法是否符合規(guī)范
          http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm

          19.Hibernate Synchronizer Hibernate插件,自動(dòng)映射等
          http://www.binamics.com/hibernatesync/

          20.VeloEclipse Velocity插件
          http://propsorter.sourceforge.net/

          21.EditorList 方便的列出所有打開的Editor
          http://editorlist.sourceforge.net/

          22.MemoryManager 內(nèi)存占用率的監(jiān)視
          http://cloudgarden.com/memorymanager/

          23.swt-designer java的GUI插件
          http://www.swt-designer.com/

          24.TomcatPlugin 支持Tomcat插件
          http://www.eclipsetotale.com/tomcatPlugin.html

          25.XML Viewer
          http://tabaquismo.freehosting.net/ignacio/eclipse/xmlview/index.html

          26.quantum 數(shù)據(jù)庫(kù)插件
          http://quantum.sourceforge.net/

          27.Dbedit 數(shù)據(jù)庫(kù)插件
          http://sourceforge.net/projects/dbedit

          28.clay.core 可視化的數(shù)據(jù)庫(kù)插件
          http://www.azzurri.jp/en/software/index.jsp
          http://www.azzurri.jp/eclipse/plugins

          29.hiberclipse hibernate插件
          http://hiberclipse.sourceforge.net
          http://www.binamics.com/hibernatesync

          30.struts-console Struts插件
          http://www.jamesholmes.com/struts/console/

          31.easystruts Struts插件
          http://easystruts.sourceforge.net

          32.veloedit Velocity插件
          http://veloedit.sourceforge.net/

          33.jalopy 代碼整理插件
          http://jalopy.sourceforge.net/

          34.JDepend 包關(guān)系分析
          http://andrei.gmxhome.de/jdepend4eclipse/links.html

          35.Spring IDE Spring插件
          http://springide-eclip.sourceforge.net/updatesite/

          36.doclipse 可以產(chǎn)生xdoclet 的代碼提示
          http://beust.com/doclipse/
          posted @ 2008-06-05 15:44 比特鼠| 編輯 收藏

               摘要: 有這樣一個(gè)函數(shù), 它接受一個(gè)函數(shù)(或者說閉包)作為參數(shù)  閱讀全文
          posted @ 2008-05-30 15:19 比特鼠| 編輯 收藏

          當(dāng)談到表格數(shù)據(jù)的設(shè)計(jì)時(shí),沒有太多的網(wǎng)頁(yè)設(shè)計(jì)師會(huì)有太大的興趣。今天我們已經(jīng)收集了20多個(gè)功能超大且看上去挺漂亮的Ajax/CSS表格設(shè)計(jì),并且教你一些表格設(shè)計(jì)中所運(yùn)用的技巧,例如表格數(shù)據(jù)的排序和過濾等。

          OK,讓我們來看一下這些表格:

          1. Tablecloth

          Tablecloth 由CSS Globe 開發(fā),是一個(gè)輕巧易于使用的表格,簡(jiǎn)潔的將表格樣式添加到你的HTML 表格元素中。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Tablecloth

          2. Ask the CSS Guy Table

          Ask the CSS Guy Table教給我們要如何去創(chuàng)建能夠清晰顯出去資料之間的相關(guān)聯(lián)系的表格,例如:點(diǎn)擊一個(gè)表格元素時(shí),將突了顯示這個(gè)元素,并且在縱列和橫列都顯示出相關(guān)的類別關(guān)系。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Ask the CSS Guy Table

          #3. A CSS styled table version 2

          Veerle Duoh 為我們展示了一個(gè)漂亮的表格設(shè)計(jì),并教我們?nèi)绾问褂肅SS來吸引用戶的眼球。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-A CSS styled table version 2

          #4. Sortable Table

          Sortable Table 演示了如何按升序或降序排列以及如何過濾表格中的數(shù)據(jù)。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Sortable Table

          5. Row Locking with CSS and JavaScript

          Css Guy再次對(duì)表格使用了聚焦高亮的效果,除非用戶再次點(diǎn)擊,否則表單數(shù)據(jù)將一直保持亮高。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Row Locking with CSS and JavaScript

          他還給了我們另一個(gè)示例:another example to Lock rows with radios .

          #6. Vertical scrolling tables

          如果您有大量的表格數(shù)據(jù),但卻沒有太大的空間來展示它,這可能是個(gè)比較好的方法:一個(gè)純CSS的表格與固定的標(biāo)題和頁(yè)腳,以及滾動(dòng)顯示的內(nèi)容。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Vertical scrolling tables

          7. Replicating a Tree table

          這是一個(gè)使用HTML 和CSS 設(shè)計(jì)的樹形狀表格。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Replicating a Tree table

          8 ) Paginate, sort and search a table with Ajax and Rails

          這個(gè)表格提供了一個(gè)動(dòng)態(tài)的界面,而不需要重新刷新整個(gè)頁(yè)面。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-ajax tables

          9. Collapsible tables with DOM and CSS

          此表格加上箭頭形象的腳本提示,用來控制表格的伸展和收縮。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Collapsible tables with DOM and CSS

          10. TableSorter plug-in for jQuery

          它的主要特性包括多列排序,支持<TH>的rowspan和colspan屬性以及許多其他功能。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-TableSorter plug-in for jQuery

          11. Stripe your tables the OO way

          使用了Javascript 為表格中的行進(jìn)行顏色交替,并且添加了onmouseoveronmouseout 事件,當(dāng)鼠標(biāo)點(diǎn)擊時(shí),切換背景顏色。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Stripe your tables the OO way

          12. MooTools Table Row & Column highlighting

          基于MooTools 框架,高亮顯示鼠標(biāo)懸停時(shí)的單元格所在的行和列。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-MooTools Table Row & Column highlighting

          13. CSS Table Gallery

          93 styled tables是一個(gè)專門收集表格樣式的站點(diǎn),下面是來自一個(gè)表格樣式的截圖:

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-CSS Table Gallery

          14. jQuery Table Filter

          可以對(duì)數(shù)據(jù)進(jìn)行各種不同的排序、過濾。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-jQuery Table Filter

          15. Sortable/Resizable/Editable TableKit

          TableKit基于Prototype框架,專門收集各種HTML表格,可以利用Ajax實(shí)時(shí)的進(jìn)行表格欄目大小、排序等編輯。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-sortable, resizable, editable

          16. Make all your tables sortable

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-sortable table

          17. Zebra Tables

          alistapart為我們提供了一個(gè)極好的例子,如何使用JavaScript和DOM的改變背景色風(fēng)格,以突出顯示單元格。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Zebra Tables

          18. Standardista Table Sorting

          Standardista Table Sorting 是一個(gè)Javascript模塊,讓您可以對(duì)HTML數(shù)據(jù)表的任何欄目進(jìn)行排序。

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Standardista Table Sorting

          19. GridView3 Example

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-GridView3 Example

          20. Mootable

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Mootable

          21. Drag & Drop Sortable Lists with JavaScript and CSS

          21個(gè)新奇漂亮的Ajax/CSS表格設(shè)計(jì)-Drag & Drop Sortable Lists with JavaScript and CSS

          可能還會(huì)有一些你更想尋找的詳細(xì)資料,下面是一些相關(guān)的資源鏈接:

          如果你知道其它更強(qiáng)大的Ajax/CSS表格,歡迎在此留言。

          posted @ 2008-01-23 17:46 比特鼠 閱讀(3204) | 評(píng)論 (0)編輯 收藏

          一個(gè)在線調(diào)色工具
          posted @ 2008-01-23 17:44 比特鼠 閱讀(396) | 評(píng)論 (1)編輯 收藏

          /**
           * 加碼解碼工具
           * @author lwm
           *
           */

          public class Encode {
           
           /*
            * 對(duì)應(yīng)javascript的escape()函數(shù), 加碼后的串可直接使用javascript的unescape()進(jìn)行解碼
            */
           public static String escape(String src) {
            int i;
            char j;
            StringBuffer tmp = new StringBuffer();
            tmp.ensureCapacity(src.length() * 6);
            for (i = 0; i < src.length(); i++) {
             j = src.charAt(i);
             if (Character.isDigit(j) || Character.isLowerCase(j)
               || Character.isUpperCase(j))
              tmp.append(j);
             else if (j < 256) {
              tmp.append("%");
              if (j < 16)
               tmp.append("0");
              tmp.append(Integer.toString(j, 16));
             } else {
              tmp.append("%u");
              tmp.append(Integer.toString(j, 16));
             }
            }
            return tmp.toString();
           }

           /*
            * 對(duì)應(yīng)javascript的unescape()函數(shù), 可對(duì)javascript的escape()進(jìn)行解碼
            */
           public static String unescape(String src) {
            StringBuffer tmp = new StringBuffer();
            tmp.ensureCapacity(src.length());
            int lastPos = 0, pos = 0;
            char ch;
            while (lastPos < src.length()) {
             pos = src.indexOf("%", lastPos);
             if (pos == lastPos) {
              if (src.charAt(pos + 1) == 'u') {
               ch = (char) Integer.parseInt(src
                 .substring(pos + 2, pos + 6), 16);
               tmp.append(ch);
               lastPos = pos + 6;
              } else {
               ch = (char) Integer.parseInt(src
                 .substring(pos + 1, pos + 3), 16);
               tmp.append(ch);
               lastPos = pos + 3;
              }
             } else {
              if (pos == -1) {
               tmp.append(src.substring(lastPos));
               lastPos = src.length();
              } else {
               tmp.append(src.substring(lastPos, pos));
               lastPos = pos;
              }
             }
            }
            return tmp.toString();
           }

          }

          posted @ 2008-01-11 17:08 比特鼠 閱讀(1841) | 評(píng)論 (0)編輯 收藏

          讀 YUI ,EXT等源碼的時(shí)候看JS天旋地轉(zhuǎn),那可不是51JS上那種挪挪位置就能理解的,此刻如果沒有JavaScrip的基礎(chǔ),更是像沒有星光的黑夜…….

          自以為覺得Js對(duì)象是很好理解的東東,然而真實(shí)踐起來卻一片糊涂。
          通過查閱經(jīng)典書籍《Professional JavaScript For Web Developers》稍微有些理解了

          JavaScript的基本類型
          原始類型如: Undefined Null Boolean Number String 等 用 typeof方法能辨別之
          引用類型如: Object Function Array Boolean Number String Date等,用insanceof方法辨別之

          嚴(yán)格來講,JavaScript沒有對(duì)象(Object),但是由于和OO術(shù)語對(duì)應(yīng),所以也稱之為對(duì)象。所以Array,Function,基本類型,引用類型,函數(shù),以及函數(shù)的屬性 等等這些都是對(duì)象。

          而對(duì)象分類,則可以分為內(nèi)置對(duì)象(Built-in Object) 和宿主對(duì)象(host object)。
          內(nèi)置對(duì)象如 Math,Data啊。
          宿主對(duì)象則如 BOM,DOM之類.

          重新回顧了下這些基本概念之后,在做簡(jiǎn)單實(shí)踐就有些理解了。
          因此對(duì)象的使用,創(chuàng)建方式不盡相同,最簡(jiǎn)單的歸類如下:

          1 基本創(chuàng)建方式

          function Class() {
          window.alert("Hello Class!");
          }
          var clz= new Class();

          2 訪問對(duì)象成員

          function Class(){
          this.x = " this is x";
          this.y = "this is y";
          this.z = viewXY;
          function viewXY(){
          alert("x+","+y);
          }
          }
          var clz= new Class();
          clz.viewXY();

          3 對(duì)象繼承

          function Parent() {
          this.type= "human!";
          }
          function Child(){
          this.age = "26";
          this.sex ="male";
          this.say= myInfo;
          function myInfo(msg){
          alert(msg+this.type+ ","+this.age+","+this.sex);
          }
          }
          Child.prototype = new Parent();
          var clild = new Child();
          clild.say("I'm ");

          4.重用原對(duì)象 (書上的例子太好了,搬來了)

          Funcion.prototype.toString() = function(){
          return "Function code hidden";
          }
          function sayHi(){
          alert("hi");
          }
          alert(sayHi.toString());
          posted @ 2008-01-02 11:06 比特鼠 閱讀(275) | 評(píng)論 (0)編輯 收藏

          希望能做到以下幾點(diǎn):

          1. 在Java服務(wù)端架構(gòu)的設(shè)計(jì), 選型, 方案等方面有所突破! -- 這是最主要的!
          2. 也想玩一玩Web前端的AJAX編程, RIA(富互聯(lián)網(wǎng)應(yīng)用)等等
          3. 熟悉Linux/Unix系統(tǒng)的命令行操作
          4. 在Java中跑腳本語言Python, JRuby等等
          5. 項(xiàng)目管理

          暫時(shí)就這么多吧!

          posted @ 2007-12-28 09:41 比特鼠 閱讀(214) | 評(píng)論 (0)編輯 收藏

          為 Ajax 安全性所提出的經(jīng)驗(yàn)法則:
          1. 如果你使用身份驗(yàn)證, 確定你在請(qǐng)求頁(yè)上檢查!
          2. 為 SQL 注入檢查。
          3. 為 JavaScript 注入檢查。
          4. 保留商務(wù)邏輯在服務(wù)器上!
          5. 不要假設(shè)每個(gè)請(qǐng)求是真正的!
          6. 確認(rèn)檢查數(shù)據(jù)!
          7. 審查請(qǐng)求的數(shù)據(jù)而且確定它是正確的。
          posted @ 2007-12-19 17:10 比特鼠 閱讀(283) | 評(píng)論 (0)編輯 收藏

          1. jvm內(nèi)部分為主工作區(qū)和線程工作區(qū)。主工作區(qū)是實(shí)例的所有線程共有,線程工作區(qū)是實(shí)例的每個(gè)線程專有的工作區(qū),其中包括一些主工作區(qū)的一些實(shí)例字段數(shù)據(jù)的拷貝。

          2. 服務(wù)器一般都有線程池,線程資源是可以重復(fù)利用的。你2000個(gè)用戶在線,不見得能又200個(gè)用戶同時(shí)(或者說并發(fā))訪問。再說,只要對(duì)象不是太大,我寧愿用200個(gè)拷貝,也不想讓用戶在這個(gè)200個(gè)任務(wù)的隊(duì)列里等待。

          3. 兩個(gè)DB之間的復(fù)制數(shù)據(jù),每個(gè)DB各自使用自己的Sequane來生成id。復(fù)制數(shù)據(jù)時(shí),如果DB中的外鍵是由DB維護(hù)的,則不會(huì)產(chǎn)生id沖突,如果外鍵是由外部程序維護(hù)的,則可能會(huì)產(chǎn)生錯(cuò)誤!

          4. 對(duì)于非static的類的數(shù)據(jù)成員來說,在該類產(chǎn)生的實(shí)例中都有一份,并且相互獨(dú)立(修改后并不影響其他實(shí)例), 但static的數(shù)據(jù)成員則變成了每個(gè)類只有一份,即在該類產(chǎn)生的所有實(shí)例共享這一個(gè)數(shù)據(jù)成員, 該數(shù)據(jù)成員的改變會(huì)影響到其他的實(shí)例. 而static的方法則是讓你不用創(chuàng)建對(duì)象及能調(diào)用這個(gè)方法.

          5. ThreadLocal的作用就是將經(jīng)常要用到的對(duì)象的引用放到屬于線程自己的一個(gè)存儲(chǔ)空間中,在該線程的執(zhí)行過程中,可以通過類的靜態(tài)的ThreadLocal來方便的獲取到這個(gè)對(duì)象,而不用通過參數(shù)的形式傳來傳去。
          posted @ 2007-12-19 14:54 比特鼠 閱讀(260) | 評(píng)論 (0)編輯 收藏

          很多高分辨率的圖像真的能夠扮靚一個(gè)Web網(wǎng)站。但是它們也可能會(huì)降低網(wǎng)站的(響應(yīng))速度——圖像都是文件,文件就要占用帶寬,而帶寬與等待時(shí)間直接相關(guān)。現(xiàn)在是你進(jìn)行自我學(xué)習(xí),了解如何利用一種叫做圖像預(yù)加載的小技巧給網(wǎng)站提速的時(shí)候了。

          圖像的預(yù)加載

                 瀏覽器通常的工作方式是:只有當(dāng)要求加載圖像的HTTP請(qǐng)求被發(fā)送的時(shí)候,圖像才會(huì)被加載,而不論它是被動(dòng)地通過<img>標(biāo)記加載,還是主動(dòng)地通過方法調(diào)用加載。所以,如果你有一段JavaScript,需要在鼠標(biāo)懸停的時(shí)候切換圖像,或者在超時(shí)之后自動(dòng)地更換圖像,那么你就可能會(huì)在從服務(wù)器取回圖像的時(shí)候隨時(shí)碰到等待,時(shí)間會(huì)從數(shù)秒鐘到幾分鐘不等。當(dāng)你以較慢的速度連接到Internet上的時(shí)候,或者被取回的圖像非常巨大的時(shí)候,這種狀況尤其顯著,而這種數(shù)據(jù)延遲通常都會(huì)毀掉你所期望的效果。

                  有些瀏覽器會(huì)試圖轉(zhuǎn)嫁這一問題,比如把圖像保存在本地緩沖區(qū)里,這樣以后對(duì)它的調(diào)用就能夠很快進(jìn)行了,但是需要第一次調(diào)用圖像的時(shí)候仍然會(huì)產(chǎn)生延遲。預(yù)加載是一項(xiàng)在需要圖像之前就把它下載到緩沖區(qū)里的技術(shù)。通過這種方式,當(dāng)真的需要圖像的時(shí)候,它可以被從緩沖區(qū)里取出來,并立即顯示出來。

          Image()對(duì)象
                  預(yù)加載圖像最簡(jiǎn)單的方法用JavaScript將一個(gè)新的Image()對(duì)象實(shí)例化,并把你想要預(yù)加載的圖像的URL傳遞給它。假設(shè)我們有一個(gè)叫做
          http://www.host01.com/Get/jsp/00040004/heavyimagefile.jpg的圖像,我們希望,當(dāng)用戶把鼠標(biāo)放在一個(gè)已經(jīng)顯示過的圖像上的時(shí),系統(tǒng)能夠顯示出這個(gè)圖像。為了預(yù)加載這個(gè)圖像,以便實(shí)現(xiàn)更快的響應(yīng)時(shí)間,我們只用創(chuàng)建一個(gè)新的Image()對(duì)象,將其命名為heavyImage,并使用onLoad()事件處理程序把它同時(shí)加載到頁(yè)面上。

          1 < html >< head >< script  language  = "JavaScript" > function  preloader()  {heavyImage  =   new  Image(); heavyImage.src = " http://www.host01.com/Get/jsp/00040004/heavyimagefile.jpg " ;} </ script ></ head >< body  onLoad ="javascript:preloader()" >< href ="#"  onMouseOver ="javascript:document.img01.src='http://www.host01.com/Get/jsp/00040004/heavyimagefile.jpg'" >< img  name ="img01"  src =http://www.host01.com/Get/jsp/00040004/"justanotherfile.jpg" ></ a ></ body ></ html >
          2

           

                    要注意的是,圖像標(biāo)記自身并不會(huì)處理onMouseOver()和onMouseOut()事件,這就是為什么上面例子里的<img>標(biāo)記被放在一個(gè)<a>標(biāo)記里,后者的確加入了對(duì)這些事件類型的支持。
          用數(shù)組加載多個(gè)圖像


                     在實(shí)際操作中,你可能需要預(yù)加載一幅以上的圖像;例如,在包含有多個(gè)圖像翻滾(rollover)的菜單條里,或者如果你正在嘗試創(chuàng)建平滑的動(dòng)態(tài)效果。這并不困難;你所需要做的就是使用JavaScript的數(shù)組,就像下面例子里的一樣:

           

          1 < script language = " JavaScript " > function  preloader()  //  counter var i = 0; // create object imageObj = new Image(); // set image list images = new Array(); images[0]="image1.jpg" images[1]="image2.jpg" images[2]="image3.jpg" images[3]="image4.jpg" // start preloading for(i=0; i<=3; i++) { imageObj.src=images[i]; }
          2 }
            </ script >


                   在上面的例子里,你先定義變量i和叫做imageObj的Image()對(duì)象。然后定義一個(gè)叫做images[]的新數(shù)組,在這個(gè)數(shù)組里,每個(gè)數(shù)組元素都保存著需要預(yù)加載的圖像來源。最后,創(chuàng)建一個(gè)for()循環(huán),讓它在數(shù)組里循環(huán),并將它們中的每一個(gè)都指派給Image()對(duì)象,這樣就能夠把它預(yù)加載到緩沖區(qū)里。
          onLoad()事件處理程序
                  就和JavaScript里的其它很多對(duì)象一樣,Image()對(duì)象也帶有多個(gè)事件處理程序。這其中最有用的毫無疑問的就是onLoad()處理程序了,它會(huì)在完成圖像加載的時(shí)候被調(diào)用。這個(gè)處理程序可以與自定義的函數(shù)一起使用,以便在完成圖像加載之后進(jìn)行特定的任務(wù)。下面的例子通過在圖像加載的時(shí)候顯示“請(qǐng)等待(please wait)”提示信息來說明這個(gè)問題,然后在圖像完成加載之后就向?yàn)g覽器發(fā)送一個(gè)新的URL。

           

          < html >< head >< script  language ="JavaScript" > //  create an image objectobjImage = new Image(); // set what happens once the image has loaded objImage.onLoad=imagesLoaded(); // preload the image fileobjImage.src='http://www.host01.com/Get/jsp/00040004/images/image1n.gif';// function invoked on image loadfunction imagesLoaded(){ document.location.href='index2.html';}</script></head><body>Please wait, loading images</body></html>

           


                 當(dāng)然,你還可以創(chuàng)建一個(gè)圖像數(shù)組,對(duì)它進(jìn)行循環(huán),預(yù)加載每個(gè)圖像,并在每個(gè)階段對(duì)已加載圖像的數(shù)量保持跟蹤。一旦加載了所有的圖像,事件處理程序就能夠按照設(shè)定把瀏覽器帶到下一個(gè)頁(yè)面(或者進(jìn)行其他的任務(wù))。

          預(yù)加載與多狀態(tài)菜單

                    現(xiàn)在,把你剛剛學(xué)到的理論付諸真正的實(shí)踐怎么樣?下面一部分內(nèi)容就是我碰巧編寫的一段代碼——一個(gè)由多個(gè)按鈕(圖像鏈接)組成的菜單條——其中每個(gè)按鈕都可能處于三種狀態(tài)中的一種:正常(normal)、hover(懸停)和點(diǎn)擊(click)。由于所有的按鈕都有多個(gè)狀態(tài),所以就有必要使用圖像預(yù)加載來確保菜單能夠根據(jù)其切換到的狀態(tài)進(jìn)行快速的響應(yīng)。列表A里的代碼就說了這一點(diǎn)。

                     列表A里的HTML代碼會(huì)建立一個(gè)由四個(gè)按鈕組成的菜單條,每個(gè)按鈕都有三種狀態(tài):正常、懸停和點(diǎn)擊。其要求如下:

                    但鼠標(biāo)移動(dòng)到處于正常狀態(tài)的按鈕上時(shí),按鈕會(huì)變?yōu)閼彝顟B(tài)。當(dāng)鼠標(biāo)移開的時(shí)候,按鈕又會(huì)恢復(fù)到正常狀態(tài)。當(dāng)鼠標(biāo)點(diǎn)擊按鈕的時(shí)候,按鈕就會(huì)變?yōu)辄c(diǎn)擊狀態(tài)。它會(huì)一直保持這個(gè)狀態(tài),直到另外一個(gè)按鈕被點(diǎn)擊。如果有一個(gè)按鈕被點(diǎn)擊,那么其他的按鈕就都不能處于點(diǎn)擊狀態(tài)。其他的按鈕只能夠處于懸停或者正常狀態(tài)。一次只能有一個(gè)按鈕可以被點(diǎn)擊。一次只能有一個(gè)按鈕處于懸停狀態(tài)。
                  第一項(xiàng)任務(wù)是建立保存有菜單每個(gè)狀態(tài)的圖像的數(shù)組。與這些數(shù)組元素相對(duì)應(yīng)的<img>元素也都在HTML文檔的主體里被創(chuàng)建,并按順序命名。要注意的是,對(duì)數(shù)組值的索引是從0開始的,而相應(yīng)的<img>元素是從1開始命名的——這就需要在腳本后面的一段里進(jìn)行某種計(jì)算上的調(diào)整。

                  PreloadImages()函數(shù)會(huì)負(fù)責(zé)把所有的圖像都加載到緩沖區(qū)里,這樣的話對(duì)鼠標(biāo)移動(dòng)的響應(yīng)時(shí)間會(huì)被減到最小。一個(gè)for()循環(huán)被用在第一步里創(chuàng)建的圖像里進(jìn)行迭代,并預(yù)加載每一個(gè)圖像。

                      ResetAll()函數(shù)是把所有圖像恢復(fù)都到它們正常狀態(tài)的方便方法。這是有必要的,因?yàn)楫?dāng)菜單的項(xiàng)目被點(diǎn)擊的時(shí)候,菜單里其他所有的項(xiàng)目都必須在被點(diǎn)擊項(xiàng)目能夠切換到點(diǎn)擊狀態(tài)之前恢復(fù)到正常狀態(tài)。

                  SetNormal()、setHover()和setClick()函數(shù)負(fù)責(zé)把特定圖像(圖像的編號(hào)被作為函數(shù)的自變量進(jìn)行傳遞)的來源分別改為正常、懸停或者點(diǎn)擊狀態(tài)。由于被點(diǎn)擊的圖像必須一直保持點(diǎn)擊狀態(tài),直到另外一個(gè)圖像被點(diǎn)擊(見第二項(xiàng)要求),所以它們暫時(shí)不會(huì)對(duì)鼠標(biāo)移動(dòng)作出反應(yīng);這樣的話,如果按鈕還不是處在點(diǎn)擊狀態(tài),那么setNormal()和setHover()函數(shù)所包括的代碼就只能用來改變按鈕的狀態(tài)。

                   上面所提到的預(yù)加載只是提高你JavaScript效果響應(yīng)時(shí)間的多種方法之一。就在你的網(wǎng)站上使用上面列出的技巧,并根據(jù)你的要求在需要的地方更改它們吧。祝你好運(yùn)!

          posted @ 2007-12-19 10:40 比特鼠 閱讀(260) | 評(píng)論 (0)編輯 收藏

          這些東西都是Java Script大部分都是由老外寫的,并且封裝得很好,在運(yùn)用上也很方便,而且也都兼容FF與OPERA,檔案中少部分是由中國(guó)的高手寫的。

           

            一、多樣化摺疊菜單:下載

            一個(gè)由老外寫的折疊式垂直菜單,多樣化,多功能,可自訂,使用容易,支持FF。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖1

            二、CSS圓角邊框:下載

            以CSS為主要,用Java Script封裝的相當(dāng)完整,也是老外寫的,支持多瀏覽器,可以自訂樣式,目前有十多種可以運(yùn)用。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖2

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖3

            三、模擬視窗:下載

            用層模擬的視窗,是一個(gè)中國(guó)高手寫的,Java Script封裝的相當(dāng)好,使用上也很容易

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖4
            

            四、支持FF的省略符:下載

            說到省略符,那非CSS莫屬,有個(gè)老外用Java Script來實(shí)現(xiàn),并且是批量處理的,重點(diǎn)是支持FF。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖5

            五、TAB選項(xiàng)卡:下載

            用Java Script模仿各種作業(yè)系統(tǒng)的選項(xiàng)卡,老外就是牛,不僅支援多樣式的即時(shí)切換,同時(shí)也支援每個(gè)選項(xiàng)卡是否附帶圖示的切換選項(xiàng),選項(xiàng)卡也可以上下切換。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖6
            

            六、最佳化多樣式Windows:下載

            用層模擬視窗的最佳代表作,這是我看過功能最多的模擬式窗,內(nèi)附多達(dá)74項(xiàng)功能與樣式,你完完全全可以把它當(dāng)成是一個(gè)真正的視窗來應(yīng)用,可以根據(jù)你的需求來應(yīng)用,快丟掉你那認(rèn)為好用的層視窗,這套封裝非常完整的視窗絕對(duì)可以滿足你的各種需求。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖7

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖8

            七、多樣化的垂直菜單:附件

            別具風(fēng)格的方塊式垂直折疊菜單,目前有8種風(fēng)格可以運(yùn)用,如果你已經(jīng)厭煩WEB上平凡的菜單,這套在國(guó)外頗受歡迎的菜單肯定是你的最佳首選。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖9
            

            八、多樣化的連結(jié)提示效果:下載

            這個(gè)連結(jié)提示樣式允許你直接寫入css與html,共有14項(xiàng)功能可以讓你自訂。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖10

            九、側(cè)欄式折疊菜單:下載

            這是一個(gè)側(cè)欄式的折疊菜單,它允許你設(shè)置它是否有過渡效果、側(cè)欄菜單是否自動(dòng)伸縮、菜單項(xiàng)切換是否允許動(dòng)畫過渡、是否輪替切換等多項(xiàng)設(shè)置,并且也有多種樣式可以運(yùn)用。

            這個(gè)腳本有個(gè)很好玩的東東,下載并且解壓後,請(qǐng)進(jìn)入samples的目錄并打show.html看看效果,我不知道這效果容不容易實(shí)現(xiàn),但是這效果很牛,菜單全自動(dòng)運(yùn)行的~

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖11
            

            十、圖形滾動(dòng)條:下載

            老外寫的圖形滾動(dòng)條,有多種樣式,在ie里頭還支持滾輪滾動(dòng)。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖12

            十一、圖片倒影效果:下載
            說到圖片倒影,不外乎就是直接作成圖片跟css濾鏡來實(shí)現(xiàn),但是這個(gè)是用Java Script實(shí)現(xiàn)的,值得借鏡。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖13

            十二、代碼自動(dòng)高亮:下載

            雖說這不是什麼新東西,但總是會(huì)有人需要吧,而且想學(xué)正則表達(dá)的人,這肯定是最佳借鏡的作品。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖14
            
            

            十三、酷似flash效果的圖片展示:下載

            這個(gè)老外牛到有點(diǎn)變態(tài),這圖片展示效果已經(jīng)跟FLASH沒什麼兩樣,用Java Script寫的耶。

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖15

            十四、讓ie6支援png圖檔:下載

          國(guó)內(nèi)外 Java Script 經(jīng)典封裝
          圖16

            這個(gè)問題之前被很多人討論過,我就不多說什麼了,有需要下吧。

          posted @ 2007-12-13 17:29 比特鼠 閱讀(5347) | 評(píng)論 (5)編輯 收藏

          在一個(gè)老外的Blog上看到了這個(gè)網(wǎng)站,發(fā)現(xiàn)原來是一個(gè)以C語言為基準(zhǔn)的性能比較網(wǎng)站!

          Java還算不錯(cuò),Ruby就不怎么樣了, 在腳本語言中居然排在了最后!

          看來,解析性的語言玩起來是簡(jiǎn)單方便了,可是卻是以損失性能為代價(jià)的!
          posted @ 2007-12-13 16:34 比特鼠 閱讀(471) | 評(píng)論 (0)編輯 收藏

          BIG-ENDIAN(大字節(jié)序、高字節(jié)序)
          LITTLE-ENDIAN(小字節(jié)序、低字節(jié)序)
          主機(jī)字節(jié)序
          網(wǎng)絡(luò)字節(jié)順序
          JAVA字節(jié)序

          1.BIG-ENDIAN、LITTLE-ENDIAN跟多字節(jié)類型的數(shù)據(jù)有關(guān)的比如int,short,long型,而對(duì)單字節(jié)數(shù)據(jù)byte卻沒有影響。BIG-ENDIAN就是低位字節(jié)排放在內(nèi)存的低端,高位字節(jié)排放在內(nèi)存的高端。而LITTLE-ENDIAN正好相反。
          比如 int a = 0x05060708
          在BIG-ENDIAN的情況下存放為:
          字節(jié)號(hào) 0 1 2 3
          數(shù)據(jù) 05 06 07 08
          在LITTLE-ENDIAN的情況下存放為:
          字節(jié)號(hào) 0 1 2 3
          數(shù)據(jù) 08 07 06 05

          2.BIG-ENDIAN、LITTLE-ENDIAN、跟CPU有關(guān)的,每一種CPU不是BIG-ENDIAN就是LITTLE-ENDIAN、。IA架構(gòu)的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola處理器。這其實(shí)就是所謂的主機(jī)字節(jié)序。而網(wǎng)絡(luò)字節(jié)序是指數(shù)據(jù)在網(wǎng)絡(luò)上傳輸時(shí)是大頭還是小頭的,在Internet的網(wǎng)絡(luò)字節(jié)序是BIG-ENDIAN。所謂的JAVA字節(jié)序指的是在JAVA虛擬機(jī)中多字節(jié)類型數(shù)據(jù)的存放順序,JAVA字節(jié)序也是BIG-ENDIAN。

          3.所以在用C/C++寫通信程序時(shí),在發(fā)送數(shù)據(jù)前務(wù)必用htonl和htons去把整型和短整型的數(shù)據(jù)進(jìn)行從主機(jī)字節(jié)序到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換,而接收數(shù)據(jù)后對(duì)于整型和短整型數(shù)據(jù)則必須調(diào)用ntohl和ntohs實(shí)現(xiàn)從網(wǎng)絡(luò)字節(jié)序到主機(jī)字節(jié)序的轉(zhuǎn)換。如果通信的一方是JAVA程序、一方是C/C++程序時(shí),則需要在C/C++一側(cè)使用以上幾個(gè)方法進(jìn)行字節(jié)序的轉(zhuǎn)換,而JAVA一側(cè),則不需要做任何處理,因?yàn)镴AVA字節(jié)序與網(wǎng)絡(luò)字節(jié)序都是BIG-ENDIAN,只要C/C++一側(cè)能正確進(jìn)行轉(zhuǎn)換即可(發(fā)送前從主機(jī)序到網(wǎng)絡(luò)序,接收時(shí)反變換)。如果通信的雙方都是JAVA,則根本不用考慮字節(jié)序的問題了。

          4.如果網(wǎng)絡(luò)上全部是PowerPC,SPARC和Motorola CPU的主機(jī)那么不會(huì)出現(xiàn)任何問題,但由于實(shí)際存在大量的IA架構(gòu)的CPU,所以經(jīng)常出現(xiàn)數(shù)據(jù)傳輸錯(cuò)誤。

          5.文章開頭所提出的問題,就是因?yàn)槌绦蜻\(yùn)行在X86架構(gòu)的PC SERVER上,發(fā)送數(shù)據(jù)的一端用C實(shí)現(xiàn)的,接收一端是用JAVA實(shí)現(xiàn)的,而發(fā)送端在發(fā)送數(shù)據(jù)前未進(jìn)行從主機(jī)字節(jié)序到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換,這樣接收端接收到的是LITTLE-ENDIAN的數(shù)據(jù),數(shù)據(jù)解釋自然出錯(cuò)。
          具體數(shù)據(jù)如下,實(shí)際發(fā)送的數(shù)據(jù)為23578
          發(fā)送端發(fā)送數(shù)據(jù): 1A 5C
          接收端接收到數(shù)據(jù)后,按BIG-ENDIAN進(jìn)行解釋具體數(shù)據(jù)是多少?你們自己去計(jì)算并比較吧!


          ===============================================================================================

          Big Endian and Little Endian

              談到字節(jié)序的問題,必然牽涉到兩大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存儲(chǔ)數(shù)據(jù),而x86系列則采用little endian方式存儲(chǔ)數(shù)據(jù)。那么究竟什么是big endian,什么又是little endian呢?

              其實(shí)big endian是指低地址存放最高有效字節(jié)(MSB),而little endian則是低地址存放最低有效字節(jié)(LSB),即常說的低位在先,高位在后。
              用文字說明可能比較抽象,下面用圖像加以說明。比如數(shù)字0x12345678在兩種不同字節(jié)序CPU中的存儲(chǔ)順序如下所示:

          Big Endian

            低地址                           高地址
            ----------------------------------------->
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |     12     |      34    |     56      |     78    |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

          Little Endian

            低地址                           高地址
            ----------------------------------------->
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |     78     |      56    |     34      |     12    |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

              從上面兩圖可以看出,采用big endian方式存儲(chǔ)數(shù)據(jù)是符合我們?nèi)祟惖乃季S習(xí)慣的。而little endian,!@#$%^&*,見鬼去吧 -_-|||

              為什么要注意字節(jié)序的問題呢?你可能這么問。當(dāng)然,如果你寫的程序只在單機(jī)環(huán)境下面運(yùn)行,并且不和別人的程序打交道,那么你完全可以忽略字節(jié)序的存在。但是,如果你的程序要跟別人的程序產(chǎn)生交互呢?尤其是當(dāng)你把你在微機(jī)上運(yùn)算的結(jié)果運(yùn)用到計(jì)算機(jī)群上去的話。在這里我想說說兩種語言。C/C++語言編寫的程序里數(shù)據(jù)存儲(chǔ)順序是跟編譯平臺(tái)所在的CPU相關(guān)的,而JAVA編寫的程序則唯一采用big endian方式來存儲(chǔ)數(shù)據(jù)。試想,如果你用C/C++語言在x86平臺(tái)下編寫的程序跟別人的JAVA程序互通時(shí)會(huì)產(chǎn)生什么結(jié)果?就拿上面的 0x12345678來說,你的程序傳遞給別人的一個(gè)數(shù)據(jù),將指向0x12345678的指針傳給了JAVA程序,由于JAVA采取big endian方式存儲(chǔ)數(shù)據(jù),很自然的它會(huì)將你的數(shù)據(jù)翻譯為0x78563412。什么?竟然變成另外一個(gè)數(shù)字了?是的,就是這種后果。因此,在你的C程序傳給JAVA程序之前有必要進(jìn)行字節(jié)序的轉(zhuǎn)換工作。

              無獨(dú)有偶,所有網(wǎng)絡(luò)協(xié)議也都是采用big endian的方式來傳輸數(shù)據(jù)的。所以有時(shí)我們也會(huì)把big endian方式稱之為網(wǎng)絡(luò)字節(jié)序。當(dāng)兩臺(tái)采用不同字節(jié)序的主機(jī)通信時(shí),在發(fā)送數(shù)據(jù)之前都必須經(jīng)過字節(jié)序的轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序后再進(jìn)行傳輸。ANSI C中提供了四個(gè)轉(zhuǎn)換字節(jié)序的宏。


          ========================================================================================================

          /**
          * 通信格式轉(zhuǎn)換
          *
          * Java和一些windows編程語言如c、c++、delphi所寫的網(wǎng)絡(luò)程序進(jìn)行通訊時(shí),需要進(jìn)行相應(yīng)的轉(zhuǎn)換
          * 高、低字節(jié)之間的轉(zhuǎn)換
          * windows的字節(jié)序?yàn)榈妥止?jié)開頭
          * linux,unix的字節(jié)序?yàn)楦咦止?jié)開頭
          * java則無論平臺(tái)變化,都是高字節(jié)開頭
          */

          public class FormatTransfer {
          /**
            * 將int轉(zhuǎn)為低字節(jié)在前,高字節(jié)在后的byte數(shù)組
            * @param n int
            * @return byte[]
            */
          public static byte[] toLH(int n) {
            byte[] b = new byte[4];
            b[0] = (byte) (n & 0xff);
            b[1] = (byte) (n >> 8 & 0xff);
            b[2] = (byte) (n >> 16 & 0xff);
            b[3] = (byte) (n >> 24 & 0xff);
            return b;
          }

          /**
            * 將int轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組
            * @param n int
            * @return byte[]
            */
          public static byte[] toHH(int n) {
            byte[] b = new byte[4];
            b[3] = (byte) (n & 0xff);
            b[2] = (byte) (n >> 8 & 0xff);
            b[1] = (byte) (n >> 16 & 0xff);
            b[0] = (byte) (n >> 24 & 0xff);
            return b;
          }

          /**
            * 將short轉(zhuǎn)為低字節(jié)在前,高字節(jié)在后的byte數(shù)組
            * @param n short
            * @return byte[]
            */
          public static byte[] toLH(short n) {
            byte[] b = new byte[2];
            b[0] = (byte) (n & 0xff);
            b[1] = (byte) (n >> 8 & 0xff);
            return b;
          }

          /**
            * 將short轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組
            * @param n short
            * @return byte[]
            */
          public static byte[] toHH(short n) {
            byte[] b = new byte[2];
            b[1] = (byte) (n & 0xff);
            b[0] = (byte) (n >> 8 & 0xff);
            return b;
          }

           

          /**
            * 將將int轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組

          public static byte[] toHH(int number) {
            int temp = number;
            byte[] b = new byte[4];
            for (int i = b.length - 1; i > -1; i--) {
              b = new Integer(temp & 0xff).byteValue();
              temp = temp >> 8;
            }
            return b;
          }

          public static byte[] IntToByteArray(int i) {
              byte[] abyte0 = new byte[4];
              abyte0[3] = (byte) (0xff & i);
              abyte0[2] = (byte) ((0xff00 & i) >> 8);
              abyte0[1] = (byte) ((0xff0000 & i) >> 16);
              abyte0[0] = (byte) ((0xff000000 & i) >> 24);
              return abyte0;
          }


          */

          /**
            * 將float轉(zhuǎn)為低字節(jié)在前,高字節(jié)在后的byte數(shù)組
            */
          public static byte[] toLH(float f) {
            return toLH(Float.floatToRawIntBits(f));
          }

          /**
            * 將float轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組
            */
          public static byte[] toHH(float f) {
            return toHH(Float.floatToRawIntBits(f));
          }

          /**
            * 將String轉(zhuǎn)為byte數(shù)組
            */
          public static byte[] stringToBytes(String s, int length) {
            while (s.getBytes().length < length) {
              s += " ";
            }
            return s.getBytes();
          }


          /**
            * 將字節(jié)數(shù)組轉(zhuǎn)換為String
            * @param b byte[]
            * @return String
            */
          public static String bytesToString(byte[] b) {
            StringBuffer result = new StringBuffer("");
            int length = b.length;
            for (int i=0; i<length; i++) {
              result.append((char)(b & 0xff));
            }
            return result.toString();
          }

          /**
            * 將字符串轉(zhuǎn)換為byte數(shù)組
            * @param s String
            * @return byte[]
            */
          public static byte[] stringToBytes(String s) {
            return s.getBytes();
          }

          /**
            * 將高字節(jié)數(shù)組轉(zhuǎn)換為int
            * @param b byte[]
            * @return int
            */
          public static int hBytesToInt(byte[] b) {
            int s = 0;
            for (int i = 0; i < 3; i++) {
              if (b >= 0) {
              s = s + b;
              } else {
              s = s + 256 + b;
              }
              s = s * 256;
            }
            if (b[3] >= 0) {
              s = s + b[3];
            } else {
              s = s + 256 + b[3];
            }
            return s;
          }

          /**
            * 將低字節(jié)數(shù)組轉(zhuǎn)換為int
            * @param b byte[]
            * @return int
            */
          public static int lBytesToInt(byte[] b) {
            int s = 0;
            for (int i = 0; i < 3; i++) {
              if (b[3-i] >= 0) {
              s = s + b[3-i];
              } else {
              s = s + 256 + b[3-i];
              }
              s = s * 256;
            }
            if (b[0] >= 0) {
              s = s + b[0];
            } else {
              s = s + 256 + b[0];
            }
            return s;
          }


          /**
            * 高字節(jié)數(shù)組到short的轉(zhuǎn)換
            * @param b byte[]
            * @return short
            */
          public static short hBytesToShort(byte[] b) {
            int s = 0;
            if (b[0] >= 0) {
              s = s + b[0];
              } else {
              s = s + 256 + b[0];
              }
              s = s * 256;
            if (b[1] >= 0) {
              s = s + b[1];
            } else {
              s = s + 256 + b[1];
            }
            short result = (short)s;
            return result;
          }

          /**
            * 低字節(jié)數(shù)組到short的轉(zhuǎn)換
            * @param b byte[]
            * @return short
            */
          public static short lBytesToShort(byte[] b) {
            int s = 0;
            if (b[1] >= 0) {
              s = s + b[1];
              } else {
              s = s + 256 + b[1];
              }
              s = s * 256;
            if (b[0] >= 0) {
              s = s + b[0];
            } else {
              s = s + 256 + b[0];
            }
            short result = (short)s;
            return result;
          }

          /**
            * 高字節(jié)數(shù)組轉(zhuǎn)換為float
            * @param b byte[]
            * @return float
            */
          public static float hBytesToFloat(byte[] b) {
            int i = 0;
            Float F = new Float(0.0);
            i = ((((b[0]&0xff)<<8 | (b[1]&0xff))<<8) | (b[2]&0xff))<<8 | (b[3]&0xff);
            return F.intBitsToFloat(i);
          }

          /**
            * 低字節(jié)數(shù)組轉(zhuǎn)換為float
            * @param b byte[]
            * @return float
            */
          public static float lBytesToFloat(byte[] b) {
            int i = 0;
            Float F = new Float(0.0);
            i = ((((b[3]&0xff)<<8 | (b[2]&0xff))<<8) | (b[1]&0xff))<<8 | (b[0]&0xff);
            return F.intBitsToFloat(i);
          }

          /**
            * 將byte數(shù)組中的元素倒序排列
            */
          public static byte[] bytesReverseOrder(byte[] b) {
            int length = b.length;
            byte[] result = new byte[length];
            for(int i=0; i<length; i++) {
              result[length-i-1] = b;
            }
            return result;
          }

          /**
            * 打印byte數(shù)組
            */
          public static void printBytes(byte[] bb) {
            int length = bb.length;
            for (int i=0; i<length; i++) {
              System.out.print(bb + " ");
            }
            System.out.println("");
          }

          public static void logBytes(byte[] bb) {
            int length = bb.length;
            String ut = "";
            for (int i=0; i<length; i++) {
              ut = out + bb + " ";
            }

          }

          /**
            * 將int類型的值轉(zhuǎn)換為字節(jié)序顛倒過來對(duì)應(yīng)的int值
            * @param i int
            * @return int
            */
          public static int reverseInt(int i) {
            int result = FormatTransfer.hBytesToInt(FormatTransfer.toLH(i));
            return result;
          }

          /**
            * 將short類型的值轉(zhuǎn)換為字節(jié)序顛倒過來對(duì)應(yīng)的short值
            * @param s short
            * @return short
            */
          public static short reverseShort(short s) {
            short result = FormatTransfer.hBytesToShort(FormatTransfer.toLH(s));
            return result;
          }

          /**
            * 將float類型的值轉(zhuǎn)換為字節(jié)序顛倒過來對(duì)應(yīng)的float值
            * @param f float
            * @return float
            */
          public static float reverseFloat(float f) {
            float result = FormatTransfer.hBytesToFloat(FormatTransfer.toLH(f));
            return result;
          }

          }

          posted @ 2007-10-24 09:57 比特鼠 閱讀(3409) | 評(píng)論 (0)編輯 收藏

          實(shí)現(xiàn)Leader/Fellows模式的項(xiàng)目--CAJ, 地址是:http://caj.cosylab.com/
          posted @ 2007-10-23 14:57 比特鼠 閱讀(200) | 評(píng)論 (0)編輯 收藏

          網(wǎng)址:http://httpd.apache.org/docs/2.0/programs/ab.html
          posted @ 2007-10-23 14:53 比特鼠 閱讀(276) | 評(píng)論 (0)編輯 收藏

          緩沖區(qū)基礎(chǔ)

          抽象類Buffer是java.nio包支持緩沖區(qū)的基礎(chǔ)。 Buffer 的工作方式就象內(nèi)存中用于讀寫基本數(shù)據(jù)類型的 RandomAccessFile 。象 RandomAccessFile 一樣,使用 Buffer ,所執(zhí)行的下一個(gè)操作(讀/寫)在當(dāng)前某個(gè)位置發(fā)生。執(zhí)行讀/寫操作中的任一個(gè)都會(huì)改變那個(gè)位置,所以在寫操作之后進(jìn)行讀操作不會(huì)讀到剛才所寫的內(nèi)容,而會(huì)讀到剛才所寫內(nèi)容之后的數(shù)據(jù)。 Buffer 提供了四個(gè)指示方法,用于訪問線性結(jié)構(gòu)(從最高值到最低值):

          capacity() :表明緩沖區(qū)的容量大小, 一旦確定了大小, 將不能再改變;
          limit() :告訴您到目前為止已經(jīng)往緩沖區(qū)填了多少字節(jié),或者讓您用 :limit(int newLimit) 來改變這個(gè)限制
          position() :告訴您當(dāng)前的位置,以執(zhí)行下一個(gè)讀/寫操作
          mark() :為了稍后用 reset() 進(jìn)行重新設(shè)置而記住某個(gè)位置
          flip() :交換限制指針和位置指針,然后將位置置為 0,并廢棄已經(jīng)做的mark標(biāo)記

          緩沖區(qū)的基本操作是讀 get() 和寫 put() ;然而,這些方法在子類中都是針對(duì)每種數(shù)據(jù)類型的特定方法。為了說明這一情況,讓我們研究一個(gè)簡(jiǎn)單示例,該示例演示了從同一個(gè)緩沖區(qū)讀和寫一個(gè)字符。在清單 1 中, flip() 方法交換限制和位置,然后將位置置為 0,并廢棄標(biāo)記,讓您讀剛才所寫的數(shù)據(jù):


          清單 1. 讀/寫示例
          import java.nio.*;
          ...
          CharBuffer buff = ...;
          buff.put('A');
          buff.flip();
          char c = buff.get();
          System.out.println("An A: " + c);
           


          現(xiàn)在讓我們研究一些具體的 Buffer 子類。

           

          緩沖區(qū)類型

          Merlin 具有 7 種特定的 Buffer 類型,每種類型對(duì)應(yīng)著一個(gè)基本數(shù)據(jù)類型(不包括 boolean):

          ByteBuffer       //存放任何除boolean類型外的其他基本類型
          CharBuffer       //存放char
          DoubleBuffer     //存放double
          FloatBuffer      //存放float
          IntBuffer        //存放int
          LongBuffer       //存放long
          ShortBuffer      //存放short

          在本文后面,我將討論第 8 種類型 MappedByteBuffer ,它用于內(nèi)存映射文件。如果您必須使用的類型不是這些基本類型,則可以先從 ByteBuffer 獲得字節(jié)類型,然后將其轉(zhuǎn)換成 Object 或其它任何類型。


          創(chuàng)建緩沖區(qū)
          一共有兩種類型的緩沖區(qū),直接緩沖區(qū)和非直接緩沖區(qū)。

          在創(chuàng)建緩沖區(qū)時(shí),可以要求創(chuàng)建直接緩沖區(qū),創(chuàng)建直接緩沖區(qū)的成本要比創(chuàng)建間接緩沖區(qū)高,但這可以使運(yùn)行時(shí)環(huán)境直接在該緩沖區(qū)上進(jìn)行較快的本機(jī) I/O 操作。因?yàn)閯?chuàng)建直接緩沖區(qū)所增加的成本,所以直接緩沖區(qū)只用于長(zhǎng)生存期的緩沖區(qū),而不用于短生存期、一次性且用完就丟棄的緩沖區(qū)。而且,只能在 ByteBuffer 這個(gè)級(jí)別上創(chuàng)建直接緩沖區(qū),如果希望使用其它類型,則必須將 Buffer 轉(zhuǎn)換成更具體的類型。

          判斷一個(gè)緩沖區(qū)是否是直接緩沖區(qū),可以調(diào)用isDirect()方法。

          有三種方式來獲取一個(gè)緩沖區(qū)的對(duì)象:
          a. 調(diào)用allocate()或者allocateDirect()方法直接分配,其中allocateDirect()返回的是直接緩沖區(qū)。
          b. 包裝一個(gè)數(shù)組,如:
                byte[] b = new byte[1024];
                ByteBuffer bb = ByteBuffer.wrap(b);
          c. 內(nèi)存映射,即調(diào)用FileChannel的map()方法。

          緩沖區(qū)基本屬性
          這幾個(gè)屬性是每個(gè)緩沖區(qū)都有的并且是常用的操作。
          a. 容量(capacity),緩沖區(qū)大小
          b. 限制(limit),第一個(gè)不應(yīng)被讀取或?qū)懭氲淖止?jié)的索引,總是小于容量。
          c. 位置(position),下一個(gè)被讀取或?qū)懭氲淖止?jié)的索引,總是小于限制。
          d. clear()方法:設(shè)置limit為capacity,position為0。
          e. filp()方法:設(shè)置limit為當(dāng)前position,然后設(shè)置position為0。
          f. rewind()方法:保持limit不變,設(shè)置position為0。

          緩沖區(qū)數(shù)據(jù)操作
          操作包括了讀取和寫入數(shù)據(jù)兩種。
          讀取數(shù)據(jù)使用get()及其系列方法,除boolean外,每一種類型包括了對(duì)應(yīng)的get()方法,如getInt(),getChar()等,get()方法用來讀取字節(jié),支持相對(duì)和絕對(duì)索引兩種方式。
          寫入數(shù)據(jù)使用put()及其系列方法,和get()方法是對(duì)應(yīng)的。

          package nio;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.nio.ByteBuffer;
          import java.nio.channels.FileChannel;

          public class BufferDemo ...{

              
              public static void main(String[] args) throws Exception...{
                  //分配一個(gè)非直接緩沖區(qū)
                  ByteBuffer bb = ByteBuffer.allocate(100);
                  //向緩沖區(qū)寫入0到100的字節(jié)制
                  for(int i = 0; i <100; i++)...{
                      byte b = (byte) (Math.random() * 100);
                      bb.put(b);
                  }
                  
                  System.out.println("寫入文件前的緩沖區(qū)數(shù)據(jù)");
                  bb.flip();
                  while(bb.hasRemaining())
                      System.out.print(bb.get() + " ");
                  System.out.println();
                  
                  //獲取一個(gè)關(guān)聯(lián)到文件buffer.txt的信道
                  FileChannel fc = new FileOutputStream("buffer.txt").getChannel();
                  //將緩沖區(qū)數(shù)據(jù)寫到文件中
                  bb.flip();
                  fc.write(bb);
                  //防止緩存
                  fc.force(true);
                  //關(guān)閉信道
                  fc.close();
                  bb = null;
                  fc = null;
                  
                  //下面從文件中讀取數(shù)據(jù)
                  fc = new FileInputStream("buffer.txt").getChannel();
                  ByteBuffer bb2 = ByteBuffer.allocate((int) fc.size());
                  fc.read(bb2);
                  System.out.println("從文件讀取的緩沖區(qū)數(shù)據(jù)");
                  bb2.flip();
                  while(bb2.hasRemaining())
                      System.out.print(bb2.get() + " ");
                  System.out.println();
                  fc.close();
                  bb2 = null;
                  fc = null;
                  

              }

          }

          內(nèi)存映射文件

          第 8 種 Buffer 類型 MappedByteBuffer 只是一種特殊的 ByteBuffer 。 MappedByteBuffer 將文件所在區(qū)域直接映射到內(nèi)存。通常,該區(qū)域包含整個(gè)文件,但也可以只映射部分文件。所以,必須指定要映射文件的哪部分。而且,與其它 Buffer 對(duì)象一樣,這里沒有構(gòu)造函數(shù);必須讓 java.nio.channels.FileChannel 的 map() 方法來獲取 MappedByteBuffer 。此外,無需過多涉及通道就可以用 getChannel() 方法從 FileInputStream 或 FileOutputStream 獲取 FileChannel 。通過從命令行傳入文件名來讀取文本文件的內(nèi)容,清單 4 顯示了 MappedByteBuffer :


          清單 4. 讀取內(nèi)存映射文本文件
          import java.io.*;
          import java.nio.*;
          import java.nio.channels.*;
          import java.nio.charset.*;
          public class ReadFileBuff {
            public static void main(String args[]) throws IOException {
               if (args.length != 0) {
                String filename = args[0];
                FileInputStream fis = new FileInputStream(filename);
                FileChannel channel = fis.getChannel();
                int length = (int)channel.size();
                MappedByteBuffer byteBuffer =
                  channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
                Charset charset = Charset.forName("ISO-8859-1");
                CharsetDecoder decoder = charset.newDecoder();
                CharBuffer charBuffer = decoder.decode(byteBuffer);
                for (int i=0, n=charBuffer.length(); i<n; i++) {
                  System.out.print(charBuffer.get());
                }
              }
            }
          }

          posted @ 2007-08-01 11:13 比特鼠 閱讀(3829) | 評(píng)論 (0)編輯 收藏

          1. 左移操作: x << n
            x可以是byte, short, char, int, long基本類型, n(位移量)只能是int型

            編譯器的執(zhí)行步驟:
            1) 如果x是byte, short, char類型, 則將x提升為int;
            2) 如果x是byte, short, char, int類型, 則n被重新賦值(過程是:取n的補(bǔ)碼的低5位再轉(zhuǎn)成十進(jìn)制的int值,相當(dāng)對(duì)n取32模: n=n%32);
               如果x是long型, 則n被重新賦值(過程是:取n的補(bǔ)碼的低6位再轉(zhuǎn)成十進(jìn)制的int值,相當(dāng)對(duì)n取64模: n=n%64);
               (因?yàn)閕nt類型為4個(gè)字節(jié),即32位,移動(dòng)32位將沒有任何意義.對(duì)于long則是模64)
            3) 對(duì)x左移n個(gè)位數(shù), 整個(gè)表達(dá)式產(chǎn)生一個(gè)新值(x的值不變);
          2. <<是左移符號(hào),列x<<1,就是x的內(nèi)容左移一位(x的內(nèi)容并不改變)
          3. >>是帶符號(hào)位的右移符號(hào),x>>1就是x的內(nèi)容右移一位,如果開頭是1則補(bǔ)1,是0責(zé)補(bǔ)0,(x的內(nèi)容并不改變).
          4. >>>是不帶符號(hào)位的右移,x>>>1就是x的內(nèi)容右移一位,開頭補(bǔ)0(x的內(nèi)容并不改變)
          posted @ 2007-08-01 10:12 比特鼠 閱讀(2809) | 評(píng)論 (0)編輯 收藏

          原文地址 http://www.programbbs.com/doc/2433.htm
          為什么會(huì)排隊(duì)等待?

          下面的這個(gè)簡(jiǎn)單的 Java 程序完成四項(xiàng)不相關(guān)的任務(wù)。這樣的程序有單個(gè)控制線程,控制在這四個(gè)任務(wù)之間線性地移動(dòng)。此外,因?yàn)樗璧馁Y源 — 打印機(jī)、磁盤、數(shù)據(jù)庫(kù)和顯示屏 -- 由于硬件和軟件的限制都有內(nèi)在的潛伏時(shí)間,所以每項(xiàng)任務(wù)都包含明顯的等待時(shí)間。因此,程序在訪問數(shù)據(jù)庫(kù)之前必須等待打印機(jī)完成打印文件的任務(wù),等等。如果您正在等待程序的完成,則這是對(duì)計(jì)算資源和您的時(shí)間的一種拙劣使用。改進(jìn)此程序的一種方法是使它成為多線程的。
           
          四項(xiàng)不相關(guān)的任務(wù)
           

          class myclass {
              static public void main(String args[]) {
                  print_a_file();
                  manipulate_another_file();
                  access_database();
                  draw_picture_on_screen();
              }
          }

          在本例中,每項(xiàng)任務(wù)在開始之前必須等待前一項(xiàng)任務(wù)完成,即使所涉及的任務(wù)毫不相關(guān)也是這樣。但是,在現(xiàn)實(shí)生活中,我們經(jīng)常使用多線程模型。我們?cè)谔幚砟承┤蝿?wù)的同時(shí)也可以讓孩子、配偶和父母完成別的任務(wù)。例如,我在寫信的同時(shí)可能打發(fā)我的兒子去郵局買郵票。用軟件術(shù)語來說,這稱為多個(gè)控制(或執(zhí)行)線程。

          可以用兩種不同的方法來獲得多個(gè)控制線程:

          多個(gè)進(jìn)程
          在大多數(shù)操作系統(tǒng)中都可以創(chuàng)建多個(gè)進(jìn)程。當(dāng)一個(gè)程序啟動(dòng)時(shí),它可以為即將開始的每項(xiàng)任務(wù)創(chuàng)建一個(gè)進(jìn)程,并允許它們同時(shí)運(yùn)行。當(dāng)一個(gè)程序因等待網(wǎng)絡(luò)訪問或用戶輸入而被阻塞時(shí),另一個(gè)程序還可以運(yùn)行,這樣就增加了資源利用率。但是,按照這種方式創(chuàng)建每個(gè)進(jìn)程要付出一定的代價(jià):設(shè)置一個(gè)進(jìn)程要占用相當(dāng)一部分處理器時(shí)間和內(nèi)存資源。而且,大多數(shù)操作系統(tǒng)不允許進(jìn)程訪問其他進(jìn)程的內(nèi)存空間。因此,進(jìn)程間的通信很不方便,并且也不會(huì)將它自己提供給容易的編程模型。


          線程
          線程也稱為輕型進(jìn)程 (LWP)。因?yàn)榫€程只能在單個(gè)進(jìn)程的作用域內(nèi)活動(dòng),所以創(chuàng)建線程比創(chuàng)建進(jìn)程要廉價(jià)得多。這樣,因?yàn)榫€程允許協(xié)作和數(shù)據(jù)交換,并且在計(jì)算資源方面非常廉價(jià),所以線程比進(jìn)程更可取。線程需要操作系統(tǒng)的支持,因此不是所有的機(jī)器都提供線程。Java 編程語言,作為相當(dāng)新的一種語言,已將線程支持與語言本身合為一體,這樣就對(duì)線程提供了強(qiáng)健的支持。


          使用 Java 編程語言實(shí)現(xiàn)線程
          Java 編程語言使多線程如此簡(jiǎn)單有效,以致于某些程序員說它實(shí)際上是自然的。盡管在 Java 中使用線程比在其他語言中要容易得多,仍然有一些概念需要掌握。要記住的一件重要的事情是 main() 函數(shù)也是一個(gè)線程,并可用來做有用的工作。程序員只有在需要多個(gè)線程時(shí)才需要?jiǎng)?chuàng)建新的線程。

          Thread 類
          Thread 類是一個(gè)具體的類,即不是抽象類,該類封裝了線程的行為。要?jiǎng)?chuàng)建一個(gè)線程,程序員必須創(chuàng)建一個(gè)從 Thread 類導(dǎo)出的新類。程序員必須覆蓋 Thread 的 run() 函數(shù)來完成有用的工作。用戶并不直接調(diào)用此函數(shù);而是必須調(diào)用 Thread 的 start() 函數(shù),該函數(shù)再調(diào)用 run()。下面的代碼說明了它的用法:

          創(chuàng)建兩個(gè)新線程

          import java.util.*;

          class TimePrinter extends Thread {
              int pauseTime;

              String name;

              public TimePrinter(int x, String n) {
                  pauseTime = x;
                  name = n;
              }

              public void run() {
                  while (true) {
                      try {
                          System.out.println(name + ":"
                                  + new Date(System.currentTimeMillis()));
                          Thread.sleep(pauseTime);
                      } catch (Exception e) {
                          System.out.println(e);
                      }
                  }
              }

              static public void main(String args[]) {
                  TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
                  tp1.start();
                  TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
                  tp2.start();

              }
          }

          在本例中,我們可以看到一個(gè)簡(jiǎn)單的程序,它按兩個(gè)不同的時(shí)間間隔(1 秒和 3 秒)在屏幕上顯示當(dāng)前時(shí)間。這是通過創(chuàng)建兩個(gè)新線程來完成的,包括 main() 共三個(gè)線程。但是,因?yàn)橛袝r(shí)要作為線程運(yùn)行的類可能已經(jīng)是某個(gè)類層次的一部分,所以就不能再按這種機(jī)制創(chuàng)建線程。雖然在同一個(gè)類中可以實(shí)現(xiàn)任意數(shù)量的接口,但 Java 編程語言只允許一個(gè)類有一個(gè)父類。同時(shí),某些程序員避免從 Thread 類導(dǎo)出,因?yàn)樗鼜?qiáng)加了類層次。對(duì)于這種情況,就要 runnable 接口。

          Runnable 接口
          此接口只有一個(gè)函數(shù),run(),此函數(shù)必須由實(shí)現(xiàn)了此接口的類實(shí)現(xiàn)。但是,就運(yùn)行這個(gè)類而論,其語義與前一個(gè)示例稍有不同。我們可以用 runnable 接口改寫前一個(gè)示例。(不同的部分用黑體表示。)

          創(chuàng)建兩個(gè)新線程而不強(qiáng)加類層次

          import java.util.*;

          class TimePrinter implements Runnable {
              int pauseTime;

              String name;

              public TimePrinter(int x, String n) {
                  pauseTime = x;
                  name = n;
              }

              public void run() {
                  while (true) {
                      try {
                          System.out.println(name + ":"
                                  + new Date(System.currentTimeMillis()));
                          Thread.sleep(pauseTime);
                      } catch (Exception e) {
                          System.out.println(e);
                      }
                  }
              }

              static public void main(String args[]) {
                  Thread t1 = new Thread(new TimePrinter(1000, "Fast Guy"));
                  t1.start();
                  Thread t2 = new Thread(new TimePrinter(3000, "Slow Guy"));
                  t2.start();

              }
          }

          請(qǐng)注意,當(dāng)使用 runnable 接口時(shí),您不能直接創(chuàng)建所需類的對(duì)象并運(yùn)行它;必須從 Thread 類的一個(gè)實(shí)例內(nèi)部運(yùn)行它。許多程序員更喜歡 runnable 接口,因?yàn)閺?Thread 類繼承會(huì)強(qiáng)加類層次。

          synchronized 關(guān)鍵字
          到目前為止,我們看到的示例都只是以非常簡(jiǎn)單的方式來利用線程。只有最小的數(shù)據(jù)流,而且不會(huì)出現(xiàn)兩個(gè)線程訪問同一個(gè)對(duì)象的情況。但是,在大多數(shù)有用的程序中,線程之間通常有信息流。試考慮一個(gè)金融應(yīng)用程序,它有一個(gè) Account 對(duì)象,如下例中所示:

          一個(gè)銀行中的多項(xiàng)活動(dòng)

          public class Account {
              String holderName;

              float amount;

              public Account(String name, float amt) {
                  holderName = name;
                  amount = amt;
              }

              public void deposit(float amt) {
                  amount += amt;
              }

              public void withdraw(float amt) {
                  amount -= amt;
              }

              public float checkBalance() {
                  return amount;
              }
          }

          在此代碼樣例中潛伏著一個(gè)錯(cuò)誤。如果此類用于單線程應(yīng)用程序,不會(huì)有任何問題。但是,在多線程應(yīng)用程序的情況中,不同的線程就有可能同時(shí)訪問同一個(gè) Account 對(duì)象,比如說一個(gè)聯(lián)合帳戶的所有者在不同的 ATM 上同時(shí)進(jìn)行訪問。在這種情況下,存入和支出就可能以這樣的方式發(fā)生:一個(gè)事務(wù)被另一個(gè)事務(wù)覆蓋。這種情況將是災(zāi)難性的。但是,Java 編程語言提供了一種簡(jiǎn)單的機(jī)制來防止發(fā)生這種覆蓋。每個(gè)對(duì)象在運(yùn)行時(shí)都有一個(gè)關(guān)聯(lián)的鎖。這個(gè)鎖可通過為方法添加關(guān)鍵字 synchronized 來獲得。這樣,修訂過的 Account 對(duì)象(如下所示)將不會(huì)遭受像數(shù)據(jù)損壞這樣的錯(cuò)誤:

          對(duì)一個(gè)銀行中的多項(xiàng)活動(dòng)進(jìn)行同步處理

          public class Account {
              String holderName;

              float amount;

              public Account(String name, float amt) {
                  holderName = name;
                  amount = amt;
              }

              public synchronized void deposit(float amt) {
                  amount += amt;
              }

              public synchronized void withdraw(float amt) {
                  amount -= amt;
              }

              public float checkBalance() {
                  return amount;
              }
          }

          deposit() 和 withdraw() 函數(shù)都需要這個(gè)鎖來進(jìn)行操作,所以當(dāng)一個(gè)函數(shù)運(yùn)行時(shí),另一個(gè)函數(shù)就被阻塞。請(qǐng)注意,checkBalance() 未作更改,它嚴(yán)格是一個(gè)讀函數(shù)。因?yàn)?checkBalance() 未作同步處理,所以任何其他方法都不會(huì)阻塞它,它也不會(huì)阻塞任何其他方法,不管那些方法是否進(jìn)行了同步處理。

          Java 編程語言中的高級(jí)多線程支持

          線程組
          線程是被個(gè)別創(chuàng)建的,但可以將它們歸類到線程組中,以便于調(diào)試和監(jiān)視。只能在創(chuàng)建線程的同時(shí)將它與一個(gè)線程組相關(guān)聯(lián)。在使用大量線程的程序中,使用線程組組織線程可能很有幫助。可以將它們看作是計(jì)算機(jī)上的目錄和文件結(jié)構(gòu)。

          線程間發(fā)信
          當(dāng)線程在繼續(xù)執(zhí)行前需要等待一個(gè)條件時(shí),僅有 synchronized 關(guān)鍵字是不夠的。雖然 synchronized 關(guān)鍵字阻止并發(fā)更新一個(gè)對(duì)象,但它沒有實(shí)現(xiàn)線程間發(fā)信。Object 類為此提供了三個(gè)函數(shù):wait()、notify() 和 notifyAll()。以全球氣候預(yù)測(cè)程序?yàn)槔_@些程序通過將地球分為許多單元,在每個(gè)循環(huán)中,每個(gè)單元的計(jì)算都是隔離進(jìn)行的,直到這些值趨于穩(wěn)定,然后相鄰單元之間就會(huì)交換一些數(shù)據(jù)。所以,從本質(zhì)上講,在每個(gè)循環(huán)中各個(gè)線程都必須等待所有線程完成各自的任務(wù)以后才能進(jìn)入下一個(gè)循環(huán)。這個(gè)模型稱為屏蔽同步,下例說明了這個(gè)模型:

          屏蔽同步

          public class BSync {
              int totalThreads;

              int currentThreads;

              public BSync(int x) {
                  totalThreads = x;
                  currentThreads = 0;
              }

              public synchronized void waitForAll() {
                  currentThreads++;
                  if (currentThreads < totalThreads) {
                      try {
                          wait();
                      } catch (Exception e) {
                      }
                  } else {
                      currentThreads = 0;
                      notifyAll();
                  }
              }
          }

          當(dāng)對(duì)一個(gè)線程調(diào)用 wait() 時(shí),該線程就被有效阻塞,只到另一個(gè)線程對(duì)同一個(gè)對(duì)象調(diào)用 notify() 或 notifyAll() 為止。因此,在前一個(gè)示例中,不同的線程在完成它們的工作以后將調(diào)用 waitForAll() 函數(shù),最后一個(gè)線程將觸發(fā) notifyAll() 函數(shù),該函數(shù)將釋放所有的線程。第三個(gè)函數(shù) notify() 只通知一個(gè)正在等待的線程,當(dāng)對(duì)每次只能由一個(gè)線程使用的資源進(jìn)行訪問限制時(shí),這個(gè)函數(shù)很有用。但是,不可能預(yù)知哪個(gè)線程會(huì)獲得這個(gè)通知,因?yàn)檫@取決于 Java 虛擬機(jī) (JVM) 調(diào)度算法。

          將 CPU 讓給另一個(gè)線程
          當(dāng)線程放棄某個(gè)稀有的資源(如數(shù)據(jù)庫(kù)連接或網(wǎng)絡(luò)端口)時(shí),它可能調(diào)用 yield() 函數(shù)臨時(shí)降低自己的優(yōu)先級(jí),以便某個(gè)其他線程能夠運(yùn)行。

          守護(hù)線程
          有兩類線程:用戶線程和守護(hù)線程。用戶線程是那些完成有用工作的線程。守護(hù)線程是那些僅提供輔助功能的線程。Thread 類提供了 setDaemon() 函數(shù)。Java 程序?qū)⑦\(yùn)行到所有用戶線程終止,然后它將破壞所有的守護(hù)線程。在 Java 虛擬機(jī) (JVM) 中,即使在 main 結(jié)束以后,如果另一個(gè)用戶線程仍在運(yùn)行,則程序仍然可以繼續(xù)運(yùn)行。

          避免不提倡使用的方法
          不提倡使用的方法是為支持向后兼容性而保留的那些方法,它們?cè)谝院蟮陌姹局锌赡艹霈F(xiàn),也可能不出現(xiàn)。Java 多線程支持在版本 1.1 和版本 1.2 中做了重大修訂,stop()、suspend() 和 resume() 函數(shù)已不提倡使用。這些函數(shù)在 JVM 中可能引入微妙的錯(cuò)誤。雖然函數(shù)名可能聽起來很誘人,但請(qǐng)抵制誘惑不要使用它們。

          調(diào)試線程化的程序
          在線程化的程序中,可能發(fā)生的某些常見而討厭的情況是死鎖、活鎖、內(nèi)存損壞和資源耗盡。

          死鎖
          死鎖可能是多線程程序最常見的問題。當(dāng)一個(gè)線程需要一個(gè)資源而另一個(gè)線程持有該資源的鎖時(shí),就會(huì)發(fā)生死鎖。這種情況通常很難檢測(cè)。但是,解決方案卻相當(dāng)好:在所有的線程中按相同的次序獲取所有資源鎖。例如,如果有四個(gè)資源 —A、B、C 和 D — 并且一個(gè)線程可能要獲取四個(gè)資源中任何一個(gè)資源的鎖,則請(qǐng)確保在獲取對(duì) B 的鎖之前首先獲取對(duì) A 的鎖,依此類推。如果“線程 1”希望獲取對(duì) B 和 C 的鎖,而“線程 2”獲取了 A、C 和 D 的鎖,則這一技術(shù)可能導(dǎo)致阻塞,但它永遠(yuǎn)不會(huì)在這四個(gè)鎖上造成死鎖。

          活鎖
          當(dāng)一個(gè)線程忙于接受新任務(wù)以致它永遠(yuǎn)沒有機(jī)會(huì)完成任何任務(wù)時(shí),就會(huì)發(fā)生活鎖。這個(gè)線程最終將超出緩沖區(qū)并導(dǎo)致程序崩潰。試想一個(gè)秘書需要錄入一封信,但她一直在忙于接電話,所以這封信永遠(yuǎn)不會(huì)被錄入。

          內(nèi)存損壞
          如果明智地使用 synchronized 關(guān)鍵字,則完全可以避免內(nèi)存錯(cuò)誤這種氣死人的問題。

          資源耗盡
          某些系統(tǒng)資源是有限的,如文件描述符。多線程程序可能耗盡資源,因?yàn)槊總€(gè)線程都可能希望有一個(gè)這樣的資源。如果線程數(shù)相當(dāng)大,或者某個(gè)資源的侯選線程數(shù)遠(yuǎn)遠(yuǎn)超過了可用的資源數(shù),則最好使用資源池。一個(gè)最好的示例是數(shù)據(jù)庫(kù)連接池。只要線程需要使用一個(gè)數(shù)據(jù)庫(kù)連接,它就從池中取出一個(gè),使用以后再將它返回池中。資源池也稱為資源庫(kù)。

          調(diào)試大量的線程
          有時(shí)一個(gè)程序因?yàn)橛写罅康木€程在運(yùn)行而極難調(diào)試。在這種情況下,下面的這個(gè)類可能會(huì)派上用場(chǎng):

          public class Probe extends Thread {
              public Probe() {
              }

              public void run() {

                  while (true) {
                      Thread[] x = new Thread[100];
                      Thread.enumerate(x);

                      for (int i = 0; i < 100; i++) {
                          Thread t = x[i];
                          if (t == null)
                              break;
                          else
                              System.out.println(t.getName() + "\t" + t.getPriority()
                                      + "\t" + t.isAlive() + "\t" + t.isDaemon());
                      }
                  }
              }
          }

          限制線程優(yōu)先級(jí)和調(diào)度
          Java 線程模型涉及可以動(dòng)態(tài)更改的線程優(yōu)先級(jí)。本質(zhì)上,線程的優(yōu)先級(jí)是從 1 到 10 之間的一個(gè)數(shù)字,數(shù)字越大表明任務(wù)越緊急。JVM 標(biāo)準(zhǔn)首先調(diào)用優(yōu)先級(jí)較高的線程,然后才調(diào)用優(yōu)先級(jí)較低的線程。但是,該標(biāo)準(zhǔn)對(duì)具有相同優(yōu)先級(jí)的線程的處理是隨機(jī)的。如何處理這些線程取決于基層的操作系統(tǒng)策略。在某些情況下,優(yōu)先級(jí)相同的線程分時(shí)運(yùn)行;在另一些情況下,線程將一直運(yùn)行到結(jié)束。請(qǐng)記住,Java 支持 10 個(gè)優(yōu)先級(jí),基層操作系統(tǒng)支持的優(yōu)先級(jí)可能要少得多,這樣會(huì)造成一些混亂。因此,只能將優(yōu)先級(jí)作為一種很粗略的工具使用。最后的控制可以通過明智地使用 yield() 函數(shù)來完成。通常情況下,請(qǐng)不要依靠線程優(yōu)先級(jí)來控制線程的狀態(tài)。

          小結(jié)
          本文說明了在 Java 程序中如何使用線程。像是否應(yīng)該使用線程這樣的更重要的問題在很大程序上取決于手頭的應(yīng)用程序。決定是否在應(yīng)用程序中使用多線程的一種方法是,估計(jì)可以并行運(yùn)行的代碼量。并記住以下幾點(diǎn):

          使用多線程不會(huì)增加 CPU 的能力。但是如果使用 JVM 的本地線程實(shí)現(xiàn),則不同的線程可以在不同的處理器上同時(shí)運(yùn)行(在多 CPU 的機(jī)器中),從而使多 CPU 機(jī)器得到充分利用。
          如果應(yīng)用程序是計(jì)算密集型的,并受 CPU 功能的制約,則只有多 CPU 機(jī)器能夠從更多的線程中受益。
          當(dāng)應(yīng)用程序必須等待緩慢的資源(如網(wǎng)絡(luò)連接或數(shù)據(jù)庫(kù)連接)時(shí),或者當(dāng)應(yīng)用程序是非交互式的時(shí),多線程通常是有利的。
          基于 Internet 的軟件有必要是多線程的;否則,用戶將感覺應(yīng)用程序反映遲鈍。例如,當(dāng)開發(fā)要支持大量客戶機(jī)的服務(wù)器時(shí),多線程可以使編程較為容易。在這種情況下,每個(gè)線程可以為不同的客戶或客戶組服務(wù),從而縮短了響應(yīng)時(shí)間。

          某些程序員可能在 C 和其他語言中使用過線程,在那些語言中對(duì)線程沒有語言支持。這些程序員可能通常都被搞得對(duì)線程失去了信心。

          posted @ 2007-07-30 09:36 比特鼠 閱讀(218) | 評(píng)論 (0)編輯 收藏

          眾所周知, Java在從XML文件中裝載內(nèi)容到內(nèi)存過程中,不論用何種方式,IO操作的開銷都無可避免。本文嘗試比較dom4j中的XPP3和SAX兩種方式裝載XML文件的性能,以便將IO操作的開銷降到最小!

          package gz.lwm;

          import java.io.File;
          import org.apache.log4j.Logger;
          import org.dom4j.Document;
          import org.dom4j.DocumentHelper;
          import org.dom4j.io.SAXReader;
          import org.dom4j.io.XPP3Reader;

          public class TestDom4j {
           private static final Logger log = Logger.getLogger(TestDom4j.class);
           private static long bt; 
           
           public static void main(String[] args) {
            Document doc = DocumentHelper.createDocument();   
            //先運(yùn)行g(shù)etXmlSAX()
            bt = System.currentTimeMillis();
            String strXml = getXmlSAX("xml/test.xml");
            if(log.isDebugEnabled()){
             log.debug("\ngetXmlSAX() use time: " + (System.currentTimeMillis() - bt) + " millis\n");
            }

            //再運(yùn)行g(shù)etXmlXPP3()
            bt = System.currentTimeMillis();
            String s1 =getXmlXPP3("xml/test.xml");
            if(log.isDebugEnabled()){
             log.debug("\ngetXmlXPP3() use time: " + (System.currentTimeMillis() - bt) + " millis\n");
            }
            
            
           }
           
           public static String getXmlSAX(String xmlFile){
            String result = "";
            try {
             SAXReader reader = new SAXReader();
             Document document = reader.read(new File(xmlFile));
             result = document.asXML();
            } catch (Exception e) {
             e.printStackTrace();
            }
            return result;
           }
           
           public static String getXmlXPP3(String xmlFile){
            String result = "";
            try {
             XPP3Reader reader = new XPP3Reader();
             Document document = reader.read(new File(xmlFile));
             result = document.asXML();
            } catch (Exception e) {
             e.printStackTrace();
            }
            return result;
           }


           
          }

          有沒有這一句"Document doc = DocumentHelper.createDocument()",對(duì)性能的影響很大,特別是對(duì)大xml文件(盡管并沒有使用doc)

          另外, getXmlXSAX()和getXmlXPP3()運(yùn)行的先后次序?qū)π阅艿挠绊懸埠艽螅?br>
          測(cè)試:
              在我的機(jī)器上,對(duì)一個(gè)100k左右的XML文件進(jìn)行多次測(cè)試后的均值結(jié)果為:

              getXmlXPP3() use time: 265 millis
              ...
              getXmlXSAX() use time: 359 millis
              ...

          結(jié)論:
              通過比較,在讀取XML文件上,XPP3略為優(yōu)于SAX!


          注意:

          要運(yùn)行例子,classpath需包含:
          dom4j-1.6.1.jar
          jaxen-1.1-beta-10.jar
          log4j-1.2.9.jar
          pull-parser-2.1.10.jar
          xpp3-1.1.4c.jar


          參考:
          dom4j :  http://www.dom4j.org/
          XPP   :  http://www.extreme.indiana.edu/xgws/xsoap/xpp/

          posted @ 2007-05-19 00:39 比特鼠 閱讀(2513) | 評(píng)論 (0)編輯 收藏

             Namespace namespace ...

             //第一種方法
             Document doc = DocumentHelper.createDocument();
             Element root = doc.addElement("Root", namespace.getURI());
             Element eResultMessage = root.addElement("ResultMessage");

             結(jié)果為:
             <Root xmlns="http://aaaaaa"><ResultMessage>...</ResultMessage></Root>



             //第二種方法
             Document doc = DocumentHelper.createDocument();
             Element root = doc.addElement(("Root");
             root.add(namespace);
             Element eResultMessage = root.addElement("ResultMessage");
             
             結(jié)果為:
             <Root xmlns="
          http://aaaaaa"><ResultMessage xmlns="">...</ResultMessage></Root>

          posted @ 2007-05-17 21:08 比特鼠 閱讀(2662) | 評(píng)論 (0)編輯 收藏

          正則表達(dá)式語法 
           

          正則表達(dá)式是一種文本模式,包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為“元字符”)。模式描述在搜索文本時(shí)要匹配的一個(gè)或多個(gè)字符串。

          正則表達(dá)式示例
           
          表達(dá)式  匹配 
          /^\s*$/
           匹配空行。
           
          /\d{2}-\d{5}/
           驗(yàn)證由兩位數(shù)字、一個(gè)連字符再加 5 位數(shù)字組成的 ID 號(hào)。
           
          /<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*\/\1\s*>/
           匹配 HTML 標(biāo)記。
           

          下表包含了元字符的完整列表以及它們?cè)谡齽t表達(dá)式上下文中的行為:

           
          字符  說明 
          \
           將下一字符標(biāo)記為特殊字符、文本、反向引用或八進(jìn)制轉(zhuǎn)義符。例如,“n”匹配字符“n”。“\n”匹配換行符。序列“\\”匹配“\”,“\(”匹配“(”。
           
          ^
           匹配輸入字符串開始的位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,^ 還會(huì)與“\n”或“\r”之后的位置匹配。
           
          $
           匹配輸入字符串結(jié)尾的位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,$ 還會(huì)與“\n”或“\r”之前的位置匹配。
           
          *
           零次或多次匹配前面的字符或子表達(dá)式。例如,zo* 匹配“z”和“zoo”。* 等效于 {0,}。
           
          +
           一次或多次匹配前面的字符或子表達(dá)式。例如,“zo+”與“zo”和“zoo”匹配,但與“z”不匹配。+ 等效于 {1,}。
           
          ?
           零次或一次匹配前面的字符或子表達(dá)式。例如,“do(es)?”匹配“do”或“does”中的“do”。? 等效于 {0,1}。
           
          {n}
           n 是非負(fù)整數(shù)。正好匹配 n 次。例如,“o{2}”與“Bob”中的“o”不匹配,但與“food”中的兩個(gè)“o”匹配。
           
          {n,}
           n 是非負(fù)整數(shù)。至少匹配 n 次。例如,“o{2,}”不匹配“Bob”中的“o”,而匹配“foooood”中的所有 o。“o{1,}”等效于“o+”。“o{0,}”等效于“o*”。
           
          {n,m}
           M 和 n 是非負(fù)整數(shù),其中 n <= m。匹配至少 n 次,至多 m 次。例如,“o{1,3}”匹配“fooooood”中的頭三個(gè) o。'o{0,1}' 等效于 'o?'。注意:您不能將空格插入逗號(hào)和數(shù)字之間。
           
          ?
           當(dāng)此字符緊隨任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后時(shí),匹配模式是“非貪心的”。“非貪心的”模式匹配搜索到的、盡可能短的字符串,而默認(rèn)的“貪心的”模式匹配搜索到的、盡可能長(zhǎng)的字符串。例如,在字符串“oooo”中,“o+?”只匹配單個(gè)“o”,而“o+”匹配所有“o”。
           
          .
           匹配除“\n”之外的任何單個(gè)字符。若要匹配包括“\n”在內(nèi)的任意字符,請(qǐng)使用諸如“[\s\S]”之類的模式。
           
          (pattern)
           匹配 pattern 并捕獲該匹配的子表達(dá)式。可以使用 $0…$9 屬性從結(jié)果“匹配”集合中檢索捕獲的匹配。若要匹配括號(hào)字符 ( ),請(qǐng)使用“\(”或者“\)”。
           
          (?:pattern)
           匹配 pattern 但不捕獲該匹配的子表達(dá)式,即它是一個(gè)非捕獲匹配,不存儲(chǔ)供以后使用的匹配。這對(duì)于用“or”字符 (|) 組合模式部件的情況很有用。例如,'industr(?:y|ies) 是比 'industry|industries' 更經(jīng)濟(jì)的表達(dá)式。
           
          (?=pattern)
           執(zhí)行正向預(yù)測(cè)先行搜索的子表達(dá)式,該表達(dá)式匹配處于匹配 pattern 的字符串的起始點(diǎn)的字符串。它是一個(gè)非捕獲匹配,即不能捕獲供以后使用的匹配。例如,'Windows (?=95|98|NT|2000)' 匹配“Windows 2000”中的“Windows”,但不匹配“Windows 3.1”中的“Windows”。預(yù)測(cè)先行不占用字符,即發(fā)生匹配后,下一匹配的搜索緊隨上一匹配之后,而不是在組成預(yù)測(cè)先行的字符后。
           
          (?!pattern)
           執(zhí)行反向預(yù)測(cè)先行搜索的子表達(dá)式,該表達(dá)式匹配不處于匹配 pattern 的字符串的起始點(diǎn)的搜索字符串。它是一個(gè)非捕獲匹配,即不能捕獲供以后使用的匹配。例如,'Windows (?!95|98|NT|2000)' 匹配“Windows 3.1”中的 “Windows”,但不匹配“Windows 2000”中的“Windows”。預(yù)測(cè)先行不占用字符,即發(fā)生匹配后,下一匹配的搜索緊隨上一匹配之后,而不是在組成預(yù)測(cè)先行的字符后。
           
          x|y
           匹配 x 或 y。例如,'z|food' 匹配“z”或“food”。'(z|f)ood' 匹配“zood”或“food”。
           
          [xyz]
           字符集。匹配包含的任一字符。例如,“[abc]”匹配“plain”中的“a”。
           
          [^xyz]
           反向字符集。匹配未包含的任何字符。例如,“[^abc]”匹配“plain”中的“p”。
           
          [a-z]
           字符范圍。匹配指定范圍內(nèi)的任何字符。例如,“[a-z]”匹配“a”到“z”范圍內(nèi)的任何小寫字母。
           
          [^a-z]
           反向范圍字符。匹配不在指定的范圍內(nèi)的任何字符。例如,“[^a-z]”匹配任何不在“a”到“z”范圍內(nèi)的任何字符。
           
          \b
           匹配一個(gè)字邊界,即字與空格間的位置。例如,“er\b”匹配“never”中的“er”,但不匹配“verb”中的“er”。
           
          \B
           非字邊界匹配。“er\B”匹配“verb”中的“er”,但不匹配“never”中的“er”。
           
          \cx
           匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回車符。x 的值必須在 A-Z 或 a-z 之間。如果不是這樣,則假定 c 就是“c”字符本身。
           
          \d
           數(shù)字字符匹配。等效于 [0-9]。
           
          \D
           非數(shù)字字符匹配。等效于 [^0-9]。
           
          \f
           換頁(yè)符匹配。等效于 \x0c 和 \cL。
           
          \n
           換行符匹配。等效于 \x0a 和 \cJ。
           
          \r
           匹配一個(gè)回車符。等效于 \x0d 和 \cM。
           
          \s
           匹配任何空白字符,包括空格、制表符、換頁(yè)符等。與 [ \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 是一個(gè)十六進(jìn)制轉(zhuǎn)義碼。十六進(jìn)制轉(zhuǎn)義碼必須正好是兩位數(shù)長(zhǎng)。例如,“\x41”匹配“A”。“\x041”與“\x04”&“1”等效。允許在正則表達(dá)式中使用 ASCII 代碼。
           
          \num
           匹配 num,此處的 num 是一個(gè)正整數(shù)。到捕獲匹配的反向引用。例如,“(.)\1”匹配兩個(gè)連續(xù)的相同字符。
           
          \n
           標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義碼或反向引用。如果 \n 前面至少有 n 個(gè)捕獲子表達(dá)式,那么 n 是反向引用。否則,如果 n 是八進(jìn)制數(shù) (0-7),那么 n 是八進(jìn)制轉(zhuǎn)義碼。
           
          \nm
           標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義碼或反向引用。如果 \nm 前面至少有 nm 個(gè)捕獲子表達(dá)式,那么 nm 是反向引用。如果 \nm 前面至少有 n 個(gè)捕獲,則 n 是反向引用,后面跟有字符 m。如果兩種前面的情況都不存在,則 \nm 匹配八進(jìn)制值 nm,其中 n 和 m 是八進(jìn)制數(shù)字 (0-7)。
           
          \nml
           當(dāng) n 是八進(jìn)制數(shù) (0-3),m 和 l 是八進(jìn)制數(shù) (0-7) 時(shí),匹配八進(jìn)制轉(zhuǎn)義碼 nml。
           
          \un
           匹配 n,其中 n 是以四位十六進(jìn)制數(shù)表示的 Unicode 字符。例如,\u00A9 匹配版權(quán)符號(hào) (?)。
           

          posted @ 2007-05-17 10:48 比特鼠 閱讀(7541) | 評(píng)論 (0)編輯 收藏

          package com.sunrise.ocs.webservice.unicom.test;

          import java.io.File;
          import java.io.StringWriter;
          import java.util.HashMap;
          import java.util.Iterator;

          import javax.xml.parsers.DocumentBuilderFactory;

          import org.apache.log4j.Logger;
          import org.dom4j.Document;
          import org.dom4j.DocumentHelper;
          import org.dom4j.Element;
          import org.dom4j.XPath;
          import org.dom4j.io.SAXReader;

          import com.sun.org.apache.xml.internal.serialize.OutputFormat;
          import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

          public class TestDom4j {
           private static final Logger log = Logger.getLogger(TestDom4j.class);

           private static long bt;

           public static void main(String[] args) {
            String strXml = "";
            int b = 0;
            String file1 = "xml/CreateUserRequest.xml";
            String file2 = "xml/CancelUserRequest.xml";
            if(b==0){
             bt = System.currentTimeMillis();
             strXml = xmlFile2String(file1);
             if (log.isDebugEnabled()) {
              log.debug("\nxmlFile2String() use time: "
                + (System.currentTimeMillis() - bt) + " millis\n");
             }
            }else{
             bt = System.currentTimeMillis();
             strXml = xmlFile2String2(file1);
             if (log.isDebugEnabled()) {
              log.debug("\nxmlFile2String2() use time: "
                + (System.currentTimeMillis() - bt) + " millis\n");
             }
            }

            if(b==0){
             bt = System.currentTimeMillis();
             findElement4XPath1(strXml);
             if (log.isDebugEnabled()) {
              log.debug("\nfindElement4XPath1() use time: "
                + (System.currentTimeMillis() - bt) + " millis\n");
             }
            }else{
             bt = System.currentTimeMillis();
             findElement4XPath2(strXml);
             if (log.isDebugEnabled()) {
              log.debug("\nfindElement4XPath2() use time: "
                + (System.currentTimeMillis() - bt) + " millis\n");
             } 
             
            }
           }

           public static void findElement4XPath1(String xml) {
            try {
             String str = delNamespace4Pattern(xml);
             Document doc = DocumentHelper.parseText(str);
             Element e = (Element) doc.selectSingleNode("http://CreateUserRequest/RequestMessage/MessageHeader");
             if (e != null) {
              Iterator iter = e.elementIterator();
              while (iter.hasNext()) {
               Element sub = (Element) iter.next();
               log.debug("\n" + sub.getText() + "\n");
              }
             }
             
             /* 讀取屬性的例子
             List childNodes = doc.selectNodes("http://Config/Child/ChildNode");
                   for(Object obj:childNodes) {
                       Node childNode = (Node)obj;
                       String name = childNode.valueOf("@name"); //讀取屬性
                       String text = childNode.getText();
                   }
                   */

             
            } catch (Exception e) {
             e.printStackTrace();
            }
           }
           public static void findElement4XPath2(String xml) {
            try {
             Document doc = DocumentHelper.parseText(xml);
             Element root = doc.getRootElement();
             
             HashMap map = new HashMap();
             map.put("tns", "   XPath x = doc.createXPath("http://tns:CreateUserRequest/tns:RequestMessage/tns:MessageHeader");
             x.setNamespaceURIs(map);
             
             Element e = (Element) x.selectSingleNode(doc);
             if (e != null) {
              Iterator iter = e.elementIterator();
              while (iter.hasNext()) {
               Element sub = (Element) iter.next();
               if (log.isDebugEnabled()) {
                log.debug("\n" + sub.getText() + "\n");
               }
              }
             }
            } catch (Exception e) {
             e.printStackTrace();
            }
           }

           public static Document xml2Document(String xml) {
            try {
             return DocumentHelper.parseText(xml);
            } catch (Exception e) {
             e.printStackTrace();
            }
            return null;
           }

           public static String xmlFile2String(String xmlFile) {
            try {
             return new SAXReader().read(new File(xmlFile)).asXML();
            } catch (Exception e) {
             e.printStackTrace();
            }
            return null;
           }
           
           //讀取xml文件為xml串
           public static String xmlFile2String2(String xmlFile) {
            try {
             org.w3c.dom.Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile); 
             OutputFormat format = new OutputFormat(document);
             //format.setEncoding("UTF-8");
             StringWriter stringOut = new StringWriter();
             XMLSerializer serial = new XMLSerializer(stringOut, format);
             serial.asDOMSerializer();
             serial.serialize(document.getDocumentElement());
             return stringOut.toString();
            } catch (Exception e) {
             e.printStackTrace();
            }
            return "";
           }
           
           
           public static String delNamespace4Pattern(String xml){
            String result = "";
            try {
             result = xml.replaceFirst("xmlns([^ ]*)=([^ ]*)http([^>^\"]*)\"", "");
            } catch (Exception e) {
             e.printStackTrace();
            }
            return result;
            
           }

           

          }


          package com.sunrise.ocs.webservice.unicom.test;

          import java.io.File;
          import java.io.StringReader;
          import java.io.StringWriter;

          import javax.xml.parsers.DocumentBuilder;
          import javax.xml.parsers.DocumentBuilderFactory;

          import org.w3c.dom.Document;
          import org.w3c.dom.Element;
          import org.w3c.dom.Node;
          import org.xml.sax.InputSource;

          import com.sun.org.apache.xml.internal.serialize.OutputFormat;
          import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

          public class TestDom {
           
           //將xml串轉(zhuǎn)換為document
           public static Document xml2Document(String xml) {
            Document doc = null;
            try {
             DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
             doc = builder.parse(new InputSource(new StringReader(xml)));
            } catch (Exception e) {
             e.printStackTrace();
            }
            return doc;
           }
           
           //將xml文件串轉(zhuǎn)換為document
           public static Document xmlFile2Document(String xmlFile) {
            Document doc = null;
            try {
             DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
             doc = builder.parse(new File(xmlFile));
            } catch (Exception e) {
             e.printStackTrace();
            }
            return doc;
           }
           
           //刪除命名空間: xmlns="..."
           public static String delNamespace(String xml) {
            String result = xml;
            try {
             Document doc = xml2Document(xml);
             Element root = doc.getDocumentElement();
             root.removeAttribute("xmlns");
             result = asXml(doc);
            } catch (Exception e) {
             e.printStackTrace();
            }
            return result;
           }
           
           //將doc轉(zhuǎn)換為xml串
           public static String asXml(Document doc) {
            String strxml = "";
            try {
             OutputFormat format = new OutputFormat(doc);
             // format.setEncoding("UTF-8");
             StringWriter stringOut = new StringWriter();
             XMLSerializer serial = new XMLSerializer(stringOut, format);
             serial.asDOMSerializer();
             serial.serialize(doc.getDocumentElement());
             strxml = stringOut.toString();
            } catch (Exception e) {
             e.printStackTrace();
            }
            return strxml;
           }
           
           //將node轉(zhuǎn)換為xml串
           public static String asXml(Node node, Document doc) {
            String strxml = "";
            try {
             OutputFormat format = new OutputFormat(doc);
             // format.setEncoding("UTF-8");
             StringWriter stringOut = new StringWriter();
             XMLSerializer serial = new XMLSerializer(stringOut, format);
             serial.asDOMSerializer();
             serial.serialize((Element)node);
             strxml = stringOut.toString();
            } catch (Exception e) {
             e.printStackTrace();
            }
            return strxml;
           }
          }

          posted @ 2007-05-17 10:10 比特鼠 閱讀(288) | 評(píng)論 (0)編輯 收藏

          vi 是visual edit 的縮寫
          文本編輯器是所有計(jì)算機(jī)系統(tǒng)中最常用的一種工具。UNIX下的編輯器有ex,sed和vi等,其中,使用最為廣泛的是vi,而vi命令繁多,論壇里好像這方面的總結(jié)不多,以下稍做總結(jié),以資共享!渴望更正和補(bǔ)充!

          進(jìn)入vi的命令
          vi filename :打開或新建文件,并將光標(biāo)置于第一行首
          vi +n filename :打開文件,并將光標(biāo)置于第n行首
          vi + filename :打開文件,并將光標(biāo)置于最后一行首
          vi +/pattern filename:打開文件,并將光標(biāo)置于第一個(gè)與pattern匹配的串處
          vi -r filename :在上次正用vi編輯時(shí)發(fā)生系統(tǒng)崩潰,恢復(fù)filename
          vi filename....filename :打開多個(gè)文件,依次進(jìn)行編輯

          移動(dòng)光標(biāo)類命令
          h :光標(biāo)左移一個(gè)字符
          l :光標(biāo)右移一個(gè)字符
          space:光標(biāo)右移一個(gè)字符
          Backspace:光標(biāo)左移一個(gè)字符
          k或Ctrl+p:光標(biāo)上移一行
          j或Ctrl+n :光標(biāo)下移一行
          Enter :光標(biāo)下移一行
          w或W :光標(biāo)右移一個(gè)字至字首
          b或B :光標(biāo)左移一個(gè)字至字首
          e或E :光標(biāo)右移一個(gè)字至字尾
          ) :光標(biāo)移至句尾
          ( :光標(biāo)移至句首
          }:光標(biāo)移至段落開頭
          { :光標(biāo)移至段落結(jié)尾
          nG:光標(biāo)移至第n行首
          n+:光標(biāo)下移n行
          n-:光標(biāo)上移n行
          n$:光標(biāo)移至第n行尾
          H :光標(biāo)移至屏幕頂行
          M :光標(biāo)移至屏幕中間行
          L :光標(biāo)移至屏幕最后行
          0:(注意是數(shù)字零)光標(biāo)移至當(dāng)前行首
          $:光標(biāo)移至當(dāng)前行尾

          屏幕翻滾類命令
          Ctrl+u:向文件首翻半屏
          Ctrl+d:向文件尾翻半屏
          Ctrl+f:向文件尾翻一屏
          Ctrl+b;向文件首翻一屏
          nz:將第n行滾至屏幕頂部,不指定n時(shí)將當(dāng)前行滾至屏幕頂部。

          插入文本類命令
          i :在光標(biāo)前
          I :在當(dāng)前行首
          a:光標(biāo)后
          A:在當(dāng)前行尾
          o:在當(dāng)前行之下新開一行
          O:在當(dāng)前行之上新開一行
          r:替換當(dāng)前字符
          R:替換當(dāng)前字符及其后的字符,直至按ESC鍵
          s:從當(dāng)前光標(biāo)位置處開始,以輸入的文本替代指定數(shù)目的字符
          S:刪除指定數(shù)目的行,并以所輸入文本代替之
          ncw或nCW:修改指定數(shù)目的字
          nCC:修改指定數(shù)目的行

          刪除命令
          ndw或ndW:刪除光標(biāo)處開始及其后的n-1個(gè)字
          do:刪至行首
          d$:刪至行尾
          ndd:刪除當(dāng)前行及其后n-1行
          x或X:刪除一個(gè)字符,x刪除光標(biāo)后的,而X刪除光標(biāo)前的
          Ctrl+u:刪除輸入方式下所輸入的文本

          搜索及替換命令
          /pattern:從光標(biāo)開始處向文件尾搜索pattern
          ?pattern:從光標(biāo)開始處向文件首搜索pattern
          n:在同一方向重復(fù)上一次搜索命令
          N:在反方向上重復(fù)上一次搜索命令
          :s/p1/p2/g:將當(dāng)前行中所有p1均用p2替代
          :n1,n2s/p1/p2/g:將第n1至n2行中所有p1均用p2替代
          :g/p1/s//p2/g:將文件中所有p1均用p2替換

          選項(xiàng)設(shè)置
          all:列出所有選項(xiàng)設(shè)置情況
          term:設(shè)置終端類型
          ignorance:在搜索中忽略大小寫
          list:顯示制表位(Ctrl+I)和行尾標(biāo)志($)
          number:顯示行號(hào)
          report:顯示由面向行的命令修改過的數(shù)目
          terse:顯示簡(jiǎn)短的警告信息
          warn:在轉(zhuǎn)到別的文件時(shí)若沒保存當(dāng)前文件則顯示NO write信息
          nomagic:允許在搜索模式中,使用前面不帶“\”的特殊字符
          nowrapscan:禁止vi在搜索到達(dá)文件兩端時(shí),又從另一端開始
          mesg:允許vi顯示其他用戶用write寫到自己終端上的信息

          最后行方式命令
          :n1,n2 co n3:將n1行到n2行之間的內(nèi)容拷貝到第n3行下
          :n1,n2 m n3:將n1行到n2行之間的內(nèi)容移至到第n3行下
          :n1,n2 d :將n1行到n2行之間的內(nèi)容刪除
          :w :保存當(dāng)前文件
          :e filename:打開文件filename進(jìn)行編輯
          :x:保存當(dāng)前文件并退出
          :q:退出vi
          :q!:不保存文件并退出vi
          :!command:執(zhí)行shell命令command
          :n1,n2 w!command:將文件中n1行至n2行的內(nèi)容作為command的輸入并執(zhí)行之,若不指定n1,n2,則表示將整個(gè)文件內(nèi)容作為command的輸入
          :r!command:將命令command的輸出結(jié)果放到當(dāng)前行

          寄存器操作
          "?nyy:將當(dāng)前行及其下n行的內(nèi)容保存到寄存器?中,其中?為一個(gè)字母,n為一個(gè)數(shù)字
          "?nyw:將當(dāng)前行及其下n個(gè)字保存到寄存器?中,其中?為一個(gè)字母,n為一個(gè)數(shù)字
          "?nyl:將當(dāng)前行及其下n個(gè)字符保存到寄存器?中,其中?為一個(gè)字母,n為一個(gè)數(shù)字
          "?p:取出寄存器?中的內(nèi)容并將其放到光標(biāo)位置處。這里?可以是一個(gè)字母,也可以是一個(gè)數(shù)字
          ndd:將當(dāng)前行及其下共n行文本刪除,并將所刪內(nèi)容放到1號(hào)刪除寄存器中。


          進(jìn)入vi
          vi test
          離開vi
          :q! 離開vi,并放棄剛在緩沖區(qū)內(nèi)編輯的內(nèi)容。
             :wq 將緩沖區(qū)內(nèi)的資料寫入磁盤中,并離開vi。
             :ZZ 同wq
          同wq
          :w 將緩沖區(qū)內(nèi)的資料寫入磁盤中,但并不離開vi。
            :q 離開vi,若文件被修改過,則會(huì)被要求確認(rèn)是否放棄修改的內(nèi)容,此指令可與: w 配合使用。
          Vi 的操作模式
          Vi 提供兩種操作模式:
          輸入模式(insert mode)
          指令模式(command mode)
          當(dāng)使用者進(jìn)入vi后,既處于指令模式下,此刻鍵入任何字元皆被視為指令。

          輸入模式:a(append) 游標(biāo)之后加入資料。
          A 該行之末加入資料
          i (insert) 游標(biāo)之前加入資料
          I 該行之首加入資料
          o (open) 新增一行與該行之下供輸入資料
          O 新增一行與該行之上供輸入資料

          指令模式:B      移至該行第一個(gè)字符,若光標(biāo)在該行第一字符則光標(biāo)移至上一行第一字符。
             b    由游標(biāo)所在位置之前一個(gè)字串的第一個(gè)字元
               cc 刪除整行,修改整行的內(nèi)容。
               D      以行為單位,刪除游標(biāo)在內(nèi)后面的所有字符。
          db 刪除該行光標(biāo)前字符
               dd 刪除該行
               de 刪除自光標(biāo)開始后面的字符
               d加字符   刪除光標(biāo)所在位置至字符之間的單
               E      移至該行最后字符,若光標(biāo)在該行最后字符則光標(biāo)移至下一行最后字符
           e      由游標(biāo)所在位置至該字串的最后一個(gè)字元
               G 移至該檔案的最后一行 
               h 向前移一個(gè)字元
          j 向下移一個(gè)字元
          k 向上移一個(gè)字元
          0 移至該行之首
          M 移至視窗的中間那行
          L 移至視窗的最后一行
               l 向后移一個(gè)字符
          0 由游標(biāo)所在位置該行的第一個(gè)字元
          nG 移至該檔案的第n行
          n+ 自游標(biāo)所在位置向后移n行至該行的第一字符
          n- 自游標(biāo)所在位置向前移n行至該行的第一字符
          R 進(jìn)入取代狀態(tài),直到《ESC》為止
          s 刪除游標(biāo)所在字元,并進(jìn)入取代模式直到《ESC》
          S 刪除游標(biāo)所在之該行資料,并進(jìn)入輸入模式直到《ESC》
          w 由游標(biāo)所在位置之下一個(gè)字串的第一個(gè)字元
          x 刪除游標(biāo)所在該字元。
          X 刪除游標(biāo)所在之前一字元。
          r 用接于此指令之后的字元取代(replace)游標(biāo)所在字元
          yy yank整行,使游標(biāo)所在該行復(fù)制到記憶體緩沖區(qū)
          顯示該行之行號(hào)、檔案名稱、檔案中最末之行號(hào)、游標(biāo)所在行號(hào)占
          總行號(hào)之百分比
          $ 由游標(biāo)所在位置至該行的最后一個(gè)字元。
          ) 由游標(biāo)所在位置至下一個(gè)句子的第一個(gè)字元。
          ( 由游標(biāo)所在位置至該句子的第一個(gè)字元。
          {  由游標(biāo)所在位置至該段落的最后一個(gè)字元。
          } 由游標(biāo)所在位置至該段落的第一個(gè)字元

          yank和delete可將指定的資料復(fù)制到記憶體緩沖區(qū),而藉有put指令可將緩沖區(qū)內(nèi)的資料復(fù)制到熒幕上
          例如:搬移一行 :在該行執(zhí)行dd
          游標(biāo)移至目的地
          執(zhí)行p
          復(fù)制一行 :在該行執(zhí)行yy
          游標(biāo)移至目的地
          執(zhí)行p
          視窗移動(dòng):
          視窗往下卷一頁(yè)
          視窗往上卷一頁(yè)
          視窗往下卷半頁(yè)
          視窗往上卷半頁(yè)
          視窗往下卷一行
          視窗往上卷一行
          刪除、復(fù)制及修改指令介紹:
          d(delete)、c(change)和y(yank)這一類的指令在vi 中的指令格式為:
          operation+scope=command
          (運(yùn)算子)(范圍)
          運(yùn)算子:
          d 刪除指令。刪除資料,但會(huì)將刪除資料復(fù)制到記憶體緩沖區(qū)。
          y 將資料(字組、行列、句子或段落)復(fù)制到緩沖區(qū)。
          p 放置(put)指令,與d和y配合使用。可將最后delete或yank的資料放置于游標(biāo)所在位置之行列下。
          c 修改(change)指令,類似delete于insert的組合。刪除一個(gè)字組、句子等資料,并插入新鍵入的




          posted @ 2007-05-15 11:33 比特鼠 閱讀(255) | 評(píng)論 (0)編輯 收藏

          1、使用JdbcTemplate的execute()方法執(zhí)行SQL語句

          代碼

          2、如果是UPDATE或INSERT,可以用update()方法。
          代碼

          3、帶參數(shù)的更新
          代碼

          代碼

          4、使用JdbcTemplate進(jìn)行查詢時(shí),使用queryForXXX()等方法
          代碼

          代碼

          代碼

          代碼

          JdbcTemplate將我們使用的JDBC的流程封裝起來,包括了異常的捕捉、SQL的執(zhí)行、查詢結(jié)果的轉(zhuǎn)換等等。spring大量使用Template Method模式來封裝固定流程的動(dòng)作,XXXTemplate等類別都是基于這種方式的實(shí)現(xiàn)。
          除了大量使用Template Method來封裝一些底層的操作細(xì)節(jié),spring也大量使用callback方式類回調(diào)相關(guān)類別的方法以提供JDBC相關(guān)類別的功能,使傳統(tǒng)的JDBC的使用者也能清楚了解spring所提供的相關(guān)封裝類別方法的使用。

          JDBC的PreparedStatement

          代碼

          代碼

          代碼

          在getUser(id)里面使用UserRowMapper

          代碼

          網(wǎng)上收集
          org.springframework.jdbc.core.PreparedStatementCreator 返回預(yù)編譯SQL 不能于Object[]一起用

          代碼

          1.增刪改
          org.springframework.jdbc.core.JdbcTemplate 類(必須指定數(shù)據(jù)源dataSource)
          代碼


          代碼

          org.springframework.jdbc.core.PreparedStatementSetter 接口 處理預(yù)編譯SQL
          代碼

          2.查詢JdbcTemplate.query(String,[Object[]/PreparedStatementSetter],RowMapper/RowCallbackHandler)
          org.springframework.jdbc.core.RowMapper 記錄映射接口 處理結(jié)果集
          代碼

          org.springframework.jdbc.core.RowCallbackHandler 記錄回調(diào)管理器接口 處理結(jié)果集
          代碼

          posted @ 2007-04-11 18:48 比特鼠 閱讀(519) | 評(píng)論 (0)編輯 收藏

          制作可執(zhí)行的JAR文件包及jar命令詳解


          常常在網(wǎng)上看到有人詢問:如何把 java 程序編譯成 .exe 文件。通常回答只有兩種,一種是制作一個(gè)可執(zhí)行的 JAR 文件包,然后就可以像.chm 文檔一樣雙擊運(yùn)行了;而另一種是使用 JET 來進(jìn)行 編譯。但是 JET 是要用錢買的,而且據(jù)說 JET 也不是能把所有的 Java 程序都編譯成執(zhí)行文件,性能也要打些折扣。所以,使用制作可執(zhí)行 JAR 文件包的方法就是最佳選擇了,何況它還能保持 Java 的跨平臺(tái)特性。 

          下面就來看看什么是 JAR 文件包吧: 

          1. JAR 文件包 

          JAR 文件就是 Java Archive File,顧名思意,它的應(yīng)用是與 Java 息息相關(guān)的,是 Java 的一種文檔格式。JAR 文件非常類似 ZIP 文件——準(zhǔn)確的說,它就是 ZIP 文件,所以叫它文件包。JAR 文件與 ZIP 文件唯一的區(qū)別就是在 JAR 文件的內(nèi)容中,包含了一個(gè) META-INF/MANIFEST.MF 文件,這個(gè)文件是在生成 JAR 文件的時(shí)候自動(dòng)創(chuàng)建的。舉個(gè)例子,如果我們具有如下目錄結(jié)構(gòu)的一些文件: 

            == 

            `-- test 

              `-- Test.class 

          把它壓縮成 ZIP 文件 test.zip,則這個(gè) ZIP 文件的內(nèi)部目錄結(jié)構(gòu)為: 

            test.zip 

            `-- test 

              `-- Test.class 

          如果我們使用 JDK 的 jar 命令把它打成 JAR 文件包 test.jar,則這個(gè) JAR 文件的內(nèi)部目錄結(jié)構(gòu)為: 

            test.jar 

            |-- META-INF 

            |  `-- MANIFEST.MF 

            `-- test 

              `--Test.class 

          2. 創(chuàng)建可執(zhí)行的 JAR 文件包 

          制作一個(gè)可執(zhí)行的 JAR 文件包來發(fā)布你的程序是 JAR 文件包最典型的用法。 

          Java 程序是由若干個(gè) .class 文件組成的。這些 .class 文件必須根據(jù)它們所屬的包不同而分級(jí)分目錄存放;運(yùn)行前需要把所有用到的包的根目錄指定給 CLASSPATH 環(huán)境變量或者 java 命令的 -cp 參數(shù);運(yùn)行時(shí)還要到控制臺(tái)下去使用 java 命令來運(yùn)行,如果需要直接雙擊運(yùn)行必須寫 Windows 的批處理文件 (.bat) 或者 Linux 的 Shell 程序。因此,許多人說,Java 是一種方便開發(fā)者苦了用戶的程序設(shè)計(jì)語言。 

          其實(shí)不然,如果開發(fā)者能夠制作一個(gè)可執(zhí)行的 JAR 文件包交給用戶,那么用戶使用起來就方便了。在 Windows 下安裝 JRE (Java Runtime Environment) 的時(shí)候,安裝文件會(huì)將 .jar 文件映射給 javaw.exe 打開。那么,對(duì)于一個(gè)可執(zhí)行的 JAR 文件包,用戶只需要雙擊它就可以運(yùn)行程序了,和閱讀 .chm 文檔一樣方便 (.chm 文檔默認(rèn)是由 hh.exe 打開的)。那么,現(xiàn)在的關(guān)鍵,就是如何來創(chuàng)建這個(gè)可執(zhí)行的 JAR 文件包。 

          創(chuàng)建可執(zhí)行的 JAR 文件包,需要使用帶 cvfm 參數(shù)的 jar 命令,同樣以上述 test 目錄為例,命令如下: 

          jar cvfm test.jar manifest.mf test 

          這里 test.jar 和 manifest.mf 兩個(gè)文件,分別是對(duì)應(yīng)的參數(shù) f 和 m,其重頭戲在 manifest.mf。因?yàn)橐獎(jiǎng)?chuàng)建可執(zhí)行的 JAR 文件包,光靠指定一個(gè) manifest.mf 文件是不夠的,因?yàn)?nbsp;MANIFEST 是 JAR 文件包的特征,可執(zhí)行的 JAR 文件包和不可執(zhí)行的 JAR 文件包都包含 MANIFEST。關(guān)鍵在于可執(zhí)行 JAR 文件包的 MANIFEST,其內(nèi)容包含了 Main-Class 一項(xiàng)。這在 MANIFEST 中書寫格式如下: 

          Main-Class: 可執(zhí)行主類全名(包含包名) 

          例如,假設(shè)上例中的 Test.class 是屬于 test 包的,而且是可執(zhí)行的類 (定義了 public static void main(String[]) 方法),那么這個(gè) manifest.mf 可以編輯如下: 

          Main-Class: test.Test <回車>; 

          這個(gè) manifest.mf 可以放在任何位置,也可以是其它的文件名,只需要有 Main-Class: test.Test 一行,且該行以一個(gè)回車符結(jié)束即可。創(chuàng)建了 manifest.mf 文件之后,我們的目錄結(jié)構(gòu)變?yōu)椋?nbsp;

            == 

            |-- test 

            |  `-- Test.class 

            `-- manifest.mf 

          這時(shí)候,需要到 test 目錄的上級(jí)目錄中去使用 jar 命令來創(chuàng)建 JAR 文件包。也就是在目錄樹中使用“==”表示的那個(gè)目錄中,使用如下命令: 

          jar cvfm test.jar manifest.mf test 

          之后在“==”目錄中創(chuàng)建了 test.jar,這個(gè) test.jar 就是執(zhí)行的 JAR 文件包。運(yùn)行時(shí)只需要使用 java -jar test.jar 命令即可。 

          需要注意的是,創(chuàng)建的 JAR 文件包中需要包含完整的、與 Java 程序的包結(jié)構(gòu)對(duì)應(yīng)的目錄結(jié)構(gòu),就像上例一樣。而 Main-Class 指定的類,也必須是完整的、包含包路徑的類名,如上例的 test.Test;而且在沒有打成 JAR 文件包之前可以使用 java <類名>; 來運(yùn)行這個(gè)類,即在上例中 java test.Test 是可以正確運(yùn)行的 (當(dāng)然要在 CLASSPATH 正確的情況下)。 

          3. jar 命令詳解 

          jar 是隨 JDK 安裝的,在 JDK 安裝目錄下的 bin 目錄中,Windows 下文件名為 jar.exe,Linux 下文件名為 jar。它的運(yùn)行需要用到 JDK 安裝目錄下 lib 目錄中的 tools.jar 文件。不過我們除了安裝 JDK 什么也不需要做,因?yàn)?nbsp;SUN 已經(jīng)幫我們做好了。我們甚至不需要將 tools.jar 放到 CLASSPATH 中。 

          使用不帶任何的 jar 命令我們可以看到 jar 命令的用法如下: 

          jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目錄] 文件名 ... 

          其中 {ctxu} 是 jar 命令的子命令,每次 jar 命令只能包含 ctxu 中的一個(gè),它們分別表示: 

          -c 創(chuàng)建新的 JAR 文件包 

          -t 列出 JAR 文件包的內(nèi)容列表 

          -x 展開 JAR 文件包的指定文件或者所有文件 

          -u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中) 

          [vfm0M] 中的選項(xiàng)可以任選,也可以不選,它們是 jar 命令的選項(xiàng)參數(shù) 

          -v 生成詳細(xì)報(bào)告并打印到標(biāo)準(zhǔn)輸出 

          -f 指定 JAR 文件名,通常這個(gè)參數(shù)是必須的 

          -m 指定需要包含的 MANIFEST 清單文件 

          -0 只存儲(chǔ),不壓縮,這樣產(chǎn)生的 JAR 文件包會(huì)比不用該參數(shù)產(chǎn)生的體積大,但速度更快 

          -M 不產(chǎn)生所有項(xiàng)的清單(MANIFEST〕文件,此參數(shù)會(huì)忽略 -m 參數(shù) 

          [jar-文件] 即需要生成、查看、更新或者解開的 JAR 文件包,它是 -f 參數(shù)的附屬參數(shù) 

          [manifest-文件] 即 MANIFEST 清單文件,它是 -m 參數(shù)的附屬參數(shù) 

          [-C 目錄] 表示轉(zhuǎn)到指定目錄下去執(zhí)行這個(gè) jar 命令的操作。它相當(dāng)于先使用 cd 命令轉(zhuǎn)該目錄下再執(zhí)行不帶 -C 參數(shù)的 jar 命令,它只能在創(chuàng)建和更新 JAR 文件包的時(shí)候可用。   

          文件名 ... 指定一個(gè)文件/目錄列表,這些文件/目錄就是要添加到 JAR 文件包中的文件/目錄。如果指定了目錄,那么 jar 命令打包的時(shí)候會(huì)自動(dòng)把該目錄中的所有文件和子目錄打入包中。 

          下面舉一些例子來說明 jar 命令的用法: 

          1) jar cf test.jar test 

          該命令沒有執(zhí)行過程的顯示,執(zhí)行結(jié)果是在當(dāng)前目錄生成了 test.jar 文件。如果當(dāng)前目錄已經(jīng)存在 test.jar,那么該文件將被覆蓋。 

          2) jar cvf test.jar test 

          該命令與上例中的結(jié)果相同,但是由于 v 參數(shù)的作用,顯示出了打包過程,如下: 

          標(biāo)明清單(manifest) 

          增加:test/(讀入= 0) (寫出= 0)(存儲(chǔ)了 0%) 

          增加:test/Test.class(讀入= 7) (寫出= 6)(壓縮了 14%) 

          3) jar cvfM test.jar test 

          該命令與 2) 結(jié)果類似,但在生成的 test.jar 中沒有包含 META-INF/MANIFEST 文件,打包過程的信息也略有差別: 

          增加:test/(讀入= 0) (寫出= 0)(存儲(chǔ)了 0%) 

          增加:test/Test.class(讀入= 7) (寫出= 6)(壓縮了 14%) 

          4) jar cvfm test.jar manifest.mf test 

          運(yùn)行結(jié)果與 2) 相似,顯示信息也相同,只是生成 JAR 包中的 META-INF/MANIFEST 內(nèi)容不同,是包含了 manifest.mf 的內(nèi)容 

          5) jar tf test.jar 

          在 test.jar 已經(jīng)存在的情況下,可以查看 test.jar 中的內(nèi)容,如對(duì)于 2) 和 3) 生成的 test.jar 分別應(yīng)該此命令,結(jié)果如下; 

          對(duì)于 2) 

          META-INF/ 

          META-INF/MANIFEST.MF 

          test/ 

          test/Test.class 

          對(duì)于 3) 

          test/ 

          test/Test.class 

          6) jar tvf test.jar 

          除顯示 5) 中顯示的內(nèi)容外,還包括包內(nèi)文件的詳細(xì)信息,如: 

          0 Wed Jun 19 15:39:06 GMT 2002 META-INF/ 

          86 Wed Jun 19 15:39:06 GMT 2002 META-INF/MANIFEST.MF 

          0 Wed Jun 19 15:33:04 GMT 2002 test/ 

          7 Wed Jun 19 15:33:04 GMT 2002 test/Test.class 

          7) jar xf test.jar 

          解開 test.jar 到當(dāng)前目錄,不顯示任何信息,對(duì)于 2) 生成的 test.jar,解開后的目錄結(jié)構(gòu)如下: 

            == 

            |-- META-INF 

            |  `-- MANIFEST 

            `-- test 

              `--Test.class 

          8) jar xvf test.jar 

          運(yùn)行結(jié)果與 7) 相同,對(duì)于解壓過程有詳細(xì)信息顯示,如: 

          創(chuàng)建:META-INF/ 

          展開:META-INF/MANIFEST.MF 

          創(chuàng)建:test/ 

          展開:test/Test.class 

          9) jar uf test.jar manifest.mf 

          在 test.jar 中添加了文件 manifest.mf,此使用 jar tf 來查看 test.jar 可以發(fā)現(xiàn) test.jar 中比原來多了一個(gè) manifest。這里順便提一下,如果使用 -m 參數(shù)并指定 manifest.mf 文件,那么 manifest.mf 是作為清單文件 MANIFEST 來使用的,它的內(nèi)容會(huì)被添加到 MANIFEST 中;但是,如果作為一般文件添加到 JAR 文件包中,它跟一般文件無異。 

          10) jar uvf test.jar manifest.mf 

          與 9) 結(jié)果相同,同時(shí)有詳細(xì)信息顯示,如: 

          增加:manifest.mf(讀入= 17) (寫出= 19)(壓縮了 -11%) 

          4. 關(guān)于 JAR 文件包的一些技巧 

          1) 使用 unzip 來解壓 JAR 文件 

          在介紹 JAR 文件的時(shí)候就已經(jīng)說過了,JAR 文件實(shí)際上就是 ZIP 文件,所以可以使用常見的一些解壓 ZIP 文件的工具來解壓 JAR 文件,如 Windows 下的 WinZip、WinRAR 等和 Linux 下的 unzip 等。使用 WinZip 和 WinRAR 等來解壓是因?yàn)樗鼈兘鈮罕容^直觀,方便。而使用 unzip,則是因?yàn)樗鈮簳r(shí)可以使用 -d 參數(shù)指定目標(biāo)目錄。 

          在解壓一個(gè) JAR 文件的時(shí)候是不能使用 jar 的 -C 參數(shù)來指定解壓的目標(biāo)的,因?yàn)?nbsp;-C 參數(shù)只在創(chuàng)建或者更新包的時(shí)候可用。那么需要將文件解壓到某個(gè)指定目錄下的時(shí)候就需要先將這具 JAR 文件拷貝到目標(biāo)目錄下,再進(jìn)行解壓,比較麻煩。如果使用 unzip,就不需要這么麻煩了,只需要指定一個(gè) -d 參數(shù)即可。如: 

          unzip test.jar -d dest/ 

          2) 使用 WinZip 或者 WinRAR 等工具創(chuàng)建 JAR 文件 

          上面提到 JAR 文件就是包含了 META-INF/MANIFEST 的 ZIP 文件,所以,只需要使用 WinZip、WinRAR 等工具創(chuàng)建所需要 ZIP 壓縮包,再往這個(gè) ZIP 壓縮包中添加一個(gè)包含 MANIFEST 文件的 META-INF 目錄即可。對(duì)于使用 jar 命令的 -m 參數(shù)指定清單文件的情況,只需要將這個(gè) MANIFEST 按需要修改即可。 

          3) 使用 jar 命令創(chuàng)建 ZIP 文件 

          有些 Linux 下提供了 unzip 命令,但沒有 zip 命令,所以需要可以對(duì) ZIP 文件進(jìn)行解壓,即不能創(chuàng)建 ZIP 文件。如要?jiǎng)?chuàng)建一個(gè) ZIP 文件,使用帶 -M 參數(shù)的 jar 命令即可,因?yàn)?nbsp;-M 參數(shù)表示制作 JAR 包的時(shí)候不添加 MANIFEST 清單,那么只需要在指定目標(biāo) JAR 文件的地方將 .jar 擴(kuò)展名改為 .zip 擴(kuò)展名,創(chuàng)建的就是一個(gè)不折不扣的 ZIP 文件了,如將上一節(jié)的第 3) 個(gè)例子略作改動(dòng): 

          jar cvfM test.zip test
          posted @ 2007-04-11 18:19 比特鼠 閱讀(331) | 評(píng)論 (1)編輯 收藏

           

          import java.io.File;

          public class Test {
              
          public static void main(String[] args) {
                   System.out.println(
          "1:"+Thread.currentThread().getContextClassLoader().getResource(""));     

                    System.out.println(
          "2:"+Test.class.getClassLoader().getResource(""));        

                    System.out.println(
          "3:"+ClassLoader.getSystemResource(""));        
                    System.out.println(
          "4:"+Test.class.getResource(""));        
                    System.out.println(
          "5:"+Test.class.getResource("/")); //Class文件所在路徑  
                    System.out.println("6:"+new File("").getAbsolutePath());        
                    System.out.println(
          "7:"+System.getProperty("user.dir"));  
                    
                    String s 
          = ClassLoader.getSystemResource("").getPath();
                    System.out.println(s.substring(
          1));
                    System.out.println(s.substring(
          1).substring(0, s.lastIndexOf("/classes")));

              }

          }
          posted @ 2007-04-04 16:49 比特鼠 閱讀(175) | 評(píng)論 (0)編輯 收藏

          dom4j 直接往Element中加入符合格式的xml串!

          下面的代碼直接往root元素插入符合格式的xml串:

          String strXml = "<aaa><bbb></bbb><ccc></ccc></aaa>";
          Document doc = DocumentHelper.createDocument();
          Element??root = doc.getRootElement();
          root.add(DocumentHelper.parseText(strXml).getRootElement());
          posted @ 2007-03-27 16:20 比特鼠 閱讀(489) | 評(píng)論 (1)編輯 收藏

          ?public long algo(){
          ????int a = 0;
          ????String b = null;
          ????long st = System.currentTimeMillis();
          ????for (int i = 0; i < 2000000; i++){
          ??????b = Integer.toString(a);
          ????}
          ????long et = System.currentTimeMillis();
          ????return (et - st);
          ??}
          posted @ 2007-03-27 15:11 比特鼠 閱讀(1426) | 評(píng)論 (1)編輯 收藏

          玩轉(zhuǎn) XPath 和缺省命名空間(Default Namespaces)

          原文出自:http://www.edankert.com/defaultnamespaces.html
          翻譯文出自:http://wakan.blog.51cto.com/blog/59583/7220



          諸如“為什么用 XPath 的表達(dá)式進(jìn)行查詢,卻沒有返回所期望的結(jié)果?”的問題通常都與命名空間(NameSpace)有關(guān),而且絕大多數(shù)是與缺省命名空間(Default Namespace)有關(guān)。本文試圖解釋這個(gè)問題并針對(duì)三種流行的 XPath 實(shí)現(xiàn)給出解決方法:Jaxen、JAXP XPPathFactory 以及 XSLT。
          內(nèi)容列表
          問題描述
          “前綴-命名空間”映射
          Jaxen 和 Dom4J
          Jaxen 和 XOM
          Jaxen 和 JDOM
          JAXP XPathFactory
          XSLT
          結(jié)束語
          資源


          問題描述
          看下述 XML:
          <catalog>
          ? <cd>
          ??? <artist>Sufjan Stevens</artist>
          ??? <title>Illinois</title>
          ??? <src>http://www.sufjan.com/</src>
          ? </cd>
          ? <cd>
          ??? <artist>Stoat</artist>
          ??? <title>Future come and get me</title>
          ??? <src>http://www.stoatmusic.com/</src>
          ? </cd>
          ? <cd>
          ??? <artist>The White Stripes</artist>
          ??? <title>Get behind me satan</title>
          ??? <src>http://www.whitestripes.com/</src>
          ? </cd>
          </catalog>

          ??? 你可以使用“//cd”來得到?jīng)]有在任何命名空間中定義的“cd”節(jié)點(diǎn)。?


          ??? 現(xiàn)在讓我們來改造這個(gè) XML,讓它的所有元素都屬于 'http://www.edankert.com/examples/' 命名空間中。
          ?
          ??? 為了避免在每個(gè)不同的元素前都要加個(gè)前綴,我們?cè)诟厣隙x通常所說的缺省命名空間。改造后的 XML 如下:
          ?
          <catalog xmlns="
          http://www.edankert.com/examples/ ">
          ? <cd>
          ??? <artist>Sufjan Stevens</artist>
          ??? <title>Illinois</title>
          ??? <src>http://www.sufjan.com/</src>
          ? </cd>
          ? <cd>
          ??? <artist>Stoat</artist>
          ??? <title>Future come and get me</title>
          ??? <src>http://www.stoatmusic.com/</src>
          ? </cd>
          ? <cd>
          ??? <artist>The White Stripes</artist>
          ??? <title>Get behind me satan</title>
          ??? <src>http://www.whitestripes.com/</src>
          ? </cd>
          </catalog>

          ??? 當(dāng)我們使用與上文相同的 XPath “//cd”,將得不到任何元素。這是因?yàn)橹付ǖ?XPath 返回的是所有不屬于任何命名空間的“cd”節(jié)點(diǎn),而本例中,所有的“cd”元素都屬于缺省的命名空間“http://www.edankert.com/examples/”。


          “前綴-命名空間”映射
          ??? 為了取出命名空間“http://www.edankert.com/examples/”中的所有“cd”元素,我們需要對(duì) XPath 表達(dá)式做一些額外的工作。
          ?
          ??? 為了解決這個(gè)問題,XPath 規(guī)范允許我們使用 QName 來指定元素或者屬性。QName 可以是元素的直接名稱(形如“element”),或者包含一個(gè)前綴(形如“pre:element”)。這個(gè)前綴需要映射到一個(gè)命名空間的 URI 上。例如,如果把“pre”前綴映射到“http://www.edankert.com/test”上,則通過“pre:element”可以查找出屬于命名空間“http://www.edankert.com/test”的所有 “element”元素。
          ?
          ??? 在本例中,我們把“edx”映射到“'http://www.edankert.com/examples/”命名空間上。通過 XPath“//edx:cd”就可以查找出屬于“'http://www.edankert.com/examples/”命名空間的所有“cd”元素。?
          ?
          ??? XPath 處理器允許設(shè)置“前綴-命名空間”的映射,但是,如何去映射,卻要依賴于具體的實(shí)現(xiàn)。下文舉例說明 Jaxen (JDOM/dom4j/XOM)、JAXP 以及 XSLT 中是如何進(jìn)行“前綴-命名空間”的映射的。

          Jaxen 和 Dom4J
          ??? 下述代碼從文件系統(tǒng)讀入一個(gè) XML 文件到 org.dom4j.Document 對(duì)象中,并且在 Document 中查找屬于“http://www.edankert.com/examples/”命名空間的所有“cd”元素。
          ?
          try {
          ? SAXReader reader = new SAXReader();
          ? Document document = reader.read( "file:catalog.xml");
          ?
          ? HashMap map = new HashMap();
          ? map.put( "edx", "
          http://www.edankert.com/examples/ ");
          ?
          ? XPath xpath = new Dom4jXPath( "http://edx:cd");
          ? xpath.setNamespaceContext( new SimpleNamespaceContext( map));
          ?
          ? List nodes = xpath.selectNodes( document);
          ?
          ? ...
          ?
          } catch ( JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( DocumentException e) {
          ? // the document is not well-formed.
          ? ...
          }
          ??? 第一步,創(chuàng)建一個(gè) SAXReader,用來從文件系統(tǒng)中讀取“catalog.xml”并創(chuàng)建一個(gè)特定于 Dom4j 的 Document 對(duì)象。

          ??? 第二步,對(duì)于所有 Jaxen 實(shí)現(xiàn)都一樣,就是創(chuàng)建一個(gè) HashMap 對(duì)象,用于保存“前綴-命名空間的 URI”的映射。
          ?
          ??? 為了能通過 Dom4j 使用 Jaxen 的 XPath 功能,需要?jiǎng)?chuàng)建一個(gè)與 Dom4j 相關(guān)的 XPath 對(duì)象:Dom4jXPath。創(chuàng)建方法是把 XPath 的表達(dá)式(即“//edx:cd”)傳給 Dom4jXPath 的構(gòu)造方法。
          ?
          ??? 現(xiàn)在,我們已經(jīng)創(chuàng)建了 XPath 對(duì)象,接下來可以把“前綴-命名空間”的映射表傳遞給 XPath 引擎:把這個(gè) HashMap 映射表用 SimpleNamespaceContext 包裝起來。SimpleNamespaceContext 是 Jaxen 的 NamespaceContext 接口的默認(rèn)實(shí)現(xiàn)類。
          ?
          ??? 最后一步就是調(diào)用 XPath 對(duì)象的 selectNodes() 方法進(jìn)行查找。并把完整的 Dom4j? Document 對(duì)象作為參數(shù)傳遞進(jìn)去。實(shí)際上,Document 中的任何結(jié)點(diǎn)都可以作為參數(shù)。

          Jaxen 和 XOM
          ??? XOM 是基于簡(jiǎn)單的 Java DOM APIs 之上的最新工具,它的設(shè)計(jì)初衷是提供簡(jiǎn)單和易學(xué)易用的接口。
          ?
          try {
          ? Builder builder = new Builder();
          ? Document document = builder.build( "file:catalog.xml");
          ?
          ? HashMap map = new HashMap();
          ? map.put( "edx", "
          http://www.edankert.com/examples/ ");
          ?
          ? XPath xpath = new XOMXPath( "http://edx:cd");
          ? xpath.setNamespaceContext( new SimpleNamespaceContext( map));
          ?
          ? List nodes = xpath.selectNodes( document);
          ?
          ? ...
          ?
          } catch ( JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( IOException e) {
          ? // An error occurred opening the document
          ? ...
          } catch ( ParsingException e) {
          ? // An error occurred parsing the document
          ? ...
          }

          ?
          ??? 我們需要?jiǎng)?chuàng)建一個(gè) Builder 對(duì)象,從文件系統(tǒng)中讀取“catalog.xml”文件,并創(chuàng)建出與 XOM 相關(guān)的 Document 對(duì)象。
          ?
          ??? 下一步創(chuàng)建出包含了“前綴-命名空間”映射關(guān)系的 HashMap 對(duì)象。
          ?
          ??? 我們需要?jiǎng)?chuàng)建一個(gè)特定于 XOM 的 XPath 對(duì)象:XOMXPath。創(chuàng)建方法是把 XPath 表達(dá)式傳遞給構(gòu)造方法,然后就可以通過 XOM 使用 Jaxen 的 XPath 功能了。
          ?
          ??? 創(chuàng)建完 XPath 對(duì)象后,同樣,我們把“前綴-命名空間”的映射表用 SimpleNamespaceContext 對(duì)象封裝后,傳遞給 XPath 引擎。
          ?
          ??? 最后調(diào)用 XPath 對(duì)象的“selectNodes()”方法進(jìn)行查找,把 XOM Document 對(duì)象作為本方法的參數(shù)。
          Jaxen 和 JDOM
          ??? JDOM 是第一個(gè)提供簡(jiǎn)單的 XML 訪問 API 的工具。
          ?
          try {
          ? SAXBuilder builder = new SAXBuilder();
          ? Document document = builder.build( "file:catalog.xml");
          ?
          ? HashMap map = new HashMap();
          ? map.put( "edx", "
          http://www.edankert.com/examples/ ");
          ?
          ? XPath xpath = new JDOMXPath( "http://edx:cd");
          ? xpath.setNamespaceContext( new SimpleNamespaceContext( map));
          ?
          ? List nodes = xpath.selectNodes( document);
          ?
          ? ...
          ?
          } catch ( JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( IOException e) {
          ? // An error occurred opening the document
          ? ...
          } catch ( JDOMException e) {
          ? // An error occurred parsing the document
          ? ...
          }

          ?
          ??? 首先,通過 SAXBuilder 創(chuàng)建了一個(gè)特定于 JDom 的 Document 對(duì)象。
          ?
          ??? 接著創(chuàng)建一個(gè)特定于 JDOM 的 XPath 對(duì)象:JDOMXPath。
          ?
          ??? 然后,把“前綴-命名空間”的映射表(HashMap)用 SimpleNamespaceContext 對(duì)象封裝起來,傳遞給 XPath 引擎。
          ?
          ??? 最后調(diào)用 XPath 對(duì)象的“selectNodes()”方法來進(jìn)行查找,并把 JDOM 的 Document 對(duì)象作為本方法的輸入?yún)?shù)。
          JAXP XPathFactory
          ??? 從 1.3 版起, JAXP 還提供了一種在 XML Object Models 上進(jìn)行查詢的通用機(jī)制。
          ?
          try {
          ?DocumentBuilderFactory domFactory =DocumentBuilderFactory.newInstance();
          ? domFactory.setNamespaceAware( true);
          ?
          ?DocumentBuilder builder = domFactory.newDocumentBuilder();Document document = builder.parse( new InputSource( "file:catalog.xml"));
          ?
          ?XPathFactory factory =XPathFactory.newInstance();
          ?XPath xpath = factory.newXPath();
          ? xpath.setNamespaceContext( new NamespaceContext() {
          ??? public String getNamespaceURI(String prefix) {
          ????? if ( prefix.equals( "edx")) {
          ??????? return "
          http://www.edankert.com/examples/ ";
          ????? } else if ...
          ??????? ...
          ????? }
          ?????
          ????? return XPathConstants.NULL_NS_URI;
          ??? }
          ?
          ??? public String getPrefix(String namespaceURI) {
          ????? if ( namespaceURI.equals( "
          http://www.edankert.com/examples/ ")) {
          ??????? return "edx";
          ????? } else if ...
          ??????? ...
          ????? }?
          ???
          ????? return null;
          ??? }
          ?
          ??? public Iterator getPrefixes(String namespaceURI) {
          ???? ArrayList list = new ArrayList();
          ???
          ????? if ( namespaceURI.equals( "
          http://www.edankert.com/examples/ ")) {
          ??????? list.add( "edx");
          ????? } else if ...
          ??????? ...
          ????? }
          ???
          ????? return list.iterator();
          ??? }
          ? });
          ?
          ?Object nodes = xpath.evaluate( "http://edx:cd", document.getDocumentElement(),
          ??????????????????????????????? XPathConstants.NODESET);
          ?
          ? ...
          ?
          } catch (ParserConfigurationException e) {
          ? ...
          } catch (XPathExpressionException e) {
          ? ...
          } catch (SAXException e) {
          ? ...
          } catch (IOException e) {
          ? ...
          }

          ??? 首先用 JAXP 的 DocumentBuilderFactory 創(chuàng)建一個(gè)org.w3c.dom.Document 對(duì)象,確保啟用了 namespace 處理功能。
          ?
          ??? 現(xiàn)在可以通過 XPathFactory 來創(chuàng)建 XPath 對(duì)象,并通過 XPath 對(duì)象對(duì)文檔進(jìn)行查詢。
          ?
          ??? 為了創(chuàng)建“前綴-命名空間”映射并傳遞給 XPath 引擎,我們需要實(shí)現(xiàn) NamespaceContext 接口,該接口目前還沒有默認(rèn)實(shí)現(xiàn)類。這就意味著要實(shí)現(xiàn) getNamespaceURI、getPrefix 和getPrefixes 方法,并確保這些方法能返回正確的值,包括“xmlns”和“xml”前綴所對(duì)應(yīng)的命名空間的 URI 值。
          ?
          ??? 把我們自己實(shí)現(xiàn)的 NamespaceContext 對(duì)象傳遞給 XPath 引擎后,就可以通過 evaluate 方法來查詢 XPath 表達(dá)式所對(duì)應(yīng)的元素:使用上文中提到的 XPath 表達(dá)式,并使用 Document 的根節(jié)點(diǎn)作為輸入入?yún)?shù),并接收一個(gè) NodeList 對(duì)象作為返回結(jié)果。
          XSLT
          ??? XPath 設(shè)計(jì)的初衷是用于 XSLT。這也許能解釋“為什么在 XSLT 中定義命名空間的前綴是一件很平常的事”(也許因?yàn)?XSLT 也是一個(gè) XML 名詞的緣故吧)。
          ?
          <xsl:stylesheet version="1.1" xmlns:xsl="
          http://www.w3.org/1999/XSL/Transform ">
          ? <xsl:template match="http://edx:cd" xmlns:edx="
          http://www.edankert.com/examples/ ">
          ??? <xsl:apply-templates/>
          ? </xsl:template>
          </xsl:stylesheet>
          ?
          ??? 只需要使用 XML 本身的機(jī)制,簡(jiǎn)單地為 edx 前綴賦予一個(gè)命名空間的 URI 值。
          ?
          ??? 通過與我們的 XPath 表達(dá)式“//edx:cd”相匹配的 xsl:template,能得到與上文其他例子相同的輸出結(jié)果。

          結(jié)束語
          ??? 為了在(缺省)命名空間上使用 XPath 表達(dá)式,我們需要指定一個(gè)“前綴-命名空間”映射。正如我們所看到的,具體使用什么樣的前綴名稱,是無關(guān)緊要的。
          ?
          ??? 同樣的方法,也可以用于查詢那些用其他前綴修飾的元素。這意味著上面的例子對(duì)下述 XML 也有效。下述 XML 沒有使用缺省命名空間,而是使用了 examples 作命名空間的前綴:
          ?
          <examples:catalog xmlns:examples="
          http://www.edankert.com/examples/ ">
          ? <examples:cd>
          ??? <examples:artist>Sufjan Stevens</examples:artist>
          ??? <examples:title>Illinois</examples:title>
          ??? <examples:src>http://www.sufjan.com/</examples:src>
          ? </examples:cd>
          ? <examples:cd>
          ??? <examples:artist>Stoat</examples:artist>
          ??? <examples:title>Future come and get me</examples:title>
          ??? <examples:src>http://www.stoatmusic.com/</examples:src>
          ? </examples:cd>
          ? <examples:cd>
          ??? <examples:artist>The White Stripes</examples:artist>
          ??? <examples:title>Get behind me satan</examples:title>
          ??? <examples:src>http://www.whitestripes.com/</examples:src>
          ? </examples:cd>
          </examples:catalog>

          ?
          ??? 使用“//edx:cd”作為 XPath 表達(dá)式,使用與前文例子相同的“前綴-命名空間”映射,在這個(gè) XML 上同樣能查詢出屬于“http://www.edankert.com/examples/”命名空間的所有“cd”元素。
          資源
          Extensible Markup Language (XML) 1.0 (Third Edition)
          http://www.w3.org/TR/REC-xml/
          Namespaces in XML
          http://www.w3.org/TR/REC-xml-names/
          XML Path Language (XPath) Version 1.0
          http://www.w3.org/TR/xpath
          XSL Transformations (XSLT) Version 1.0
          http://www.w3.org/TR/xslt
          dom4j
          http://www.dom4j.org/
          XOM
          http://www.xom.nu/
          JDOM
          http://www.jdom.org/
          Jaxen
          http://www.jaxen.org/
          Java 5.0
          http://java.sun.com/j2se/1.5.0/

          posted @ 2007-03-21 10:13 比特鼠 閱讀(1728) | 評(píng)論 (1)編輯 收藏

          spring事務(wù)探索

          原文出處:
          http://www.javaeye.com/topic/11190

          spring自建事務(wù)管理模塊。而且這個(gè)事務(wù)管理是一個(gè)抽象設(shè)計(jì),可以應(yīng)用到很多場(chǎng)合,包括普通的DataSource,jta,jms和hibernate上。

          要正確使用spring的事務(wù),首先需要了解spring在事務(wù)設(shè)計(jì)上的一些概念
          統(tǒng)觀spring事務(wù),圍繞著兩個(gè)核心PlatformTransactionManager和TransactionStatus

          PlatformTransactionManager直譯過來就是平臺(tái)相關(guān)事務(wù),這里的平臺(tái)指的是“事務(wù)源”,包括剛才我說的DataSource,jta等等。這些無一不是一個(gè)事務(wù)源。廣義的說,凡是可以完成事務(wù)性操作的對(duì)象,都可以設(shè)計(jì)出相對(duì)應(yīng)的PlatformTransactionManager,只要這個(gè)事務(wù)源支持commit,rollback和getTransaction語意。

          查看spring代碼,可以發(fā)現(xiàn)這些manager實(shí)現(xiàn)事務(wù),就是調(diào)用事務(wù)源的事務(wù)操作方法

          比如

          HibernateTransactionManager

          代碼

          ?

          1. protected ? void ?doCommit(DefaultTransactionStatus?status)?{ ??
          2. ????????HibernateTransactionObject?txObject?=?(HibernateTransactionObject)?status.getTransaction(); ??
          3. ???????? if ?(status.isDebug())?{ ??
          4. ????????????logger.debug( "Committing?Hibernate?transaction?on?session?[" ?+ ??
          5. ????????????????????txObject.getSessionHolder().getSession()?+? "]" ); ??
          6. ????????} ??
          7. ???????? try ?{ ??
          8. ????????????txObject.getSessionHolder().getTransaction().commit(); ??
          9. ????????} ??
          10. ... ??
          11. ??
          12. ????}??

          jdbc 的DataSourceTransactionManager

          代碼

          ?

          1. protected ? void ?doCommit(DefaultTransactionStatus?status)?{ ??
          2. ????????DataSourceTransactionObject?txObject?=?(DataSourceTransactionObject)?status.getTransaction(); ??
          3. ????????Connection?con?=?txObject.getConnectionHolder().getConnection(); ??
          4. ???????? if ?(status.isDebug())?{ ??
          5. ????????????logger.debug( "Committing?JDBC?transaction?on?connection?[" ?+?con?+? "]" ); ??
          6. ????????} ??
          7. ???????? try ?{ ??
          8. ????????????con.commit(); ??
          9. ????????} ??
          10. ????????... ??
          11. ????}??

          那么PlatformTransactionManager以什么依據(jù)處理事務(wù)呢?
          是TransactionStatus
          查看api發(fā)現(xiàn)這個(gè)接口有三個(gè)方法
          isNewTransaction() ,isRollbackOnly(),setRollbackOnly()
          PlatformTransactionManager就是根據(jù)前兩個(gè)方法決定是否要?jiǎng)?chuàng)建一個(gè)新事務(wù),是要遞交還是回滾。至于第三個(gè)方法是改變事務(wù)當(dāng)前狀態(tài)的,很多地方都要用到,偏偏PlatformTransactionManager自身好像不怎么用,畢竟事務(wù)狀態(tài)的改變是由程序員代碼決定的,不需要一個(gè)manager多管閑事。

          總結(jié)上面所說的,spring的事務(wù)由PlatformTransactionManager管理,manager最后調(diào)用事務(wù)源的方法來實(shí)現(xiàn)一個(gè)事務(wù)過程。而manager通過TransactionStatus 來決定如何實(shí)現(xiàn)。

          接下去說spring事務(wù)中的TransactionTemplate和TransactionInterceptor

          TransactionTemplate其實(shí)和spring中其他的template的作用類似,起到化簡(jiǎn)代碼的作用,不要被它那么長(zhǎng)的名字嚇倒了,事實(shí)上這個(gè)template并不是什么非常核心的對(duì)象。如果比較學(xué)究派的,可以去看看template設(shè)計(jì)模式,在此就不再對(duì)此贅述了。
          為什么要有TransactionTemplate?先來看看如果沒有TransactionTemplate,我們的代碼該怎么寫

          先來看看spring reference中的一段代碼

          代碼

          ?

          1. DefaultTransactionDefinition?def?=? new ?DefaultTransactionDefinition() ??
          2. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); ??
          3. ??
          4. TransactionStatus?status?=?transactionManager.getTransaction(def); ??
          5. ??
          6. try ?{ ??
          7. ???? //?execute?your?business?logic?here ??
          8. }? catch ?(MyException?ex)?{ ??
          9. ????transactionManager.rollback(status); ??
          10. ???? throw ?ex; ??
          11. } ??
          12. transactionManager.commit(status);??


          這是直接使用transactionManager的例子,可以看到真正執(zhí)行business logic 的地方是在try當(dāng)中那段,前后的代碼都是為了完成事務(wù)管理的。如果每個(gè)business logic都要寫上那么一段,我肯定是瘋了。我們翻出TransactionTemplate的代碼看看他怎么化簡(jiǎn)了我們的代碼

          代碼

          ?

          1. public ?Object?execute(TransactionCallback?action)? throws ?TransactionException?{ ??
          2. ????????TransactionStatus?status?=? this .transactionManager.getTransaction( this ); ??
          3. ????????Object?result?=? null ; ??
          4. ???????? try ?{ ??
          5. ????????????result?=?action.doInTransaction(status); ??
          6. ????????} ??
          7. ???????? catch ?(RuntimeException?ex)?{ ??
          8. ???????????? //?transactional?code?threw?application?exception?->?rollback ??
          9. ????????????rollbackOnException(status,?ex); ??
          10. ???????????? throw ?ex; ??
          11. ????????} ??
          12. ???????? catch ?(Error?err)?{ ??
          13. ???????????? //?transactional?code?threw?error?->?rollback ??
          14. ????????????rollbackOnException(status,?err); ??
          15. ???????????? throw ?err; ??
          16. ????????} ??
          17. ???????? this .transactionManager.commit(status); ??
          18. ???????? return ?result; ??
          19. ????}??

          同上面的代碼如出一轍,前后是事務(wù)處理代碼,當(dāng)中那段result = action.doInTransaction(status);是我們的應(yīng)用代碼。至于action是什么,全看各位的需要了。但是有一點(diǎn)要主要,如果利用TransactionTemplate,那么他不管你扔出什么異常都會(huì)回滾事務(wù),但是回滾的是哪個(gè)事務(wù)呢?繼續(xù)挖代碼

          代碼

          ?

          1. private ? void ?rollbackOnException(TransactionStatus?status,?Throwable?ex)? throws ?TransactionException?{ ??
          2. ???????? if ?(logger.isDebugEnabled())?{ ??
          3. ????????????logger.debug( "Initiating?transaction?rollback?on?application?exception" ,?ex); ??
          4. ????????} ??
          5. ???????? try ?{ ??
          6. ???????????? this .transactionManager.rollback(status); ??
          7. ????????} ??
          8. ???????? catch ?(RuntimeException?ex2)?{ ??
          9. ????????????logger.error( "Application?exception?overridden?by?rollback?exception" ,?ex); ??
          10. ???????????? throw ?ex2; ??
          11. ????????} ??
          12. ???????? catch ?(Error?err)?{ ??
          13. ????????????logger.error( "Application?exception?overridden?by?rollback?error" ,?ex); ??
          14. ???????????? throw ?err; ??
          15. ????????} ??
          16. ????}??


          真相大白,是對(duì)template所持有的某個(gè)transactionManager進(jìn)行回滾。所以如果你的應(yīng)用代碼用的是事務(wù)源a的一些資源,比如到服務(wù)器a的一個(gè)datasource,但是你的transactionManager管理的是另一些資源,比如服務(wù)器b的一個(gè)datasource,代碼鐵定不會(huì)正常運(yùn)行

          特別是在一些多事務(wù)源的程序里,這點(diǎn)千萬不能搞錯(cuò)。如果多個(gè)事務(wù)源之間要完成全局事務(wù),還是老老實(shí)實(shí)用分布式事務(wù)管理服務(wù)吧(jta)

          那么TransactionInterceptor是干什么的?這個(gè)是spring 的聲明式事務(wù)的支持方式。因?yàn)橛肨ransactionTemplate要硬編碼,而且調(diào)整事務(wù)策略很麻煩(不是說不能調(diào)。舉個(gè)例子原來程序拋出異常A需要回滾,現(xiàn)在不需要要,我就可以把a(bǔ) catch吃掉。這時(shí)候template就不會(huì)回滾了。但是每次調(diào)整都要重寫編碼。)而用TransactionInterceptor就可以將這些調(diào)整寫在配置中。我們?cè)賮硗赥ransactionInterceptor的代碼

          代碼

          ?

          1. public ?Object?invoke(MethodInvocation?invocation)? throws ?Throwable?{ ??
          2. ???????? //?Work?out?the?target?class:?may?be?null. ??
          3. ???????? //?The?TransactionAttributeSource?should?be?passed?the?target?class ??
          4. ???????? //?as?well?as?the?method,?which?may?be?from?an?interface ??
          5. ????????Class?targetClass?=?(invocation.getThis()?!=? null )???invocation.getThis().getClass()?:? null ; ??
          6. ???????? ??
          7. ???????? //?Create?transaction?if?necessary ??
          8. ????????TransactionInfo?txInfo?=?createTransactionIfNecessary(invocation.getMethod(),?targetClass); ??
          9. ??
          10. ????????Object?retVal?=? null ; ??
          11. ???????? try ?{ ??
          12. ???????????? //?This?is?an?around?advice. ??
          13. ???????????? //?Invoke?the?next?interceptor?in?the?chain. ??
          14. ???????????? //?This?will?normally?result?in?a?target?object?being?invoked. ??
          15. ????????????retVal?=?invocation.proceed(); ??
          16. ????????} ??
          17. ???????? catch ?(Throwable?ex)?{ ??
          18. ???????????? //?target?invocation?exception ??
          19. ????????????doCloseTransactionAfterThrowing(txInfo,?ex); ??
          20. ???????????? throw ?ex; ??
          21. ????????} ??
          22. ???????? finally ?{ ??
          23. ????????????doFinally(txInfo); ??
          24. ????????} ??
          25. ????????doCommitTransactionAfterReturning(txInfo); ??
          26. ??
          27. ???????? return ?retVal; ??
          28. ????}??


          萬變不離其宗。

          所以使用spring的事務(wù)管理需要作這些事
          1,設(shè)置好事務(wù)源,比如DataSource,hibernate的session。如果有多個(gè)事務(wù)源要考慮他們之間是否有全局事務(wù),如果有,老老實(shí)實(shí)用jta,否則就需要自己寫一個(gè)manager了
          2,設(shè)置manager,根據(jù)你的事務(wù)源選擇對(duì)應(yīng)的PlatformTransactionManager
          3,選擇實(shí)現(xiàn)事物的方式,用template還是interceptor。用template代碼直觀點(diǎn),但是template所管轄的manager和你應(yīng)用代碼所用的事務(wù)源要一致。如果用interceptor千萬注意,一定要調(diào)用interceptor那個(gè)bean,而不是原始的那個(gè)target。在壇子上我已經(jīng)看到至少有兩個(gè)朋友說spring事物不起作用,從配置和代碼上看都正確,這時(shí)要好好查查,調(diào)用的bean是哪一個(gè)。
          4,這個(gè)是設(shè)計(jì)問題了,推薦事務(wù)處于一個(gè)較高層次,比如service上的某個(gè)函數(shù),而底層的dao可以不考慮事務(wù),否則可能會(huì)出現(xiàn)事務(wù)嵌套,增加程序復(fù)雜度。

          posted @ 2007-03-05 14:45 比特鼠 閱讀(249) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 临桂县| 岳普湖县| 称多县| 胶州市| 红安县| 桦甸市| 宜州市| 清水县| 乌鲁木齐县| 吉水县| 东兰县| 阳江市| 宾川县| 开江县| 桃源县| 浠水县| 海安县| 舟山市| 任丘市| 昂仁县| 保山市| 浠水县| 辽中县| 稻城县| 乐清市| 改则县| 平舆县| 乌鲁木齐市| 罗田县| 曲麻莱县| 麻城市| 大埔区| 新沂市| 渝北区| 香港| 永顺县| 元氏县| 临城县| 乐山市| 钦州市| 海南省|