javaGrowing

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            92 隨筆 :: 33 文章 :: 49 評論 :: 0 Trackbacks

          #

          用Java解決國際化問題


          首都經貿大學信息學院 尹海琴
          01-7-18 上午 09:11:22


          如果應用系統是面向多種語言的,編程時就不得不設法解決國際化問題,包括操作界面的風格問題、提示和幫助語言的版本問題、界面定制個性化問題等。
          由于Java語言具有平臺無關、可移植性好等優點,并且提供了強大的類庫,所以Java語言可以輔助我們解決上述問題。Java語言本身采用雙字節字符編 碼,采用大漢字字符集,這就為解決國際化問題提供了很多方便。從設計角度來說,只要把程序中與語言和文化有關的部分分離出來,加上特殊處理,就可以部分解 決國際化問題。在界面風格的定制方面,我們把可以參數化的元素,如字體、顏色等,存儲在數據庫里,以便為用戶提供友好的界面;如果某些部分包含無法參數化 的元素,那么我們可能不得不分別設計,通過有針對性的編碼來解決具體問題。
          Java類包
          在用Java解決國際化問題的過程中,可能利用到的主要的類都是由java.util包提供的。該類包中相關的類有Locale、 ResourceBundle、ListResourceBundle、PropertyResourceBundle等,其繼承關系如下圖所示。
          其中各類提供的主要功能如下:
          Locale:該類包含對主要地理區域的地域化特征的封裝。其特定對象表示某一特定的地理、政治或文化區域。通過設定Locale,我們可以為特定的國家 或地區提供符合當地文化習慣的字體、符號、圖標和表達格式。例如,我們可以通過獲得特定Locale下的Calendar類的實例,顯示符合特定表達格式 的日期。
          ResourceBundle:該類是一個抽象類,需要通過靜態方法ResourceBundle.getBundle()指定具體實現類或屬性文件的基 本名稱。基本名稱會協同指定的或默認的Locale類,決定具體調用的類或屬性文件的唯一名稱。例如:指定基本類或屬性文件名稱為TestBundle, 而指定的Locale是CHINESE,那么最適合匹配的類名稱為TestBundle_zh_CN.class,而最佳匹配屬性文件名稱為 TestBundle_zh_CN.properties。按照Java Doc和相關文檔的要求,如果該類或屬性文件沒有找到,系統會查找近似匹配(主文件名依次為TestBundle_zh和TestBundle的類或屬性 文件)。該類提供的getKeys()方法用于獲得所有成員的鍵名,并提供handleGetObject方法獲得指定鍵的對應元素。
          ListResourceBundle:該類繼承ResourceBundle類,主要是增加了一些便于操作的成分,但還是抽象類。如果希望使用類的方式實現具體的ResourceBundle,一般情況下最好繼承這個類。
          PropertyResourceBundle:該類也繼承ResourceBundle類,可以實例化。該類的行為特征如同java.util.properties類,可以從輸入流中獲得具體屬性對。
          如果涉及日期和時間顯示等問題時,可以利用java.text包以及java.util包中的TimeZone、SimpleTimeZone和Calendar等類進行輔助處理。
          參數化解決方法
          在具體應用時,可以把具體國家或地區特征中可以參數化的部分放在經過特殊命名的屬性文件中,在確定具體的Locale后,通過PropertyResourceBundle類讀取相應的屬性文件,實現國際化特征。
          使用PropertyResourceBundle類獲得當地版本的國際化信息,部分代碼如下:
            ……
            public static final String BASE_PROP_FILE =
          “DISP”;
            public static final String SUFFIX =
          “.properties”;
            locale = Locale.getDefault();
            String propFile = BASE_PROP_FILE + “_” + locale.toString()+ SUFFIX;
            ResourceBundle rb;
            try {
             File file = new File(propFile);
             if (file.exists()) {
             is = new FileInputStream(file);
             rb = new PropertyResourceBundle(is);
             if (rb == null) System.out.println(“No Resource”);
             }
            } catch (IOException ioe) {
             System.out.println(“Error open file named ” + propFile);
            }
            Enumeration e = rb.getKeys();
            while (e.hasMoreElements()){
             key = (String)e.nextElement();
             value = (String)rb.handleGetObject(key);
             System.out.println(“KEY: ” + key +
          “\t\t Value: ” + value);
            }
            ……
            DISP_zh_TW.properties文件的具體內容如下:
            Key1=\u53ef\u4ee5
            Key2=\u64a4\u9500
          等號后面是利用native2ascii程序轉化后的繁體漢字,如果不進行轉化,系統可能顯示亂碼。
          處理提示和幫助
          對于提示語言和幫助文件部分,可以把語言映射放在屬性文件或者ListResourceBundle類的子類中。下面程序是一個Servlet,它通過接受客戶端的選擇,把特定語言和字符版本的信息返回到客戶端。
            ……
            public class ProcessServlet extends HttpServlet
            { //默認語言為中文
             public static final String DEFAULT_LANGUAGE = “zh”;
             //默認字符集為簡體中文
             public static final String DEFAULT_COUNTRY = “CN”;
             public void service(HttpServletRequest req,
          HttpServletResponse res) throws IOException, ServletException {
             HttpSession session = req.getSession(true);
             // 從客戶端收到的指定語言和字符的參數應當與Sun公司相關規定一致
             String lang = req.getParameter
          (“language”);
             String country = req.getParameter
          (“country”);
             if (lang == null)
              {
          //如果沒有收到參數,就試圖從Session里獲得
             lang = (String) session.getAttribute
          (“language”);
             country = (String) session.getAttribute
          (“country”)
             } else {
             session.setAttribute(“language”, lang);
             session.setAttribute(“country”, country);
             }
             if (lang == null)
              {
          //如果無法從上述手段得到語言和字符信息,就使用默認值
             lang = DEFAULT_LANGUAGE;
             country = DEFAULT_COUNTRY
             session.setAttribute(“language”, lang);
              session.setAttribute(“country”, country);
             }
             Locale locale = null;
             ResourceBundle bundle = null;
             try {
             locale = new Locale(lang, country);
             } catch (Exception e) {
             System.out.println(“No locale with” +
          country + “_” + lang);
             locale = Locale.getDefault();
             }
             try {
             bundle = ResourceBundle.getBundle(
          “DisplayList”, locale);
             } catch( MissingResourceException e) {
             System.out.println( “No resources available for locale ” + locale);
             bundle = ResourceBundle.getBundle
          (“DisplayList”, Locale.US);
             }
             res.setContentType(“text/html”);
             PrintWriter out = res.getWriter();
             out.println(“<html>”);
             out.println(“<head>”);
             String title = bundle.getString(“title”);
            String welcome =bundle.getString
          (“welcome”);
             String notice = bundle.getString(“notice”);
             out.println(“<title>”+ title +
          “</title>”);
             out.println(“</head>”);
             out.println(“<body bgcolor=\”
          white\“>”);
             out.println(“<h3>” + welcome +
          “</h3>”);
             out.println(“<br>”);
             out.println(“<b>” + notice +
          “</b>”);
             out.println(“</body>”);
             out.println(“</html>”);
             }
            }
          上述Servlet使用的屬性文件(DisplayList_zh_CN.
          properties)內容如下:
          title=中文版
          welcome=這是簡體中文版面
          notice=簡體中文測試成功
          注意:該文件直接采用了中文,而不是經過轉化的Unicode編碼,這是由于大多數Web服務器不需要上述轉化。
          在實際使用中,如果Web服務器支持Servlet 2.3規范(如jakarta-tomcate 4.0),那么上面提到的Servlet應當稍加改變,以作為其他Servlet的處理器使用。另外,如果把ResourceBundle的特定版本存放 在無狀態會話Bean中,就可以在一定程度上提高程序效率。
          小 結
          筆者在實際測試中發現了如下問題,其中部分問題得到了解決:
          1. 對于顯示字符出現亂碼的問題,如果是通過屬性文件實現國際化解決方案,那么可能是直接在屬性文件中寫入了非標準ASCII文字。解決方法是利用JDK提供 的工具native2ascii.exe掃描所有屬性文件,用掃描結果覆蓋原有文件內容。如果我們是利用類文件實現轉換方案,那么需要重新編譯相關類文 件,并在編譯時指定編碼集。例如,編譯使用國標碼的類文件,采用的編譯命令如下:
          javac -encoding GB2312 your_java_file
          2. 雖然Sun宣稱,在ResourceBundle類的實例化過程中,該類會查找與指定的基礎類絕對匹配和盡量與指定的Locale屬性相匹配的類。例如: 如果我們指定ResourceBundle基礎類為TestBundle,而Locale中指定使用zh_CN(中國大陸地區簡體中文),那么如果系統找 不到TestBundle_zh_CN,系統應當順次查找TestBundle_zh、TestBundle。但是筆者在系統開發過程中發現,該匹配沒有 產生任何實際效果。
          筆者的測試平臺是Windows 2000 Server,沒有配置任何Service Pack,使用的JDK版本是1.3.0版本。筆者試圖通過查看JDK目錄下src.jar中附帶的源碼找到引起問題的原因,但是發現有關的操作被封裝在 sun.misc包中,而src.jar文件沒有提供該包中任何類的源碼。本文把這個問題提出來,希望與有關開發人員一起探討。
          posted @ 2005-12-14 10:57 javaGrowing 閱讀(399) | 評論 (0)編輯 收藏

               摘要: 侯捷觀點 Java反射機制   摘要 Reflection 是Java被視為動態(或準動態)語言的一個關鍵性質。這個機制允許程序在運行時透過Reflection APIs取得任何一個已知名稱的class的內部信息,包括其modifiers(諸如public, static 等等)、superclass(例如Object)、實現之interfaces(例如Cloneable),也包括fie...  閱讀全文
          posted @ 2005-12-09 16:58 javaGrowing 閱讀(948) | 評論 (1)編輯 收藏

          認識.NET的集合 - 開發者 - ZDNet China


          認識.NET的集合

          作者: BUILDER.COM
          Wednesday, May 15 2002 11:06 AM

           集合(collection)提供了一種結構化組織任意對象的方式,而且我們早就知道集合在日常編程工作中的重要性。.NET類庫提供了豐富的集合數據類型,其種類之繁多甚至使許多人看得眼都花了,這些集合對象都具有各自的專用場合。不管怎么說,更多的選擇也就意味著更高的靈活性,但同時也意味著更高的復雜性。因此,對集合各個類型的用途和使用條件具有適度的了解是完全必要的。下面就請隨我進行一場.NET集合之旅吧!

          .NET集合定義


          從.NET的角度看,所謂的集合可以定義為一種對象,這種對象實現一個或者多個System.Collections.ICollectionSystem.Collections.IDictionarySystem.Collections.IList接口。這一定義把System.Collections名稱空間中的“內置”集合劃分成了三種類別:

          • 有序集合:僅僅實現ICollection接口的集合,在通常情況下,其數據項目的插入順序控制著從集合中取出對象的的順序。System.Collections.Stack和 System.Collections.Queue類都是ICollection集合的典型例子。
          • 索引集合:實現Ilist的集合,其內容能經由從零開始的數字檢索取出,就象數組一樣。System.Collections.ArrayList對象是索引集合的一個例子。
          • 鍵式集合:實現 IDictionary 接口的集合,其中包含了能被某些類型的鍵值檢索的項目。IDictionary集合的內容通常按鍵值方式存儲,可以用枚舉的方式排序檢索。 System.Collections.HashTable類實現了IDictionary 接口。

          正如你看到的那樣,給定集合的功能在很大程度上受到特定接口或其實現接口的控制。如果你對面向對象編程缺乏了解,那么你可能對上面說的這些話感到難以理解。不過你至少應該知道,以接口這種方式構造對象的功能不但造就了具有整套類似方法的對象族,而且還能讓這些對象在必要的情況下可以當作同類,以OOP(面向對象編程)的術語來說,這就是大名鼎鼎的多態性技術。

          System.Collections概述

          System.Collections名稱空間包含了在你的應用程序中可以用到的6種內建通用集合。另一些更為專業化的集合則歸屬于System.Collections.Specialized,在某些情況下你會發現這些專用集合也是非常有用的。加上一些異常(exception)類,這些專業化集合在功能上和內建集合是類似的。現在就讓我們審視一下通用集合以及少量的不太富于專業化的集合。

          堆棧和隊列

          System.Collections.Stack 和 System.Collections.Queue 類,兩者僅僅實現了ICollection 接口,按照存儲項目加到集合的順序保存System.Object類型的項目。對象只能按其加入順序從集合中檢索:堆棧是后進先出,而隊列則是先進先出。通常情況下,你在以下場合可以考慮采用以上這些集合:

          • 接收和處理集合內項目時順序比較重要。
          • 你能在處理項目之后丟棄它。
          • 你不需要訪問集合中的任意項目。

          ArrayList

          System.Collections.ArrayList類,僅僅實現 Ilist,最適合描述為一種正常數組和集合的混合類型。ArrayList按照項目被加入集合的順序存儲項目。每個項目都被分配一個索引標識符而且能由關聯它們的索引數字以任何順序被檢索。當新項目加入集合時會擴大ArrayList從而令其相比普通數組更具靈活性。然而,ArrayList負載比傳統數組更大而且沒有實現嚴格的類型化,也就可以接受任何轉換為System.Object的對象(換句話說,對什么東西都來者不拒)。

          SortedList

          System.Collections.SortedList,它實現了IDictionary和ICollection接口,是最基本的排序集合,與Vb6下的Collection對象非常類似。SortedList存儲對象并按照關聯的鍵值對這些存儲對象排序。它們也是同時支持索引數字和鍵對象檢索的唯一內建的.NET集合。

          HashTable

          強有力的System.Collections.HashTable集合實現了IDictionary 和 Icollection,能用來存儲多種類型的對象連同關聯的唯一字符串鍵值。在HashTable集合中的項目按照源自其鍵值的哈希代碼所確定的順序存儲。集合內每個對象的鍵值都必須唯一,而其哈希代碼則不一定唯一。


          什么是哈希代碼?
          哈希代碼實質上就是從一快數據中消除所有冗余部分之后的結果,它主要起到對數據輔助分類或排序的作用。

          當某個項目加入集合時,HashTable即調用鍵值的GetHashCode方法,由于所有的類都是從System.Objec繼承的,所以調用該方法即可確定該類的哈希代碼并且按該代碼排序存儲。你可以強迫使用定制的哈希函數,方法有二,一是重載類的GetHashCode方法,二是向HashTable構造器傳遞實現了System.Collections.IHashcodeProvider接口的對象,在這種情況下,該對象將用于為所有加入集合的鍵值產生哈希代碼。

          從性能的角度看,因為鍵值搜索僅限于具有同樣哈希代碼的鍵值,所以HashTable能夠很快地從集合中檢索任意一個元素,從而減少了必須通過檢查以發現匹配的鍵值的數量。然而,因為插入到集合中的每個對象-鍵值對都必須產生相應的哈希代碼,所以項目插入的代價就有點高了。因此,HashTable主要運用在按照任意鍵值反復檢索大量相對靜態的數據這一場合下。

          ListDictionary 和 HybridDictionary

          ListDictionary 和 HybridDictionary 類歸屬于System.Collections.Specialized。它們都在按照唯一鍵值的原則來組織項目,而且都實現了 IDictionary 和 ICollection 。ListDictionary在內部以鏈表的方式存儲項目,建議用在不會增長超過10個項目的集合中。HybridDictionary采用一個內部鏈表(實際上就是ListDictionary)作為小集合,當集合變得足夠大(超過10個項目)以至于鏈表實現效率降低時就會轉換為HashTable。

          StringCollection 和 StringDictionary

          System.Collections.Specialized.StringCollection 和 System.Collections.Specialized.StringDictionary 都對存儲字符串的集合進行了優化。 StringCollection實現了 IList 和 ICollection 而且實質上就是ArrayList,只不過實現了強烈的類型化僅僅接受字符串而已。StringCollection最理想的應用場合是經常更新或增加的少量數據,而StringDictionary則最適用于不經常增加項目到諸如HashTable之類集合中的大量數據。

          NameValueCollection

          System.Collections.Specialized.NameValueCollection最有趣的地方在于它能包含關聯同一鍵值的多個項目,這正是它與其他內建集合的差別所在。除此以外,它在功能上類似HashTable,按照源自每一項目鍵值的哈希代碼對項目排序從而也具有類同的優缺點。

          存在的問題

          如果說由 .NET 類庫所提供的內建集合也存在問題的話,那多半是它們幾乎都在內部把項目存儲為System.Object.類型。從最大靈活性的角度看那是一個好想法,但同時也給采用這些通用集合的程序員提出了一些問題。首先,只要你把一個新項目加到集合中去,運行時就必須實施類型轉換操作(創建值類型的索引以便可以當作對象引用)。這是一種低效的操作而且在處理大型集合時會產生相當可觀的性能問題。其次,只要你訪問通用集合中的一個項目,該項目都將作為System.Object類型被返回,這就意味著你不得不把它轉換為真實的類型才能對其進行有意義的操作。

          責任編輯:炒飯

          posted @ 2005-12-09 11:32 javaGrowing 閱讀(370) | 評論 (0)編輯 收藏

          數組與其它容器的區別體現在三個方面:效率,類型識別以及可以持有primitives.

          數組是java提供的,是能隨機存儲和訪問reference序列的諸多方法中,最高效的一種。數組是線形序列,所以它可以快速訪問其中的元素,但速度是有代價的,當你創建了一個數組之后它的容量就固定了,而且在其生命周期里不能改變。也許你會提議先創建一個數組,等到快不夠用的時候,再創建一個新的,然后將舊數組里的reference 全部導到新的里面。其實ArrayList 就是這么做的。但是這種靈活性所帶來的開銷,使得ArrayList 的效率比       起數組有了明顯下降。      

          在我們寫程序的時候往往不知道要用多少對象,或者要用一種更復雜方式來存儲對象情況。為此,Java 提供了“容器類(container class)”。其基本類型有List, Set Map。有了這些工具,你就能解決很多問題了。它們還有一些別的特性。比方說Set 所持有的對象,個個都不同,Map則是一個“關聯性數組(associative array)”,它能在兩個對象之間建立聯系。此外,與數組不同,它們還能自動調整大小,所以你可以往里面放任意數量的對象。這樣寫程序的時候,就不用操心要開多大的空間了。

           

          Java2 的容器類要解決“怎樣持有對象”,而它把這個問題分成兩類:

          1. Collection: 通常是一組有一定規律的獨立元素。List 必須按照特定的順序持有這些元素,而Set 則不能保存重復的元素。(bag沒有這個限制,但是Java的容器類庫沒有實現它,因為List 已經提供這種功能了。)

          2. Map: 一組以“鍵——值”(key-value)形式出現的pair。初看上去,它應該是一個pairCollection,但是真這么去做的話,它就會變得很滑稽,所以還是把這個概念獨立列出來為好。退一步說,真的要用到Map 的某個子集的時候,創建一個Collection 也是很方便的。Map可以返回“鍵(key)的”Set,值的Collection,或者pairSet。和數組一樣,Map 不需要什么修改,就能很容易地擴展成多維。你只要直接把Map 的值設成Map 就可以了(然后它的值再是Map,以此類推)。我們先來看看容器的一般特性,然后深入細節,最后再看什么會有這么多版本,以及如何進行選擇。

           

          List 會老老實實地持有你所輸入的所有對象,既不做排序也不做編輯。Set 則每個對象只接受一次,而且還要用它自己的規則對元素進行重新排序(一般情況下,你關心的只是Set 包沒包括某個對象,而不是它到底排在哪里——如果是那樣,你最好還是用List)。而Map 也不接收重復的pair,至于是不是重復,要由key來決定。此外,它也有它自己的內部排序規則,不會受輸入順序影響。如果插入順序是很重要的,那你就只能使用LinkedHashSet LinkedHashMap 了。

          test.bmp

          第一眼看到這張圖的時候,你會覺得很震撼。不過你馬上就會知道,實際上只有三種容器組件——Map,List 和Set,而每種又有兩到三個實現。最常用的幾個容器已經用粗黑線框了起來。看到這里,這張圖就不再那么令人望而生畏了。
          用點號框起來的是interface,用虛線框起來的是abstract 類,實線
          則表示普通的(“實體concrete”)類。點線的箭頭表示類實現了這個interface(或者,abstract 類表示部分實現了這個interface)。實線
          箭頭表示這個類可以制造箭頭所指的那個類的對象。比如,Collection
          能制造Iterator,而List 還能制造ListIterator(也能制造Iterator,因為List 是繼承自Collection 的)。
          與存放對象有關的接口包括Collection,List,Set 和Map。在理想情況下,絕大多數代碼應該只同這些接口打交道,只是在創建容器的時候才要精確地指明它的確切類型。所以你可以這樣創建一個List。
          List x = new LinkedList( );

          當然,你也可以選擇讓x 成為LinkedList(而不是泛型的List),這樣x 就帶上了準確的類型信息interface 的優雅 (同時也是它的本意)就在于,你想修改具體的實現的時候,只要改一下創建的聲明就可以了,就
          像這樣:
          List x = new ArrayList( );
          無需驚動其它代碼(用迭代器也能獲得一些這種泛型性)。這個類系里面有很多以“Abstract”開頭的類,初看起來這可能會讓人有點不明白。實際上它們只是一些部分實現某個接口的辦成品。假如你要編一個你自己的Set,不要從Set 接口開始挨個實現它的方法;相反你最好繼承AbstractSet,這樣就能把編程的工作量壓縮到最低了。但是,實際上容器類庫的功能已經夠強的了,我們要求的事情它幾乎都能做
          到。所以對我們來說,你完全可以忽略以“Abstract”開頭的類。

          List 的功能
          正如你從ArrayList 那里所看到的,List 的基本用法是相當簡單的。雖然絕大多數時候,你只是用add( )加對象,用get( )取對象,用iterator( )獲取這個序列的Iterator,但List 還有一些別的很有用的
          方法。
          實際上有兩種List:擅長對元素進行隨機訪問的,較常用的ArrayList,和更強大的LinkedList。LinkedList 不是為快速的隨機訪問而設計的,但是它卻有一組更加通用的方法。

          List (接口) List 的最重要的特征就是有序;它會確保以一定的順序保存元素。List 在Collection 的基礎上添加了大量方法,使之能在序列中間插入和刪除元素。(只對LinkedList 推薦使用。)List 可以制造ListIterator 對象,你除了能用它在List 的中間插入和刪除元素之外,還能用它沿兩個方向遍歷List。
          ArrayList*一個用數組實現的List。能進行快速的隨機訪問, 但是往列表中間插入和刪除元素的時候比較慢。ListIterator 只能用在反向遍歷ArrayList 的場 合,不要用它來插入和刪除元素,因為相比LinkedList,在ArrayList 里面用ListIterator 的系統開銷比較高。
          LinkedList對順序訪問進行了優化。在List 中間插入和刪除元 素的代價也不高。隨機訪問的速度相對較慢。(用ArrayList 吧。)此外它還有addFirst( ), addLast( ),getFirst( ),getLast( ), removeFirst( )和removeLast( )等方法(這些 方法,接口和基類均未定義),你能把它當成棧(stack),隊列(queue)或雙向隊列(deque)來用。 下面這段程序把各種操作都集中到方法里面:List 都能作的事(basicTest( )),用Iterator 在列表中移動(iterMotion( )),修改 列表的元素(iterManipulation( )),查看List 的操作結果(testVisual( )),以及LinkedList 所獨有的方法。
          Set 的功能
          Set 的接口就是Collection 的,所以不像那兩個List,它沒有額外的
          功能。實際上Set 確確實實就是一個Collection——只不過行為方式不
          同罷了。(這是繼承和多態性的完美運用:表達不同地行為。)Set 會拒絕
          持有多個具有相同值的對象的實例(對象的“值”又是由什么決定的呢?
          這個問題比較復雜,我們以后會講的)。
          Set (接口)加入Set 的每個元素必須是唯一的;否則, Set 是不會把它加進去的。要想加進Set, Object 必須定義equals( ),這樣才能標明對象的唯一性。Set 的接口和Collection 的
          一模一樣。Set 的接口不保證它會用哪種順序來存儲元素。
          HashSet* 為優化查詢速度而設計的Set。要放進HashSet 里面的Object 還得定義hashCode( )。
          TreeSet 是一個有序的Set,其底層是一棵樹。這樣你 就能從Set 里面提取一個有序序列了。
          LinkedHashSet(JDK 1.4) 一個在內部使用鏈表的Set,既有HashSet 的查詢速度,又能保存元素被加進去的順序(插入順序)。用Iterator 遍歷Set 的時候, 它是按插入順序進行訪問的。
          Map 的功能
          ArrayList 能讓你用數字在一個對象序列里面進行選擇,所以從某種意義上講,它是將數字和對象關聯起來。但是,如果你想根據其他條件在一個對象序列里面進行選擇的話,那又該怎么做呢?從概念上講,它看上去像是一個ArrayList,但它不用數字,而是用另一個對象來查找對象!這是一種至關重要的編程技巧。這一概念在Java 中表現為Map。put(Object key, Object value)方法會往Map 里面加一個值,并且把這個值同鍵(你查找時所用的對象)聯系起來。給出鍵之后,get(Object key)就會返回與之相關聯的值。
          你也可以用containsKey( ) 和 containsValue( )測試Map 是否包含有某個鍵或值。
          Java 標準類庫里有好幾種Map:HashMap,TreeMap, LinkedHashMap,WeakHashMap,IdentityHashMap。
          它們都實現了Map 的基本接口,但是在行為方式方面有著明顯的差異。這些差異體現在,效率,持有和表示對象pair 的順序,持有對象的時間長短,以及如何決定鍵的相等性。性能是Map 所要面對的一個大問題。如果你知道get( )是怎么工作的,你就會發覺(比方說)在ArrayList 里面找對象會是相當慢的。而這
          正是HashMap 的強項。它不是慢慢地一個個地找這個鍵,而是用了一種被稱為hash code的特殊值來進行查找的。散列(hash)是一種算法,它會從目標對象當中提取一些信息,然后生成一個表示這個對象的“相對
          獨特”的int。hashCode( )是Object 根類的方法,因此所有Java對象都能生成hash code。HashMap 則利用對象的hashCode( )來進行快速的查找。這樣性能就有了急劇的提高。

          Map (接口)維持鍵-值的關聯(即pairs),這樣就能用鍵來找值了。
          HashMap* 基于hash表的實現。(用它來代替Hashtable。)提供時間恒定的插入與查詢。在構造函數中可以設置 hash表的capacity 和load factor。可以通過構造 函數來調節其性能。
          LinkedHashMap(JDK 1.4) 很像HashMap,但是用Iterator 進行 遍歷的時候,它會按插入順序或最先使用 的順序(least-recently-used (LRU) order)進行訪問。除了用Iterator 外, 其他情況下,只是比HashMap 稍慢一 點。用Iterator 的情況下,由于是使用 鏈表來保存內部順序,因此速度會更快。
          TreeMap 基于紅黑樹數據結構的實現。當你查看鍵 或pair 時,會發現它們是按順序 (根據Comparable 或Comparator,我們過 一會講)排列的。TreeMap 的特點是,你 所得到的是一個有序的Map。TreeMap 是Map 中唯一有subMap( )方法的實 現。這個方法能讓你獲取這個樹中的一部 分。
          WeakHashMap 一個weak key的Map,是為某些特殊問 題而設計的。它能讓Map 釋放其所持有的 對象。如果某個對象除了在Map 當中充當 鍵之外,在其它地方都沒有其reference 的話,那它將被當作垃圾回收。
          IdentityHashMap(JDK 1.4) 一個用==,而不是equals( )來比較鍵 的hash map。不是為我們平常使用而設 計的,是用來解決特殊問題的。 散列是往Map 里存數據的常用算法。有時你會需要知道散列算法的工作 細節,所以我們會稍后再講。
          posted @ 2005-12-09 11:09 javaGrowing 閱讀(2738) | 評論 (1)編輯 收藏

          "^\d+$"  //非負整數(正整數 + 0)

          "^[0-9]*[1-9][0-9]*$"  //正整數

          "^((-\d+)|(0+))$"  //非正整數(負整數 + 0)

          "^-[0-9]*[1-9][0-9]*$"  //負整數

          "^-?\d+$"    //整數

          "^\d+(\.\d+)?$"  //非負浮點數(正浮點數 + 0)

          "^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$"  //正浮點數

          "^((-\d+(\.\d+)?)|(0+(\.0+)?))$"  //非正浮點數(負浮點數 + 0)

          "^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$"  //負浮點數

          "^(-?\d+)(\.\d+)?$"  //浮點數

          "^[A-Za-z]+$"  //由26個英文字母組成的字符串

          "^[A-Z]+$"  //由26個英文字母的大寫組成的字符串

          "^[a-z]+$"  //由26個英文字母的小寫組成的字符串

          "^[A-Za-z0-9]+$"  //由數字和26個英文字母組成的字符串

          "^\w+$"  //由數字、26個英文字母或者下劃線組成的字符串

          "^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$"    //email地址

          "^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$"  //url

          /^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$/ // 年-月-日

          /^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$/ // 月/日/年

          "^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$" //Emil

          "(d+-)?(d{4}-?d{7}|d{3}-?d{8}|^d{7,8})(-d+)?" //電話號碼

          "^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$" //IP地址

          匹配中文字符的正則表達式: [\u4e00-\u9fa5]

          匹配雙字節字符(包括漢字在內):[^\x00-\xff]

          匹配空行的正則表達式:\n[\s| ]*\r

          匹配HTML標記的正則表達式:/<(.*)>.*<\/\1>|<(.*) \/>/

          匹配首尾空格的正則表達式:(^\s*)|(\s*$)

          匹配Email地址的正則表達式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

          匹配網址URL的正則表達式:^[a-zA-z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\S*)?$

          匹配帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$

          匹配國內電話號碼:(\d{3}-|\d{4}-)?(\d{8}|\d{7})?

          匹配騰訊QQ號:^[1-9]*[1-9][0-9]*$

          下表是元字符及其在正則表達式上下文中的行為的一個完整列表:

          \ 將下一個字符標記為一個特殊字符、或一個原義字符、或一個后向引用、或一個八進制轉義符。

          ^ 匹配輸入字符串的開始位置。如果設置了 RegExp 對象的Multiline 屬性,^ 也匹配 ’\n’ 或 ’\r’ 之后的位置。

          $ 匹配輸入字符串的結束位置。如果設置了 RegExp 對象的Multiline 屬性,$ 也匹配 ’\n’ 或 ’\r’ 之前的位置。

          * 匹配前面的子表達式零次或多次。

          + 匹配前面的子表達式一次或多次。+ 等價于 {1,}。

          ? 匹配前面的子表達式零次或一次。? 等價于 {0,1}。

          {n} n 是一個非負整數,匹配確定的n 次。

          {n,} n 是一個非負整數,至少匹配n 次。

          {n,m} m 和 n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。在逗號和兩個數之間不能有空格。

          ? 當該字符緊跟在任何一個其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認的貪婪模式則盡可能多的匹配所搜索的字符串。

          . 匹配除 "\n" 之外的任何單個字符。要匹配包括 ’\n’ 在內的任何字符,請使用象 ’[.\n]’ 的模式。

          (pattern) 匹配pattern 并獲取這一匹配。

          (?:pattern) 匹配pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供以后使用。

          (?=pattern) 正向預查,在任何匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。

          (?!pattern) 負向預查,與(?=pattern)作用相反

          x|y 匹配 x 或 y。

          [xyz] 字符集合。

          [^xyz] 負值字符集合。

          [a-z] 字符范圍,匹配指定范圍內的任意字符。

          [^a-z] 負值字符范圍,匹配任何不在指定范圍內的任意字符。

          \b 匹配一個單詞邊界,也就是指單詞和空格間的位置。

          \B 匹配非單詞邊界。

          \cx 匹配由x指明的控制字符。

          \d 匹配一個數字字符。等價于 [0-9]。

          \D 匹配一個非數字字符。等價于 [^0-9]。

          \f 匹配一個換頁符。等價于 \x0c 和 \cL。

          \n 匹配一個換行符。等價于 \x0a 和 \cJ。

          \r 匹配一個回車符。等價于 \x0d 和 \cM。

          \s 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于[ \f\n\r\t\v]。

          \S 匹配任何非空白字符。等價于 [^ \f\n\r\t\v]。

          \t 匹配一個制表符。等價于 \x09 和 \cI。

          \v 匹配一個垂直制表符。等價于 \x0b 和 \cK。

          \w 匹配包括下劃線的任何單詞字符。等價于’[A-Za-z0-9_]’。

          \W 匹配任何非單詞字符。等價于 ’[^A-Za-z0-9_]’。

          \xn 匹配 n,其中 n 為十六進制轉義值。十六進制轉義值必須為確定的兩個數字長。

          \num 匹配 num,其中num是一個正整數。對所獲取的匹配的引用。

          \n 標識一個八進制轉義值或一個后向引用。如果 \n 之前至少 n 個獲取的子表達式,則 n 為后向引用。否則,如果 n 為八進制數字 (0-7),則 n 為一個八進制轉義值。

          \nm 標識一個八進制轉義值或一個后向引用。如果 \nm 之前至少有is preceded by at least nm 個獲取得子表達式,則 nm 為后向引用。如果 \nm 之前至少有 n 個獲取,則 n 為一個后跟文字 m 的后向引用。如果前面的條件都不滿足,若 n 和 m 均為八進制數字 (0-7),則 \nm 將匹配八進制轉義值 nm。

          \nml 如果 n 為八進制數字 (0-3),且 m 和 l 均為八進制數字 (0-7),則匹配八進制轉義值 nml。

          \un 匹配 n,其中 n 是一個用四個十六進制數字表示的Unicode字符。

          匹配中文字符的正則表達式: [u4e00-u9fa5]

          匹配雙字節字符(包括漢字在內):[^x00-xff]

          應用:計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1)

          String.prototype.len=function(){return this.replace([^x00-xff]/g,"aa").length;}

          匹配空行的正則表達式:n[s| ]*r

          匹配HTML標記的正則表達式:/<(.*)>.*|<(.*) />/

          匹配首尾空格的正則表達式:(^s*)|(s*$)

          應用:javascript中沒有像vbscript那樣的trim函數,我們就可以利用這個表達式來實現,如下:

          String.prototype.trim = function()

          { return this.replace(/(^s*)|(s*$)/g, "");

          } 利用正則表達式分解和轉換IP地址:

          下面是利用正則表達式匹配IP地址,并將IP地址轉換成對應數值的Javascript程序:

          function IP2V(ip)

          { re=/(d+).(d+).(d+).(d+)/g //匹配IP地址的正則表達式 if(re.test(ip)) { return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1 } else { throw new Error("Not a valid IP address!") } }

          不過上面的程序如果不用正則表達式,而直接用split函數來分解可能更簡單,程序如下:

          var ip="10.100.20.168"

          ip=ip.split(".")

          alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))

          匹配Email地址的正則表達式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*

          匹配網址URL的正則表達式:http://([w-]+.)+[w-]+(/[w- ./?%&=]*)?

          利用正則表達式去除字串中重復的字符的算法程序:

          var s="abacabefgeeii" var s1=s.replace(/(.).*1/g,"$1") var re=new RegExp("["+s1+"]","g") var s2=s.replace(re,"") alert(s1+s2) //結果為:abcefgi

          我原來在CSDN上發貼尋求一個表達式來實現去除重復字符的方法,最終沒有找到,這是我能想到的最簡單的實現方法。思路是使用后向引用取出包括重復的字符,再以重復的字符建立第二個表達式,取到不重復的字符,兩者串連。這個方法對于字符順序有要求的字符串可能不適用。

          得用正則表達式從URL地址中提取文件名的javascript程序,如下結果為page1

          s="http://www.9499.net/page1.htm" s=s.replace(/(.*/){0,}([^.]+).*/ig,"$2") alert(s) 利用正則表達式限制網頁表單里的文本框輸入內容:

          用正則表達式限制只能輸入中文:onkeyup="value=value.replace(/[^u4E00-u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^u4E00-u9FA5]/g,''))"

          用 正則表達式限制只能輸入全角字符: onkeyup="value=value.replace(/[^uFF00-uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^uFF00-uFFFF]/g,''))"

          用正則表達式限制只能輸入數字:onkeyup="value=value.replace(/[^d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^d]/g,''))"

          用正則表達式限制只能輸入數字和英文:onkeyup="value=value.replace(/[W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^d]/g,''))"

          posted @ 2005-12-08 13:53 javaGrowing 閱讀(491) | 評論 (0)編輯 收藏

          僅列出標題
          共19頁: First 上一頁 11 12 13 14 15 16 17 18 19 下一頁 
          主站蜘蛛池模板: 漯河市| 霍山县| 临城县| 武定县| 资中县| 平顺县| 新巴尔虎右旗| 广安市| 菏泽市| 灵台县| 临洮县| 肇州县| 色达县| 新竹市| 安国市| 奉节县| 海口市| 格尔木市| 荆州市| 合阳县| 乐都县| 广汉市| 普宁市| 庆云县| 兖州市| 桑植县| 紫金县| 新沂市| 牙克石市| 白沙| 惠州市| 克东县| 芷江| 衡南县| 抚松县| 大关县| 盐山县| 峡江县| 天峨县| 云林县| 扎兰屯市|