一輩子的程序員?

          愛你一生不變-芳芳!
          posts - 27, comments - 15, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          我們已經(jīng)知道,在 document 對象中有一個 cookie 屬性。但是 Cookie 又是什么?“某些 Web 站點在您的硬盤上用很小的文本文件存儲了一些信息,這些文件就稱為 Cookie。”—— MSIE 幫助。一般來說,Cookies 是 CGI 或類似,比 HTML 高級的文件、程序等創(chuàng)建的,但是 javascript 也提供了對 Cookies 的很全面的訪問權利。

            我們先要學一學 Cookie 的基本知識。

            每個 Cookie 都是這樣的:<cookie名>=<值>

            <cookie名>的限制與 javascript 的命名限制大同小異,少了“不能用 javascript 關鍵字”,多了“只能用可以用在 URL 編碼中的字符”。后者比較難懂,但是只要你只用字母和數(shù)字命名,就完全沒有問題了。<值>的要求也是“只能用可以用在 URL 編碼中的字符”。

            每個 Cookie 都有失效日期,一旦電腦的時鐘過了失效日期,這個 Cookie 就會被刪掉。我們不能直接刪掉一個 Cookie,但是可以用設定失效日期早于現(xiàn)在時刻的方法來間接刪掉它。

            每個網(wǎng)頁,或者說每個站點,都有它自己的 Cookies,這些 Cookies 只能由這個站點下的網(wǎng)頁來訪問,來自其他站點或同一站點下未經(jīng)授權的區(qū)域的網(wǎng)頁,是不能訪問的。每一“組”Cookies 有規(guī)定的總大小(大約 2KB 每“組”),一超過最大總大小,則最早失效的 Cookie 先被刪除,來讓新的 Cookie“安家”。

            現(xiàn)在我們來學習使用 documents.cookie 屬性。

            如果直接使用 document.cookie 屬性,或者說,用某種方法,例如給變量賦值,來獲得 document.cookie 的值,我們就可以知道在現(xiàn)在的文檔中有多少個 Cookies,每個 Cookies 的名字,和它的值。例如,在某文檔中添加“document.write(document.cookie)”,結果顯示:

          name=kevin; email=kevin@kevin.com; lastvisited=index.html

          這意味著,文檔包含 3 個 Cookies:name, email 和 lastvisited,它們的值分別是 kevin, kevin@kevin.com 和 index.html。可以看到,兩個 Cookies 之間是用分號和空格隔開的,于是我們可以用 cookieString.split('; ') 方法得到每個 Cookie 分開的一個數(shù)組(先用 var cookieString = document.cookie)。

            設定一個 Cookie 的方法是對 documents.cookie 賦值。與其它情況下的賦值不同,向 documents.cookie 賦值不會刪除掉原有的 Cookies,而只會增添 Cookies 或更改原有 Cookie。賦值的格式:
          documents.cookie = 'cookieName=' + escape('cookievalue')
          + ';expires=' + expirationDateObj.toGMTString();
          是不是看到頭暈了呢?cookieName 表示 Cookie 的名稱,cookievalue 表示 Cookie 的值,expirationDateObj 表示儲存著失效日期的日期對象名,如果不需要指定失效日期,則不需要第二行。不指定失效日期,則瀏覽器默認是在關閉瀏覽器(也就是關閉所有窗口)之后過期。

            首先 escape() 方法:為什么一定要用?因為 Cookie 的值的要求是“只能用可以用在 URL 編碼中的字符”。我們知道“escape()”方法是把字符串按 URL 編碼方法來編碼的,那我們只需要用一個“escape()”方法來處理輸出到 Cookie 的值,用“unescape()”來處理從 Cookie 接收過來的值就萬無一失了。而且這兩個方法的最常用途就是處理 Cookies。其實設定一個 Cookie 只是“documents.cookie = 'cookieName=cookievalue'”這么簡單,但是為了避免在 cookievalue 中出現(xiàn) URL 里不準出現(xiàn)的字符,還是用一個 escape() 好。
            然后“expires”前面的分號:注意到就行了。是分號而不是其他。
            最后 toGMTString() 方法:設定 Cookie 的時效日期都是用 GMT 格式的時間的,其它格式的時間是沒有作用的。

            現(xiàn)在我們來實戰(zhàn)一下。設定一個“name=rose”的 Cookie,在 3 個月后過期。
          var expires = new Date();
          expires.setTime(expires.getTime() + 3 * 30 * 24 * 60 * 60 * 1000);
          /* 三個月 x 一個月當作 30 天 x 一天 24 小時
          x 一小時 60 分 x 一分 60 秒 x 一秒 1000 毫秒 */
          documents.cookie = 'name=rose;expires=' + expires.toGMTString();

          為什么沒有用 escape() 方法?這是因為我們知道 rose 是一個合法的 URL 編碼字符串,也就是說,'rose' == escape('rose')。一般來說,如果設定 Cookie 時不用 escape(),那獲取 Cookie 時也不用 unescape()。

            再來一次:編寫一個函數(shù),作用是查找指定 Cookie 的值。
          function getCookie(cookieName) {
          var cookieString = documents.cookie;
          var start = cookieString.indexOf(cookieName + '=');
          // 加上等號的原因是避免在某些 Cookie 的值里有
          // 與 cookieName 一樣的字符串。
          if (start == -1) // 找不到
          return null;
          start += cookieName.length + 1;
          var end = cookieString.indexOf(';', start);
          if (end == -1) return unescape(cookieString.substring(start));
          return unescape(cookieString.substring(start, end));
          }

          這個函數(shù)用到了字符串對象的一些方法,如果你不記得了(你是不是這般沒記性啊),請快去查查。這個函數(shù)所有的 if 語句都沒有帶上 else,這是因為如果條件成立,程序運行的都是 return 語句,在函數(shù)里碰上 return,就會終止運行,所以不加 else 也沒問題。該函數(shù)在找到 Cookie 時,就會返回 Cookie 的值,否則返回“null”。

            現(xiàn)在我們要刪除剛才設定的 name=rose Cookie。
          var expires = new Date();
          expires.setTime(expires.getTime() - 1);
          documents.cookie = 'name=rose;expires=' + expires.toGMTString();

          posted @ 2006-08-18 15:11 boddi 閱讀(144) | 評論 (0)編輯 收藏

          Java 多線程程序設計要點(synchronized)
          Tag:JAVA基礎

          多線程程序設計要點:

          ? 1.多線程中有主內存和工作內存之分, 在JVM中,有一個主內存,專門負責所有線程共享數(shù)據(jù);而每個線程都有他自己私有的工作內存, 主內存和工作內存分貝在JVM的stack區(qū)和heap區(qū)。

          ? 2.線程的狀態(tài)有'Ready', 'Running', 'Sleeping', 'Blocked', 和 'Waiting'幾個狀態(tài),
          'Ready' 表示線程正在等待CPU分配允許運行的時間。

          ? 3.線程運行次序并不是按照我們創(chuàng)建他們時的順序來運行的,CPU處理線程的順序是不確定的,如果需要確定,那么必須手工介入,使用setPriority()方法設置優(yōu)先級。

          ? 4.我們無從知道一個線程什么時候運行,兩個或多個線程在訪問同一個資源時,需要synchronized

          ? 5. 每個線程會注冊自己,實際某處存在著對它的引用,因此,垃圾回收機制對它就“束手無策”了。

          ? 6. Daemon線程區(qū)別一般線程之處是:主程序一旦結束,Daemon線程就會結束。

          ? 7. 一個對象中的所有synchronized方法都共享一把鎖,這把鎖能夠防止多個方法對通用內存同時進行的寫操作。synchronized static方法可在一個類范圍內被相互間鎖定起來。

          ? 8. 對于訪問某個關鍵共享資源的所有方法,都必須把它們設為synchronized,否則就不能正常工作。

          ? 9. 假設已知一個方法不會造成沖突,最明智的方法是不要使用synchronized,能提高些性能。

          ? 10. 如果一個\"同步"方法修改了一個變量,而我們的方法要用到這個變量(可能是只讀),最好將自己的這個方法也設為 synchronized。

          ? 11. synchronized不能繼承,? 父類的方法是synchronized,那么其子類重載方法中就不會繼承“同步”。

          ? 12. 線程堵塞Blocked有幾個原因造成:

          ? (1)線程在等候一些IO操作
          ? (2)線程試圖調用另外一個對象的“同步”方法,但那個對象處于鎖定狀態(tài),暫時無法使用。

          ? 13.原子型操作(atomic), 對原始型變量(primitive)的操作是原子型的atomic. 意味著這些操作是線程安全的, 但是大部分情況下,我們并不能正確使用,來看看 i = i + 1 , i是int型,屬于原始型變量:

          ? (1)從主內存中讀取i值到本地內存.
          ? (2)將值從本地內存裝載到線程工作拷貝中.
          ? (3)裝載變量1.
          ? (4)將i 加 1.
          ? (5)將結果給變量i.
          ? (6)將i保存到線程本地工作拷貝中.
          ? (7)寫回主內存.

          ? 注意原子型操作只限于第1步到第2步的讀取以及第6到第7步的寫, i的值還是可能被同時執(zhí)行i=i+1的多線程中斷打擾(在第4步)。

          ? double 和long 變量是非原子型的(non-atomic)。數(shù)組是object 非原子型。

          ? 14. 由于13條的原因,我們解決辦法是:

          ? class xxx extends Thread{
          ?? //i會被經(jīng)常修改
          ? private int i;

          ? public synchronized int read(){ return i;}

          ? public synchronized void update(){ i = i + 1;}

          ? ..........

          ? }
          ?

          ? 15. Volatile變量, volatile變量表示保證它必須是與主內存保持一致,它實際是"變量的同步", 也就是說對于volatile變量的操作是原子型的,如用在long 或 double變量前。

          ? 16. 使用yield()會自動放棄CPU,有時比sleep更能提升性能。

          ? 17. sleep()和wait()的區(qū)別是:wait()方法被調用時會解除鎖定,但是我們能使用它的地方只是在一個同步的方法或代碼塊內。

          ? 18. 通過制造縮小同步范圍,盡可能的實現(xiàn)代碼塊同步,wait(毫秒數(shù))可在指定的毫秒數(shù)可退出wait;對于wait()需要被notisfy()或notifyAll()踢醒。

          ? 19. 構造兩個線程之間實時通信的方法分幾步:
          ? (1). 創(chuàng)建一個PipedWriter和一個PipedReader和它們之間的管道;
          ? PipedReader in = new PipedReader(new PipedWriter())
          ? (2). 在需要發(fā)送信息的線程開始之前,將外部的PipedWriter導向給其內部的Writer實例out
          ? (3). 在需要接受信息的線程開始之前,將外部的PipedReader導向給其內部的Reader實例in
          ? (4). 這樣放入out的所有東西度可從in中提取出來。

          ? 20. synchronized帶來的問題除性能有所下降外,最大的缺點是會帶來死鎖DeadLock,只有通過謹慎設計來防止死鎖,其他毫無辦法,這也是線程難以馴服的一個原因。不要再使用stop() suspend() resume()和destory()方法

          ? 21. 在大量線程被堵塞時,最高優(yōu)先級的線程先運行。但是不表示低級別線程不會運行,運行概率小而已。

          ? 22. 線程組的主要優(yōu)點是:使用單個命令可完成對整個線程組的操作。很少需要用到線程組。

          ? 23. 從以下幾個方面提升多線程的性能:

          ? 檢查所有可能Block的地方,盡可能的多的使用sleep或yield()以及wait();

          ? 盡可能延長sleep(毫秒數(shù))的時間;

          ? 運行的線程不用超過100個,不能太多;

          ? 不同平臺linux或windows以及不同JVM運行性能差別很大。


          shiweifu?發(fā)表于?22:24:04??

          posted @ 2006-08-15 14:46 boddi 閱讀(184) | 評論 (0)編輯 收藏

          attachEvent() / addEventListener() 對象添加觸發(fā)事件(轉)

          有時候當某一對象的某一事件被觸發(fā)時,它所要執(zhí)行的程序可能是一大串,有可能是要呼叫某一函數(shù),也有可能同時又要呼叫另一函數(shù)。

          document.getElementById("btn").onclick = method1;
          document.getElementById("btn").onclick = method2;
          document.getElementById("btn").onclick = method3;
          如果這樣寫,那么將會只有medhot3被執(zhí)行

          在IE中使用addachEvent ,

          var btn1Obj = document.getElementById("btn1");
          //object.attachEvent(event,function);
          btn1Obj.attachEvent("onclick",method1);
          btn1Obj.attachEvent("onclick",method2);
          btn1Obj.attachEvent("onclick",method3);
          執(zhí)行順序為method3->method2->method1

          Mozilla系列中需要使用 addEventListener

          var btn1Obj = document.getElementById("btn1");
          //element.addEventListener(type,listener,useCapture);
          btn1Obj.addEventListener("click",method1,false);
          btn1Obj.addEventListener("click",method2,false);
          btn1Obj.addEventListener("click",method3,false);
          執(zhí)行順序為method1->method2->method3

          看看gmail的代碼

          var Ka=navigator.userAgent.toLowerCase();
          var rt=Ka.indexOf("opera")!=-1;
          var r=Ka.indexOf("msie")!=-1&&(document.all&&!rt);

          function Zl(a,b,c){if(r){a.attachEvent("on"+b,c)}else{a.addEventListener(b,c,false)}}

          posted @ 2006-08-15 09:47 boddi 閱讀(5588) | 評論 (1)編輯 收藏

          javascript事件列表解說

          ?
          javascript事件列表解說
          事件瀏覽器支持解說
          一般事件onclickIE3、N2 鼠標點擊時觸發(fā)此事件
          ondblclickIE4、N4 鼠標雙擊時觸發(fā)此事件
          onmousedownIE4、N4 按下鼠標時觸發(fā)此事件
          onmouseupIE4、N4 鼠標按下后松開鼠標時觸發(fā)此事件
          onmouseoverIE3、N2 當鼠標移動到某對象范圍的上方時觸發(fā)此事件
          onmousemoveIE4、N4 鼠標移動時觸發(fā)此事件
          onmouseoutIE4、N3當鼠標離開某對象范圍時觸發(fā)此事件
          onkeypressIE4、N4 當鍵盤上的某個鍵被按下并且釋放時觸發(fā)此事件.
          onkeydownIE4、N4 當鍵盤上某個按鍵被按下時觸發(fā)此事件
          onkeyupIE4、N4 當鍵盤上某個按鍵被按放開時觸發(fā)此事件
          頁面相關事件onabortIE4、N3 圖片在下載時被用戶中斷
          onbeforeunloadIE4、N 當前頁面的內容將要被改變時觸發(fā)此事件
          onerrorIE4、N3 出現(xiàn)錯誤時觸發(fā)此事件
          onloadIE3、N2 頁面內容完成時觸發(fā)此事件
          onmoveIE、N4 瀏覽器的窗口被移動時觸發(fā)此事件
          onresizeIE4、N4 當瀏覽器的窗口大小被改變時觸發(fā)此事件
          onscrollIE4、N 瀏覽器的滾動條位置發(fā)生變化時觸發(fā)此事件
          onstopIE5、N 瀏覽器的停止按鈕被按下時觸發(fā)此事件或者正在下載的文件被中斷
          onunloadIE3、N2 當前頁面將被改變時觸發(fā)此事件
          表單相關事件onblurIE3、N2 當前元素失去焦點時觸發(fā)此事件
          onchangeIE3、N2 當前元素失去焦點并且元素的內容發(fā)生改變而觸發(fā)此事件
          onfocusIE3 、N2當某個元素獲得焦點時觸發(fā)此事件
          onresetIE4 、N3 當表單中RESET的屬性被激發(fā)時觸發(fā)此事件
          onsubmitIE3 、N2 一個表單被遞交時觸發(fā)此事件
          滾動字幕事件onbounceIE4、N在Marquee內的內容移動至Marquee顯示范圍之外時觸發(fā)此事件
          onfinishIE4、N當Marquee元素完成需要顯示的內容后觸發(fā)此事件
          onstartIE4、 N當Marquee元素開始顯示內容時觸發(fā)此事件
          編輯事件onbeforecopyIE5、N當頁面當前的被選擇內容將要復制到瀏覽者系統(tǒng)的剪貼板前觸發(fā)此事件
          onbeforecutIE5、 N當頁面中的一部分或者全部的內容將被移離當前頁面[剪貼]并移動到瀏覽者的系統(tǒng)剪貼板時觸發(fā)此事件
          onbeforeeditfocusIE5、N當前元素將要進入編輯狀態(tài)
          onbeforepasteIE5、 N內容將要從瀏覽者的系統(tǒng)剪貼板傳送[粘貼]到頁面中時觸發(fā)此事件
          onbeforeupdateIE5、 N當瀏覽者粘貼系統(tǒng)剪貼板中的內容時通知目標對象
          oncontextmenuIE5、N當瀏覽者按下鼠標右鍵出現(xiàn)菜單時或者通過鍵盤的按鍵觸發(fā)頁面菜單時觸發(fā)的事件
          oncopyIE5、N當頁面當前的被選擇內容被復制后觸發(fā)此事件
          oncutIE5、N 當頁面當前的被選擇內容被剪切時觸發(fā)此事件
          ondragIE5、N 當某個對象被拖動時觸發(fā)此事件 [活動事件]
          ondragdropIE、N4一個外部對象被鼠標拖進當前窗口或者幀
          ondragendIE5、N當鼠標拖動結束時觸發(fā)此事件,即鼠標的按鈕被釋放了
          ondragenterIE5、N當對象被鼠標拖動的對象進入其容器范圍內時觸發(fā)此事件
          ondragleaveIE5、N 當對象被鼠標拖動的對象離開其容器范圍內時觸發(fā)此事件
          ondragoverIE5、N當某被拖動的對象在另一對象容器范圍內拖動時觸發(fā)此事件
          ondragstartIE4、N當某對象將被拖動時觸發(fā)此事件
          ondropIE5、N在一個拖動過程中,釋放鼠標鍵時觸發(fā)此事件
          onlosecaptureIE5、N當元素失去鼠標移動所形成的選擇焦點時觸發(fā)此事件
          onpasteIE5、N當內容被粘貼時觸發(fā)此事件
          onselect IE4、N當文本內容被選擇時的事件
          onselectstartIE4、N當文本內容選擇將開始發(fā)生時觸發(fā)的事件
          數(shù)據(jù)綁定onafterupdateIE4、N當數(shù)據(jù)完成由數(shù)據(jù)源到對象的傳送時觸發(fā)此事件
          oncellchangeIE5、N當數(shù)據(jù)來源發(fā)生變化時
          ondataavailableIE4、N當數(shù)據(jù)接收完成時觸發(fā)事件
          ondatasetchangedIE4、N數(shù)據(jù)在數(shù)據(jù)源發(fā)生變化時觸發(fā)的事件
          ondatasetcompleteIE4、N當來子數(shù)據(jù)源的全部有效數(shù)據(jù)讀取完畢時觸發(fā)此事件
          onerrorupdateIE4、N當使用onBeforeUpdate事件觸發(fā)取消了數(shù)據(jù)傳送時,代替onAfterUpdate事件
          onrowenterIE5、N當前數(shù)據(jù)源的數(shù)據(jù)發(fā)生變化并且有新的有效數(shù)據(jù)時觸發(fā)的事件
          onrowexitIE5、N當前數(shù)據(jù)源的數(shù)據(jù)將要發(fā)生變化時觸發(fā)的事件
          onrowsdeleteIE5、N當前數(shù)據(jù)記錄將被刪除時觸發(fā)此事件
          onrowsinsertedIE5、N當前數(shù)據(jù)源將要插入新數(shù)據(jù)記錄時觸發(fā)此事件
          外部事件onafterprintIE5、N當文檔被打印后觸發(fā)此事件
          onbeforeprintIE5、N當文檔即將打印時觸發(fā)此事件
          onfilterchangeIE4、N當某個對象的濾鏡效果發(fā)生變化時觸發(fā)的事件
          onhelpIE4、N當瀏覽者按下F1或者瀏覽器的幫助選擇時觸發(fā)此事件
          onpropertychangeIE5、N當對象的屬性之一發(fā)生變化時觸發(fā)此事件
          onreadystatechangeIE4、N當對象的初始化屬性值發(fā)生變化時觸發(fā)此事件
          onactivate 當對象設置為活動元素時觸發(fā)。
          onafterupdate 當成功更新數(shù)據(jù)源對象中的關聯(lián)對象后在數(shù)據(jù)綁定對象上觸發(fā)。
          onbeforedeactivate 在 activeElement 從當前對象變?yōu)楦肝臋n其它對象之前立即觸發(fā)。
          onbeforeupdate 當成功更新數(shù)據(jù)源對象中的關聯(lián)對象前在數(shù)據(jù)綁定對象上觸發(fā)。
          onblur 在對象失去輸入焦點時觸發(fā)。
          oncontrolselect 當用戶將要對該對象制作一個控件選中區(qū)時觸發(fā)。
          ondeactivate 當 activeElement 從當前對象變?yōu)楦肝臋n其它對象時觸發(fā)。
          onerrorupdate 更新數(shù)據(jù)源對象中的關聯(lián)數(shù)據(jù)出錯時在數(shù)據(jù)綁定對象上觸發(fā)。
          onfocus 當對象獲得焦點時觸發(fā)。
          onload 在瀏覽器完成對象的裝載后立即觸發(fā)。
          onmove 當對象移動時觸發(fā)。
          onmoveend 當對象停止移動時觸發(fā)。
          onmovestart 當對象開始移動時觸發(fā)。
          onreadystatechange 當對象狀態(tài)變更時觸發(fā)。
          onresizeend 當用戶更改完控件選中區(qū)中對象的尺寸時觸發(fā)。
          onresizestart 當用戶開始更改控件選中區(qū)中對象的尺寸時觸發(fā)。
          ontimeerror 當特定時間錯誤發(fā)生時無條件觸發(fā),通常由將屬性設置為無效值導致。:

          JavaScript 事件串聯(lián)執(zhí)行多個處理過程的方法

          JavaScript 事件串聯(lián)執(zhí)行多個處理過程的方法

          2006-01-04 @ 15:46:42 · 作者 andot · 歸類于 JavaScript

          以前寫 JavaScript 程序時,事件都是采用

          object . event = handler ;

          的方式初始化。這種方式對于 Internet Explorer、Mozilla/Firefox 和 Opera 來說很通用。但是有一個問題就是,這種方式只能一個事件對應一個事件處理過程。如果希望一個事件可以依次執(zhí)行多個處理過程就不好用了。

          但是 Internet Explorer 從 5.0 開始提供了一個 attachEvent 方法,使用這個方法,就可以給一個事件指派多個處理過程了。attachEvent 對于目前的 Opera 也適用。但是問題是 Mozilla/Firefox 并不支持這個方法。但是它支持另一個 addEventListener 方法,這個方法跟 attachEvent 差不多,也是用來給一個事件指派多個處理過程的。但是它們指派的事件有些區(qū)別,在 attachEvent 方法中,事件是以 “on” 開頭的,而在 addEventListener 中,事件沒有開頭的 “on”,另外 addEventListener 還有第三個參數(shù),一般這個參數(shù)指定為 false 就可以了。

          因此要想在你的程序中給一個事件指派多個處理過程的話,只要首先判斷一下瀏覽器,然后根據(jù)不同的瀏覽器,選擇使用 attachEvent 還是 addEventListener 就可以了。實例如下:

          if ( document . all ) {
          ?? ?
          window . attachEvent ( ' onload ' , handler1 ) ;
          ?? ?
          window . attachEvent ( ' onload ' , handler2 ) ;
          }
          else {
          ?? ?
          window . addEventListener ( ' load ' , handler1 , false ) ;
          ?? ?
          window . addEventListener ( ' load ' , handler2 , false ) ;
          }

          注意:attachEvent 所指派的多個過程的執(zhí)行順序是隨機的,所以這幾個過程之間不要有順序依賴。另外 attachEvent 和 addEventListener 不僅僅適用于 window 對象,其他的一些對象也支持該方法。

          posted @ 2006-08-10 20:43 boddi 閱讀(268) | 評論 (0)編輯 收藏

          在Java?2的Collections框架中,主要包括兩個接口及其擴展和實現(xiàn)類:Collection接口和Map接口。兩者的區(qū)別在于前者存儲一組對象,后者則存儲一些關鍵字/值對。

          public?interface?java.util.Map?{

          ????//Altering?Methods
          ??????public?Object?put(Object?key,?Object?value);????
          ??????public?Object?remove(Object?key);??????????????
          ??????public?void?putAll(java.util.Map);?????????????
          ??????public?void?clear();???

          ????//Querying?Methods
          ??????public?Object?get(Object?key);???????????
          ??????public?int?size();?????????????????????
          ??????public?boolean?isEmpty();??????????????????
          ??????public?boolean?containsKey(Object);??????????
          ??????public?boolean?containsValue(Object);??????????
          ??????public?boolean?equals(Object);?????????????????

          ????//Viewing?Methods
          ??????public?java.util.Set?keySet();??????????????????//Gets?keys
          ??????public?java.util.Collection?values();???????????//Gets?values
          ??????public?java.util.Set?entrySet();????????????????//Gets?mappings

          ??????public?static?interface?java.util.Map.Entry?{???//a?map-entry?(single?key/value?pair)
          ?????????public?Object?getKey();????????????????????//returns?current?entry?key
          ?????????public?Object?getValue();??????????????????//returns?current?entry?value
          ????????public?Object?setValue(Object?value);??????
          ??public?boolean?equals(Object);?????????????
          ??public?int?hashCode();?????????????????????????}
          }
          Map接口提供了方便易用的方法,通過這些方法可以查詢、查看、修改當前Map的內容。注意對于Map接口的keySet()方法返回一個Set,Set是Collection接口的一個擴展,包含不重復的一組對象。因為Map中的key是不可重復的,所以得到所有key的keySet()方法返回一個Set對象。Map接口本身還包含了一個Map.Entry接口,一個Map.Entry就是Map中的一個關鍵字/值對。Map接口中的entrySet()方法就返回了一個集合對象,其中每一個元素都實現(xiàn)了Map.Entry接口。Map接口的get(Object?key),put(Object?key,Object?value),和remove(Object?key)方法都有同一個問題。他們的返回類型都是Object,當返回null時,可以猜測為調用那個方法前那個key不存在。但是只有在null不允許作為Map的值時可以這樣猜測。所有Map接口的通用實現(xiàn)都允許null作為key或者value,這就說當返回一個null值,就可以意味著很多事情。只是因為通用實現(xiàn)允許null值,你不能下那個映射有null值的結論。如果你確知沒有null值,那返回null值就意味著調用那個方法前,映射里并沒有那個鍵。否則,你必須調用containsKey(Object?key)來看看那個Key是否存在。

          Hashtable


          java.util.Hashtable實現(xiàn)了Map接口,在Hashtable中使用key對象的hashCode()作為對應的對象的相對存儲地址,以便實現(xiàn)根據(jù)關鍵字快速查找對象的功能。所以只有一個實現(xiàn)了hashCode()和equals()方法的對象才可作為Hashtable的key。null值不能作為關鍵字或值。
          public?class?java.util.Hashtable?extends?Dictionary?implements?Cloneable,?Map,?Serializable?{

          ?????//Hashtable?constructors
          ?????//construct?a?default?Hashtable?with?default?capacity?and?load?of?0.75
          ?????public?Hashtable();?????????????????????
          ?????//construct?a?Hashtable?with?passed?capacity?and?default?load?of?0.75?
          ?????public?Hashtable?(int?initialCapacity);?
          ?????//construct?Hashtable?with?passed?capacity?and?load?
          ?????public?Hashtable(int?initialCapacity,?float?load);?
          ?????//construct?Hashtable?with?passed?mapping?
          ?????public?Hashtable(Map);??????????????????
          ?????
          ?????//Hashtable?specific?methods
          ?????//checks?if?Object?is?in?Hashtable?
          ?????public?boolean?contains(Object);????????
          ?????//returns?Enumeration?of?elements?in?Hashtable?
          ?????public?Enumeration?elements();??????????
          ?????//returns?Enumeration?of?keys?in?hashtable
          ?????public?Enumeration?keys();??????????????
          ?????//creates?shallow?copy?of?Hashtable(structure?copied,?but?not?key/values)
          ?????public?Object?clone();??????????????????
          ?????//prints?out?key/value?pairs?of?Hashtable?elements
          ?????public?String?toString();???????????????
          ?????//reorganizes?all?elements?in?Hashtable,?and?increases?Hashtable?capacity?
          ?????protected?void?rehash();????????????????
          ?????
          ?????//get?Value?from?passed?in?key?
          ?????public?Object?get(Object);??????????????
          ?????//insert?key/value?pair
          ?????public?Object?put(Object?key,?Object?value);??????

          }
          Hashtable是Java?2集合框架推出之前的一個老的工具類,在新的Java?2集合框架下,已經(jīng)被HashMap取代。Hashtable和HashMap的區(qū)別主要是前者是同步的,后者是快速失敗機制保證不會出現(xiàn)多線程并發(fā)錯誤(Fast-Fail)。在初始化一個Hashtable時,可以指定兩個參數(shù):初始容量、負荷,這兩個參數(shù)強烈的影響著Hashtable的性能。容量是指對象的個數(shù),負荷是指散列表中的實際存儲的對象個數(shù)和容量的比率。如果初始容量太小,那么Hashtable需要不斷的擴容并rehash(),而這是很耗時的;如果初始容量太大,又會造成空間的浪費。負荷則相反,負荷太小會造成空間浪費,負荷太大又會耗時(因為這會造成較多的關鍵字的散列碼重復,Hashtable使用一個鏈接表來存儲這些重復散列碼的對象)。容量的缺省值是11,負荷的缺省值是0.75,一般情況下你都可以使用缺省值來生成一個Hashtable。另外,在Hashtable中的大部分的方法都是同步的。

          HashMap


          HashMap基本實現(xiàn)了Map接口的全部方法。方法的簽名大家看上面的Map接口。這兒主要說說幾個Map接口中的方法。
          按照集合框架的實現(xiàn),哈希表是單鏈表作為元素的數(shù)組,有著同樣索引值的兩個或更多入口被一起鏈結到單鏈表中。哈希表聲明如下:
          ????private?Entry[]?table;
          組件類型Entry是Map.Entry接口的實現(xiàn),Map.Entry聲明于Map接口內。下邊是Map.Entry接口的簡化實現(xiàn):
          ????private?static?class?Entry?implements?Map.Entry{
          ????????int?hashCode;
          ????????Object?key;
          ????????Object?value;
          ????????Entry?next;

          ????????Entry(int?hashCode,Object?key,Object?value,Entry?next){
          ????????????This.hashCode=hashCode;
          ????????????This.key=key;
          ????????????This.value=value;
          ????????????This.next=next;
          }
          public?Object?getKey(){
          ????return?key;
          }
          public?Object?getValue(){
          ????return?value;
          }
          public?Object?setValue(Object?value){
          ????Object?oldValue=this.value;
          ????This.value=value;
          ????Return?oldValue;
          }
          }

          SortedMap是Map接口的子接口,SortedMap的標準實現(xiàn)是TreeMap,實現(xiàn)了一個排序的Map。這兒不再做說明。本站翻譯的《Java?規(guī)則》(Java?Rules)中對Java2的集合框架有深入的研究。本文限于篇幅,只及皮毛。有興趣的朋友,請參考Java2源碼中的集合實現(xiàn)代碼和API?doc。

          posted @ 2006-08-05 17:15 boddi 閱讀(380) | 評論 (0)編輯 收藏

          如何優(yōu)化JavaScript腳本的性能

          隨著網(wǎng)絡的發(fā)展,網(wǎng)速和機器速度的提高,越來越多的網(wǎng)站用到了豐富客戶端技術。而現(xiàn)在Ajax則是最為流行的一種方式。JavaScript是一種解釋型語言,所以能無法達到和C/Java之類的水平,限制了它能在客戶端所做的事情,為了能改進他的性能,我想基于我以前給JavaScript做過的很多測試來談談自己的經(jīng)驗,希望能幫助大家改進自己的JavaScript腳本性能。

          ?

          語言層次方面

          循環(huán)

          循環(huán)是很常用的一個控制結構,大部分東西要依靠它來完成,在JavaScript中,我們可以使用for(;;),while(),for(in)三種循環(huán),事實上,這三種循環(huán)中for(in)的效率極差,因為他需要查詢散列鍵,只要可以就應該盡量少用。for(;;)和while循環(huán)的性能應該說基本(平時使用時)等價。

          而事實上,如何使用這兩個循環(huán),則有很大講究。最后得出的結論是:

          • 如果是循環(huán)變量遞增或遞減,不要單獨對循環(huán)變量賦值,應該在它最后一次讀取的時候使用嵌套的++或—操作符。

          • 如果要與數(shù)組的長度作比較,應該事先把數(shù)組的length屬性放入一個局部變量中,減少查詢次數(shù)。

          局部變量和全局變量

          局部變量的速度要比全局變量的訪問速度更快,因為全局變量其實是全局對象的成員,而局部變量是放在函數(shù)的棧當中的。

          不使用Eval

          使用eval相當于在運行時再次調用解釋引擎對內容進行運行,需要消耗大量時間。這時候使用JavaScript所支持的閉包可以實現(xiàn)函數(shù)模版(關于閉包的內容請參考函數(shù)式編程的有關內容)

          減少對象查找

          因為JavaScript的解釋性,所以a.b.c.d.e,需要進行至少4次查詢操作,先檢查a再檢查a中的b,再檢查b中的c,如此往下。所以如果這樣的表達式重復出現(xiàn),只要可能,應該盡量少出現(xiàn)這樣的表達式,可以利用局部變量,把它放入一個臨時的地方進行查詢。

          這一點可以和循環(huán)結合起來,因為我們常常要根據(jù)字符串、數(shù)組的長度進行循環(huán),而通常這個長度是不變的,比如每次查詢a.length,就要額外進行一個操作,而預先把var len=a.length,則就少了一次查詢。

          字符串連接

          如果是追加字符串,最好使用s+=anotherStr操作,而不是要使用s=s+anotherStr。

          如果要連接多個字符串,應該少使用+=,如

          s+=a;
          s+=b;
          s+=c;

          應該寫成

          s+=a + b + c;

          而如果是收集字符串,比如多次對同一個字符串進行+=操作的話,最好使用一個緩存。怎么用呢?使用JavaScript數(shù)組來收集,最后使用join方法連接起來,如下

          var buf = new Array();
          for(var i = 0; i < 100; i++){
          buf.push(i.toString());
          }
          var all = buf.join("");

          類型轉換

          類型轉換是大家常犯的錯誤,因為JavaScript是動態(tài)類型語言,你不能指定變量的類型。

          1. 把數(shù)字轉換成字符串,應用"" + 1,雖然看起來比較丑一點,但事實上這個效率是最高的,性能上來說:

          ("" +) > String() > .toString() > new String()

          這條其實和下面的“直接量”有點類似,盡量使用編譯時就能使用的內部操作要比運行時使用的用戶操作要快。

          String()屬于內部函數(shù),所以速度很快,而.toString()要查詢原型中的函數(shù),所以速度遜色一些,new String()用于返回一個精確的副本。

          2. 浮點數(shù)轉換成整型,這個更容易出錯,很多人喜歡使用parseInt(),其實parseInt()是用于將字符串轉換成數(shù)字,而不是浮點數(shù)和整型之間的轉換,我們應該使用Math.floor()或者Math.round()。

          另外,和第二節(jié)的對象查找中的問題不一樣,Math是內部對象,所以Math.floor()其實并沒有多少查詢方法和調用的時間,速度是最快的。

          3. 對于自定義的對象,如果定義了toString()方法來進行類型轉換的話,推薦顯式調用toString(),因為內部的操作在嘗試所有可能性之后,會嘗試對象的toString()方法嘗試能否轉化為String,所以直接調用這個方法效率會更高

          使用直接量

          其實這個影響倒比較小,可以忽略。什么叫使用直接量,比如,JavaScript支持使用[param,param,param,...]來直接表達一個數(shù)組,以往我們都使用new Array(param,param,...),使用前者是引擎直接解釋的,后者要調用一個Array內部構造器,所以要略微快一點點。

          同樣,var foo = {}的方式也比var foo = new Object();快,var reg = /../;要比var reg=new RegExp()快。

          字符串遍歷操作

          對字符串進行循環(huán)操作,譬如替換、查找,應使用正則表達式,因為本身JavaScript的循環(huán)速度就比較慢,而正則表達式的操作是用C寫成的語言的API,性能很好。

          高級對象

          自定義高級對象和Date、RegExp對象在構造時都會消耗大量時間。如果可以復用,應采用緩存的方式。

          DOM相關

          插入HTML

          很多人喜歡在JavaScript中使用document.write來給頁面生成內容。事實上這樣的效率較低,如果需要直接插入HTML,可以找一個容器元素,比如指定一個div或者span,并設置他們的innerHTML來將自己的HTML代碼插入到頁面中。

          對象查詢

          使用[“”]查詢要比.items()更快,這和前面的減少對象查找的思路是一樣的,調用.items()增加了一次查詢和函數(shù)的調用。

          創(chuàng)建DOM節(jié)點

          通常我們可能會使用字符串直接寫HTML來創(chuàng)建節(jié)點,其實這樣做

          1. 無法保證代碼的有效性

          2. 字符串操作效率低

          所以應該是用document.createElement()方法,而如果文檔中存在現(xiàn)成的樣板節(jié)點,應該是用cloneNode()方法,因為使用createElement()方法之后,你需要設置多次元素的屬性,使用cloneNode()則可以減少屬性的設置次數(shù)——同樣如果需要創(chuàng)建很多元素,應該先準備一個樣板節(jié)點。

          定時器

          如果針對的是不斷運行的代碼,不應該使用setTimeout,而應該是用setInterval。setTimeout每次要重新設置一個定時器。

          其他

          腳本引擎

          據(jù)我測試Microsoft的JScript的效率較Mozilla的Spidermonkey要差很多,無論是執(zhí)行速度還是內存管理上,因為JScript現(xiàn)在基本也不更新了。但SpiderMonkey不能使用ActiveXObject

          文件優(yōu)化

          文件優(yōu)化也是一個很有效的手段,刪除所有的空格和注釋,把代碼放入一行內,可以加快下載的速度,注意,是下載的速度而不是解析的速度,如果是本地,注釋和空格并不會影響解釋和執(zhí)行速度。

          總結

          本文總結了我在JavaScript編程中所找到的提高JavaScript運行性能的一些方法,其實這些經(jīng)驗都基于幾條原則:

          1. 直接拿手頭現(xiàn)成的東西比較快,如局部變量比全局變量快,直接量比運行時構造對象快等等。

          2. 盡可能少地減少執(zhí)行次數(shù),比如先緩存需要多次查詢的。

          3. 盡可能使用語言內置的功能,比如串鏈接。

          4. 盡可能使用系統(tǒng)提供的API,因為這些API是編譯好的二進制代碼,執(zhí)行效率很高

          同時,一些基本的算法上的優(yōu)化,同樣可以用在JavaScript中,比如運算結構的調整,這里就不再贅述了。但是由于JavaScript是解釋型的,一般不會在運行時對字節(jié)碼進行優(yōu)化,所以這些優(yōu)化仍然是很重要的。

          當然,其實這里的一些技巧同樣使用在其他的一些解釋型語言中,大家也可以進行參考。

          posted @ 2006-07-19 10:13 boddi 閱讀(211) | 評論 (0)編輯 收藏

          escape() & encodeURI() & encodeURIComponent()

          escape() & encodeURI() & encodeURIComponent()這三個函數(shù)都可以用來對URI進行encode或過濾特殊字符(#/$&+=?/等)。我的經(jīng)驗是最好用encodeURIComponent()(需要IE 5.5以上,F(xiàn)ireFox當然沒問題),因為對UTF-8支持比較好,不會遇到中文亂碼問題,否則還需要進行編碼轉換,很麻煩的。Terac Rome就是用的encodeURIComponent(),del.icio.us和365key用的是escape()。當然,有人這三個函數(shù)都不用,自己寫過濾函數(shù),我覺得那純粹是浪費精力。

          下面是MSDN上對這三個函數(shù)的解釋:

          escape(charString)

          The escape method returns a string value (in Unicode format) that contains the contents of charstring. All spaces, punctuation, accented characters, and any other non-ASCII characters are replaced with %xx encoding, where xx is equivalent to the hexadecimal number representing the character. For example, a space is returned as "%20."

          Characters with a value greater than 255 are stored using the %uxxxx format.

          Note?? The escape method should not be used to encode Uniform Resource Identifiers (URI). Use encodeURI and encodeURIComponent methods instead.

          http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthescape.asp

          ?encodeURI(URIString)

          The encodeURI method returns an encoded URI. If you pass the result to decodeURI, the original string is returned. The encodeURI method does not encode the following characters: ":", "/", ";", and "?". Use encodeURIComponent to encode these characters.

          http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthfencodeuri.asp

          encodeURIComponent(encodedURIString)

          The encodeURIComponent method returns an encoded URI. If you pass the result to decodeURIComponent, the original string is returned. Because the encodeURIComponent method encodes all characters, be careful if the string represents a path such as /folder1/folder2/default.html. The slash characters will be encoded and will not be valid if sent as a request to a web server. Use the encodeURI method if the string contains more than a single URI component.

          http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthencodeuricomponent.asp
          encodeURIComponent 方法返回一個已編碼的 URI。如果將編碼結果傳遞給 decodeURIComponent,則將返回初始的字符串。因為 encodeURIComponent 方法將對所有字符編碼,請注意,如果該字符串代表一個路徑,例如 /kyle/blogpost.asp,則其中的斜杠也將被編碼,這樣,當該字符串作為請求發(fā)送到 Web 服務器時它將是無效的。如果字符串中包含多個 URI 組件,請使用 encodeURI 方法進行編碼。
          【例子】encodeURIComponent('/?&神泥') 返回 %2F%3F%26%E7%A5%9E%E6%B3%A5

          encodeURI 方法返回一個已編碼的 URI。如果將編碼結果傳遞給 decodeURI,則將返回初始的字符串。encodeURI 不對下列字符進行編碼:“:”、“/”、“;”和“?”。請使用 encodeURIComponent 對這些字符進行編碼。
          【例子】encodeURI('/?&神泥') 返回 /?&%E7%A5%9E%E6%B3%A5

          posted @ 2006-07-19 10:00 boddi 閱讀(544) | 評論 (0)編輯 收藏

          僅列出標題
          共3頁: 上一頁 1 2 3 
          主站蜘蛛池模板: 大化| 神木县| 英吉沙县| 慈利县| 嵊州市| 高陵县| 舞钢市| 渭源县| 新乐市| 图木舒克市| 昆明市| 会理县| 宜宾县| 吴旗县| 南丹县| 自治县| 大竹县| 太湖县| 鄂伦春自治旗| 赤水市| 玉林市| 梧州市| 鄂托克前旗| 军事| 丹江口市| 泗阳县| 大渡口区| 漳浦县| 眉山市| 望都县| 诸暨市| 宁乡县| 承德市| 杨浦区| 鄄城县| 汝城县| 云南省| 延边| 永泰县| 竹溪县| 彭山县|