<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    精彩的人生

    好好工作,好好生活

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      147 Posts :: 0 Stories :: 250 Comments :: 0 Trackbacks

    #

    java.util 中的集合類包含 Java 中某些最常用的類。 最常用的集合類是 List 和 Map。 List 的具體實現(xiàn)包括 ArrayList 和 Vector,它們是可變大小的列表,比較適合構(gòu)建、存儲和操作任何類型對象的元素列表。 List 適用于按數(shù)值索引訪問元素的情形。

    Map 提供了一個更通用的元素存儲方法。 Map 集合類用于存儲元素對(稱作“鍵”和“值”),其中每個鍵映射到一個值。 從概念上而言,您可以將 List 看作是具有數(shù)值鍵的 Map。 而實際上,除了 List 和 Map 都在定義 java.util 中外,兩者并沒有直接的聯(lián)系。本文將著重介紹核心 Java 發(fā)行套件中附帶的 Map,同時還將介紹如何采用或?qū)崿F(xiàn)更適用于您應(yīng)用程序特定數(shù)據(jù)的專用 Map。

    了解 Map 接口和方法

    Java 核心類中有很多預(yù)定義的 Map 類。 在介紹具體實現(xiàn)之前,我們先介紹一下 Map 接口本身,以便了解所有實現(xiàn)的共同點。 Map 接口定義了四種類型的方法,每個 Map 都包含這些方法。 下面,我們從兩個普通的方法(表 1)開始對這些方法加以介紹。

    表 1: 覆蓋的方法。 我們將這 Object 的這兩個方法覆蓋,以正確比較 Map 對象的等價性。 equals(Object o) 比較指定對象與此 Map 的等價性
    hashCode() 返回此 Map 的哈希碼



    Map 構(gòu)建

    Map 定義了幾個用于插入和刪除元素的變換方法(表 2)。

    表 2: Map 更新方法: 可以更改 Map 內(nèi)容。 clear() 從 Map 中刪除所有映射
    remove(Object key) 從 Map 中刪除鍵和關(guān)聯(lián)的值
    put(Object key, Object value) 將指定值與指定鍵相關(guān)聯(lián)
    clear() 從 Map 中刪除所有映射
    putAll(Map t) 將指定 Map 中的所有映射復(fù)制到此 map



    盡管您可能注意到,縱然假設(shè)忽略構(gòu)建一個需要傳遞給 putAll() 的 Map 的開銷,使用 putAll() 通常也并不比使用大量的 put() 調(diào)用更有效率,但 putAll() 的存在一點也不稀奇。 這是因為,putAll() 除了迭代 put() 所執(zhí)行的將每個鍵值對添加到 Map 的算法以外,還需要迭代所傳遞的 Map 的元素。 但應(yīng)注意,putAll() 在添加所有元素之前可以正確調(diào)整 Map 的大小,因此如果您未親自調(diào)整 Map 的大小(我們將對此進行簡單介紹),則 putAll() 可能比預(yù)期的更有效。

    查看 Map

    迭代 Map 中的元素不存在直接了當?shù)姆椒ā?如果要查詢某個 Map 以了解其哪些元素滿足特定查詢,或如果要迭代其所有元素(無論原因如何),則您首先需要獲取該 Map 的“視圖”。 有三種可能的視圖(參見表 3)

    所有鍵值對 — 參見 entrySet()
    所有鍵 — 參見 keySet()
    所有值 — 參見 values()

    前兩個視圖均返回 Set 對象,第三個視圖返回 Collection 對象。 就這兩種情況而言,問題到這里并沒有結(jié)束,這是因為您無法直接迭代 Collection 對象或 Set 對象。要進行迭代,您必須獲得一個 Iterator 對象。 因此,要迭代 Map 的元素,必須進行比較煩瑣的編碼


    Iterator keyValuePairs = aMap.entrySet().iterator();
    Iterator keys = aMap.keySet().iterator();
    Iterator values = aMap.values().iterator();


    值得注意的是,這些對象(Set、Collection 和 Iterator)實際上是基礎(chǔ) Map 的視圖,而不是包含所有元素的副本。 這使它們的使用效率很高。 另一方面,Collection 或 Set 對象的 toArray() 方法卻創(chuàng)建包含 Map 所有元素的數(shù)組對象,因此除了確實需要使用數(shù)組中元素的情形外,其效率并不高。

    我運行了一個小測試(隨附文件中的 Test1),該測試使用了 HashMap,并使用以下兩種方法對迭代 Map 元素的開銷進行了比較:


    int mapsize = aMap.size();

    Iterator keyValuePairs1 = aMap.entrySet().iterator();
    for (int i = 0; i < mapsize; i++)
    {
    Map.Entry entry = (Map.Entry) keyValuePairs1.next();
    Object key = entry.getKey();
    Object value = entry.getValue();
    ...
    }

    Object[] keyValuePairs2 = aMap.entrySet().toArray();
    for (int i = 0; i < rem; i++) {
    {
    Map.Entry entry = (Map.Entry) keyValuePairs2[i];
    Object key = entry.getKey();


    Object value = entry.getValue();
    ...
    }


    此測試使用了兩種測量方法: 一種是測量迭代元素的時間,另一種測量使用 toArray 調(diào)用創(chuàng)建數(shù)組的其他開銷。 第一種方法(忽略創(chuàng)建數(shù)組所需的時間)表明,使用已從 toArray 調(diào)用中創(chuàng)建的數(shù)組迭代元素的速度要比使用 Iterator 的速度大約快 30%-60%。 但如果將使用 toArray 方法創(chuàng)建數(shù)組的開銷包含在內(nèi),則使用 Iterator 實際上要快 10%-20%。 因此,如果由于某種原因要創(chuàng)建一個集合元素的數(shù)組而非迭代這些元素,則應(yīng)使用該數(shù)組迭代元素。 但如果您不需要此中間數(shù)組,則不要創(chuàng)建它,而是使用 Iterator 迭代元素。

    表 3: 返回視圖的 Map 方法: 使用這些方法返回的對象,您可以遍歷 Map 的元素,還可以刪除 Map 中的元素。 entrySet() 返回 Map 中所包含映射的 Set 視圖。 Set 中的每個元素都是一個 Map.Entry 對象,可以使用 getKey() 和 getValue() 方法(還有一個 setValue() 方法)訪問后者的鍵元素和值元素
    keySet() 返回 Map 中所包含鍵的 Set 視圖。 刪除 Set 中的元素還將刪除 Map 中相應(yīng)的映射(鍵和值)
    values() 返回 map 中所包含值的 Collection 視圖。 刪除 Collection 中的元素還將刪除 Map 中相應(yīng)的映射(鍵和值)



    訪問元素

    表 4 中列出了 Map 訪問方法。Map 通常適合按鍵(而非按值)進行訪問。 Map 定義中沒有規(guī)定這肯定是真的,但通常您可以期望這是真的。 例如,您可以期望 containsKey() 方法與 get() 方法一樣快。 另一方面,containsValue() 方法很可能需要掃描 Map 中的值,因此它的速度可能比較慢。

    表 4: Map 訪問和測試方法: 這些方法檢索有關(guān) Map 內(nèi)容的信息但不更改 Map 內(nèi)容。 get(Object key) 返回與指定鍵關(guān)聯(lián)的值
    containsKey(Object key) 如果 Map 包含指定鍵的映射,則返回 true
    containsValue(Object value) 如果此 Map 將一個或多個鍵映射到指定值,則返回 true
    isEmpty() 如果 Map 不包含鍵-值映射,則返回 true
    size() 返回 Map 中的鍵-值映射的數(shù)目



    對使用 containsKey() 和 containsValue() 遍歷 HashMap 中所有元素所需時間的測試表明,containsValue() 所需的時間要長很多。 實際上要長幾個數(shù)量級! (參見圖 1 和圖 2,以及隨附文件中的 Test2)。 因此,如果 containsValue() 是應(yīng)用程序中的性能問題,它將很快顯現(xiàn)出來,并可以通過監(jiān)測您的應(yīng)用程序輕松地將其識別。 這種情況下,我相信您能夠想出一個有效的替換方法來實現(xiàn) containsValue() 提供的等效功能。 但如果想不出辦法,則一個可行的解決方案是再創(chuàng)建一個 Map,并將第一個 Map 的所有值作為鍵。 這樣,第一個 Map 上的 containsValue() 將成為第二個 Map 上更有效的 containsKey()。


    圖 1: 使用 JDeveloper 創(chuàng)建并運行 Map 測試類




    圖 2: 在 JDeveloper 中使用執(zhí)行監(jiān)測器進行的性能監(jiān)測查出應(yīng)用程序中的瓶頸



    核心 Map

    Java 自帶了各種 Map 類。 這些 Map 類可歸為三種類型:


    通用 Map,用于在應(yīng)用程序中管理映射,通常在 java.util 程序包中實現(xiàn)
    HashMap
    Hashtable
    Properties
    LinkedHashMap
    IdentityHashMap
    TreeMap
    WeakHashMap
    ConcurrentHashMap
    專用 Map,您通常不必親自創(chuàng)建此類 Map,而是通過某些其他類對其進行訪問
    java.util.jar.Attributes
    javax.print.attribute.standard.PrinterStateReasons
    java.security.Provider
    java.awt.RenderingHints
    javax.swing.UIDefaults
    一個用于幫助實現(xiàn)您自己的 Map 類的抽象類
    AbstractMap

    內(nèi)部哈希: 哈希映射技術(shù)

    幾乎所有通用 Map 都使用哈希映射。 這是一種將元素映射到數(shù)組的非常簡單的機制,您應(yīng)了解哈希映射的工作原理,以便充分利用 Map。

    哈希映射結(jié)構(gòu)由一個存儲元素的內(nèi)部數(shù)組組成。 由于內(nèi)部采用數(shù)組存儲,因此必然存在一個用于確定任意鍵訪問數(shù)組的索引機制。 實際上,該機制需要提供一個小于數(shù)組大小的整數(shù)索引值。 該機制稱作哈希函數(shù)。 在 Java 基于哈希的 Map 中,哈希函數(shù)將對象轉(zhuǎn)換為一個適合內(nèi)部數(shù)組的整數(shù)。 您不必為尋找一個易于使用的哈希函數(shù)而大傷腦筋: 每個對象都包含一個返回整數(shù)值的 hashCode() 方法。 要將該值映射到數(shù)組,只需將其轉(zhuǎn)換為一個正值,然后在將該值除以數(shù)組大小后取余數(shù)即可。 以下是一個簡單的、適用于任何對象的 Java 哈希函數(shù)


    int hashvalue = Maths.abs(key.hashCode()) % table.length;


    (% 二進制運算符(稱作模)將左側(cè)的值除以右側(cè)的值,然后返回整數(shù)形式的余數(shù)。)

    實際上,在 1.4 版發(fā)布之前,這就是各種基于哈希的 Map 類所使用的哈希函數(shù)。 但如果您查看一下代碼,您將看到


    int hashvalue = (key.hashCode() & 0x7FFFFFFF) % table.length;


    它實際上是使用更快機制獲取正值的同一函數(shù)。 在 1.4 版中,HashMap 類實現(xiàn)使用一個不同且更復(fù)雜的哈希函數(shù),該函數(shù)基于 Doug Lea 的 util.concurrent 程序包(稍后我將更詳細地再次介紹 Doug Lea 的類)。


    圖 3: 哈希工作原理



    該圖介紹了哈希映射的基本原理,但我們還沒有對其進行詳細介紹。 我們的哈希函數(shù)將任意對象映射到一個數(shù)組位置,但如果兩個不同的鍵映射到相同的位置,情況將會如何? 這是一種必然發(fā)生的情況。 在哈希映射的術(shù)語中,這稱作沖突。 Map 處理這些沖突的方法是在索引位置處插入一個鏈接列表,并簡單地將元素添加到此鏈接列表。 因此,一個基于哈希的 Map 的基本 put() 方法可能如下所示


    public Object put(Object key, Object value) {
    //我們的內(nèi)部數(shù)組是一個 Entry 對象數(shù)組
    //Entry[] table;

    //獲取哈希碼,并映射到一個索引
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % table.length;

    //循環(huán)遍歷位于 table[index] 處的鏈接列表,以查明
    //我們是否擁有此鍵項 — 如果擁有,則覆蓋它
    for (Entry e = table[index] ; e != null ; e = e.next) {
    //必須檢查鍵是否相等,原因是不同的鍵對象
    //可能擁有相同的哈希
    if ((e.hash == hash) && e.key.equals(key)) {
    //這是相同鍵,覆蓋該值
    //并從該方法返回 old 值
    Object old = e.value;
    e.value = value;
    return old;
    }
    }

    //仍然在此處,因此它是一個新鍵,只需添加一個新 Entry
    //Entry 對象包含 key 對象、 value 對象、一個整型的 hash、
    //和一個指向列表中的下一個 Entry 的 next Entry

    //創(chuàng)建一個指向上一個列表開頭的新 Entry,
    //并將此新 Entry 插入表中
    Entry e = new Entry(hash, key, value, table[index]);
    table[index] = e;

    return null;
    }



    如果看一下各種基于哈希的 Map 的源代碼,您將發(fā)現(xiàn)這基本上就是它們的工作原理。 此外,還有一些需要進一步考慮的事項,如處理空鍵和值以及調(diào)整內(nèi)部數(shù)組。 此處定義的 put() 方法還包含相應(yīng) get() 的算法,這是因為插入包括搜索映射索引處的項以查明該鍵是否已經(jīng)存在。 (即 get() 方法與 put() 方法具有相同的算法,但 get() 不包含插入和覆蓋代碼。) 使用鏈接列表并不是解決沖突的唯一方法,某些哈希映射使用另一種“開放式尋址”方案,本文對其不予介紹。

    優(yōu)化 Hasmap

    如果哈希映射的內(nèi)部數(shù)組只包含一個元素,則所有項將映射到此數(shù)組位置,從而構(gòu)成一個較長的鏈接列表。 由于我們的更新和訪問使用了對鏈接列表的線性搜索,而這要比 Map 中的每個數(shù)組索引只包含一個對象的情形要慢得多,因此這樣做的效率很低。 訪問或更新鏈接列表的時間與列表的大小線性相關(guān),而使用哈希函數(shù)訪問或更新數(shù)組中的單個元素則與數(shù)組大小無關(guān) — 就漸進性質(zhì)(Big-O 表示法)而言,前者為 O(n),而后者為 O(1)。 因此,使用一個較大的數(shù)組而不是讓太多的項聚集在太少的數(shù)組位置中是有意義的。

    調(diào)整 Map 實現(xiàn)的大小

    在哈希術(shù)語中,內(nèi)部數(shù)組中的每個位置稱作“存儲桶”(bucket),而可用的存儲桶數(shù)(即內(nèi)部數(shù)組的大小)稱作容量 (capacity)。 為使 Map 對象有效地處理任意數(shù)目的項,Map 實現(xiàn)可以調(diào)整自身的大小。 但調(diào)整大小的開銷很大。 調(diào)整大小需要將所有元素重新插入到新數(shù)組中,這是因為不同的數(shù)組大小意味著對象現(xiàn)在映射到不同的索引值。 先前沖突的鍵可能不再沖突,而先前不沖突的其他鍵現(xiàn)在可能沖突。 這顯然表明,如果將 Map 調(diào)整得足夠大,則可以減少甚至不再需要重新調(diào)整大小,這很有可能顯著提高速度。

    使用 1.4.2 JVM 運行一個簡單的測試,即用大量的項(數(shù)目超過一百萬)填充 HashMap。 表 5 顯示了結(jié)果,并將所有時間標準化為已預(yù)先設(shè)置大小的服務(wù)器模式(關(guān)聯(lián)文件中的 Test3)。 對于已預(yù)先設(shè)置大小的 JVM,客戶端和服務(wù)器模式 JVM 運行時間幾乎相同(在放棄 JIT 編譯階段后)。 但使用 Map 的默認大小將引發(fā)多次調(diào)整大小操作,開銷很大,在服務(wù)器模式下要多用 50% 的時間,而在客戶端模式下幾乎要多用兩倍的時間!

    表 5: 填充已預(yù)先設(shè)置大小的 HashMap 與填充默認大小的 HashMap 所需時間的比較 客戶端模式 服務(wù)器模式
    預(yù)先設(shè)置的大小 100% 100%
    默認大小 294% 157%



    使用負載因子

    為確定何時調(diào)整大小,而不是對每個存儲桶中的鏈接列表的深度進行記數(shù),基于哈希的 Map 使用一個額外參數(shù)并粗略計算存儲桶的密度。 Map 在調(diào)整大小之前,使用名為“負載因子”的參數(shù)指示 Map 將承擔的“負載”量,即它的負載程度。 負載因子、項數(shù)(Map 大小)與容量之間的關(guān)系簡單明了:


    如果(負載因子)x(容量)>(Map 大小),則調(diào)整 Map 大小

    例如,如果默認負載因子為 0.75,默認容量為 11,則 11 x 0.75 = 8.25,該值向下取整為 8 個元素。 因此,如果將第 8 個項添加到此 Map,則該 Map 將自身的大小調(diào)整為一個更大的值。 相反,要計算避免調(diào)整大小所需的初始容量,用將要添加的項數(shù)除以負載因子,并向上取整,例如,


    對于負載因子為 0.75 的 100 個項,應(yīng)將容量設(shè)置為 100/0.75 = 133.33,并將結(jié)果向上取整為 134(或取整為 135 以使用奇數(shù))

    奇數(shù)個存儲桶使 map 能夠通過減少沖突數(shù)來提高執(zhí)行效率。 雖然我所做的測試(關(guān)聯(lián)文件中的Test4)并未表明質(zhì)數(shù)可以始終獲得更好的效率,但理想情形是容量取質(zhì)數(shù)。 1.4 版后的某些 Map(如 HashMap 和 LinkedHashMap,而非 Hashtable 或 IdentityHashMap)使用需要 2 的冪容量的哈希函數(shù),但下一個最高 2 的冪容量由這些 Map 計算,因此您不必親自計算。

    負載因子本身是空間和時間之間的調(diào)整折衷。 較小的負載因子將占用更多的空間,但將降低沖突的可能性,從而將加快訪問和更新的速度。 使用大于 0.75 的負載因子可能是不明智的,而使用大于 1.0 的負載因子肯定是不明知的,這是因為這必定會引發(fā)一次沖突。 使用小于 0.50 的負載因子好處并不大,但只要您有效地調(diào)整 Map 的大小,應(yīng)不會對小負載因子造成性能開銷,而只會造成內(nèi)存開銷。 但較小的負載因子將意味著如果您未預(yù)先調(diào)整 Map 的大小,則導(dǎo)致更頻繁的調(diào)整大小,從而降低性能,因此在調(diào)整負載因子時一定要注意這個問題。

    選擇適當?shù)?Map

    應(yīng)使用哪種 Map? 它是否需要同步? 要獲得應(yīng)用程序的最佳性能,這可能是所面臨的兩個最重要的問題。 當使用通用 Map 時,調(diào)整 Map 大小和選擇負載因子涵蓋了 Map 調(diào)整選項。

    以下是一個用于獲得最佳 Map 性能的簡單方法

    將您的所有 Map 變量聲明為 Map,而不是任何具體實現(xiàn),即不要聲明為 HashMap 或 Hashtable,或任何其他 Map 類實現(xiàn)。


    Map criticalMap = new HashMap(); //好

    HashMap criticalMap = new HashMap(); //差


    這使您能夠只更改一行代碼即可非常輕松地替換任何特定的 Map 實例。

    下載 Doug Lea 的 util.concurrent 程序包 (http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html)。 將 ConcurrentHashMap 用作默認 Map。 當移植到 1.5 版時,將 java.util.concurrent.ConcurrentHashMap 用作您的默認 Map。 不要將 ConcurrentHashMap 包裝在同步的包裝器中,即使它將用于多個線程。 使用默認大小和負載因子。
    監(jiān)測您的應(yīng)用程序。 如果發(fā)現(xiàn)某個 Map 造成瓶頸,則分析造成瓶頸的原因,并部分或全部更改該 Map 的以下內(nèi)容: Map 類;Map 大小;負載因子;關(guān)鍵對象 equals() 方法實現(xiàn)。 專用的 Map 的基本上都需要特殊用途的定制 Map 實現(xiàn),否則通用 Map 將實現(xiàn)您所需的性能目標。

    Map 選擇

    也許您曾期望更復(fù)雜的考量,而這實際上是否顯得太容易? 好的,讓我們慢慢來。 首先,您應(yīng)使用哪種 Map? 答案很簡單: 不要為您的設(shè)計選擇任何特定的 Map,除非實際的設(shè)計需要指定一個特殊類型的 Map。 設(shè)計時通常不需要選擇具體的 Map 實現(xiàn)。 您可能知道自己需要一個 Map,但不知道使用哪種。 而這恰恰就是使用 Map 接口的意義所在。 直到需要時再選擇 Map 實現(xiàn) — 如果隨處使用“Map”聲明的變量,則更改應(yīng)用程序中任何特殊 Map 的 Map 實現(xiàn)只需要更改一行,這是一種開銷很少的調(diào)整選擇。 是否要使用默認的 Map 實現(xiàn)? 我很快將談到這個問題。

    同步 Map

    同步與否有何差別? (對于同步,您既可以使用同步的 Map,也可以使用 Collections.synchronizedMap() 將未同步的 Map 轉(zhuǎn)換為同步的 Map。 后者使用“同步的包裝器”)這是一個異常復(fù)雜的選擇,完全取決于您如何根據(jù)多線程并發(fā)訪問和更新使用 Map,同時還需要進行維護方面的考慮。 例如,如果您開始時未并發(fā)更新特定 Map,但它后來更改為并發(fā)更新,情況將如何? 在這種情況下,很容易在開始時使用一個未同步的 Map,并在后來向應(yīng)用程序中添加并發(fā)更新線程時忘記將此未同步的 Map 更改為同步的 Map。 這將使您的應(yīng)用程序容易崩潰(一種要確定和跟蹤的最糟糕的錯誤)。 但如果默認為同步,則將因隨之而來的可怕性能而序列化執(zhí)行多線程應(yīng)用程序。 看起來,我們需要某種決策樹來幫助我們正確選擇。

    Doug Lea 是紐約州立大學奧斯威戈分校計算機科學系的教授。 他創(chuàng)建了一組公共領(lǐng)域的程序包(統(tǒng)稱 util.concurrent),該程序包包含許多可以簡化高性能并行編程的實用程序類。 這些類中包含兩個 Map,即 ConcurrentReaderHashMap 和 ConcurrentHashMap。 這些 Map 實現(xiàn)是線程安全的,并且不需要對并發(fā)訪問或更新進行同步,同時還適用于大多數(shù)需要 Map 的情況。 它們還遠比同步的 Map(如 Hashtable)或使用同步的包裝器更具伸縮性,并且與 HashMap 相比,它們對性能的破壞很小。 util.concurrent 程序包構(gòu)成了 JSR166 的基礎(chǔ);JSR166 已經(jīng)開發(fā)了一個包含在 Java 1.5 版中的并發(fā)實用程序,而 Java 1.5 版將把這些 Map 包含在一個新的 java.util.concurrent 程序包中。

    所有這一切意味著您不需要一個決策樹來決定是使用同步的 Map 還是使用非同步的 Map, 而只需使用 ConcurrentHashMap。 當然,在某些情況下,使用 ConcurrentHashMap 并不合適。 但這些情況很少見,并且應(yīng)具體情況具體處理。 這就是監(jiān)測的用途。


    結(jié)束語

    通過 Oracle JDeveloper 可以非常輕松地創(chuàng)建一個用于比較各種 Map 性能的測試類。 更重要的是,集成良好的監(jiān)測器可以在開發(fā)過程中快速、輕松地識別性能瓶頸 - 集成到 IDE 中的監(jiān)測器通常被較頻繁地使用,以便幫助構(gòu)建一個成功的工程。 現(xiàn)在,您已經(jīng)擁有了一個監(jiān)測器并了解了有關(guān)通用 Map 及其性能的基礎(chǔ)知識,可以開始運行您自己的測試,以查明您的應(yīng)用程序是否因 Map 而存在瓶頸以及在何處需要更改所使用的 Map。

    以上內(nèi)容介紹了通用 Map 及其性能的基礎(chǔ)知識。 當然,有關(guān)特定 Map 實現(xiàn)以及如何根據(jù)不同的需求使用它們還存在更多復(fù)雜和值得關(guān)注的事項,這些將在本文第 2 部分中介紹。


    --------------------------------------------------------------------------------
    Jack Shirazi 是 O''Reilly 的“Java 性能調(diào)整”的作者,以及受歡迎的 JavaPerformanceTuning.com 網(wǎng)站(提供 Java 性能信息的全球知名站點)的總監(jiān)。 Jack 在 Java 性能領(lǐng)域提供咨詢并著書立說。 他還監(jiān)督 JavaPerformanceTuning.com 提供的信息,其中包括每年大約發(fā)布 1000 條性能技巧以及許多有關(guān)性能工具、討論組等內(nèi)容的文章。 Jack 早年還曾發(fā)布有關(guān)蛋白質(zhì)結(jié)構(gòu)預(yù)測以及黑洞熱力學方面的文章,而且在其空閑時還對某些 Perl5 核心模塊作出了貢獻。


    摘自http://www.5ivb.net/Info/121/Info36849/
    posted @ 2006-04-03 11:09 hopeshared 閱讀(691) | 評論 (0)編輯 收藏

    如果想要取得系統(tǒng)的時間,可以使用System.currentTimeMillis()方法,例如:


    • DateDemo.java

    public class DateDemo {
    ????public static void main(String[]
    args) {
    ????????System.out.println(System.currentTimeMillis());
    ????}
    }



    執(zhí)行結(jié)果會顯示從1970年1月1日開始到取得系統(tǒng)時間為止所經(jīng)過的毫秒數(shù),例如1115346430703這個數(shù)字,但這樣的數(shù)字沒有人確切了解它的意 義是什么,您可以使用Date類別來讓這個數(shù)字變的更有意義一些,例如:


    • DateDemo.java

    import java.util.Date;

    public class DateDemo {
    ????public static void main(String[]
    args) {
    ????????Date date = new Date();
    ????????
    ????????System.out.println(date.toString());
    ????????System.out.println(date.getTime());
    ????}
    }



    執(zhí)行的結(jié)果如下:

    ??

    Fri May 06 10:31:13 GMT+08:00 2005
    ??1115346673531

    ??

    當您生成Date對象時,實際上它會使用System.currentTimeMillis()來取得系統(tǒng)時間,而您使用
    toString()方法時,會將取得的1970年1月1日至今的毫秒數(shù)轉(zhuǎn)為dow mon dd hh:mm:ss zzz yyyy的格式,分別是:「星期 月 日 時:分:秒 公元」;使用Date的getTime()方法則可以取得毫秒數(shù)。

    如果您想要對日期時間作格式設(shè)定,則可以使用DateFormat來作格式化,先來看看它的子類SimpleDateFormat如何使用:
    • DateDemo.java

    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;

    public class DateDemo {
    ????public static void main(String[]
    args) {
    ????????Date date = new Date();

    ????????DateFormat dateFormat =
    ????????????new
    SimpleDateFormat("EE-MM-dd-yyyy");
    ????????
    ????????System.out.println(dateFormat.format(date));
    ????}
    }



    執(zhí)行結(jié)果:

    ??

    星期五-05-06-2005

    ??

    DateFormat會依計算機上的區(qū)域設(shè)定顯示時間格式,EE表示星期,MM表示月份、dd表示日期,而yyyy是公元,每個字符的設(shè)定都各有其意義,您
    可以參考 SimpleDateFormat 的API說明了解每個字符設(shè)定的意義。

    您也可以直接從DateFormat指定格式生成DateFormat的實例,例如:
    • DateDemo.java

    import java.text.DateFormat;
    import java.util.Date;

    public class DateDemo {
    ????public static void main(String[]
    args) {
    ????????Date date = new Date();

    ????????DateFormat shortFormat =
    ????????????DateFormat.getDateTimeInstance(
    ????????????????DateFormat.SHORT,
    DateFormat.SHORT);

    ????????DateFormat mediumFormat =
    ????????????DateFormat.getDateTimeInstance(
    ????????????????DateFormat.MEDIUM,
    DateFormat.MEDIUM);

    ????????DateFormat longFormat =
    ????????????DateFormat.getDateTimeInstance(
    ????????????????DateFormat.LONG, DateFormat.LONG);

    ????????DateFormat fullFormat =
    ????????????DateFormat.getDateTimeInstance(
    ????????????????DateFormat.FULL,
    DateFormat.FULL);

    ????????System.out.println(shortFormat.format(date));
    ????????System.out.println(mediumFormat.format(date));
    ????????System.out.println(longFormat.format(date));
    ????????System.out.println(fullFormat.format(date));
    ????}
    }



    在使用getDateTimeInstance()取得DateFormat實例時,可以指定的參數(shù)是日期格式與時間格式,以上所指定的格式依訊息詳細度 區(qū)分,執(zhí)行結(jié)果如下:

    2005/5/6 上午 10:45
    2005/5/6 上午 10:45:25
    2005年5月6日 上午10時45分25秒
    2005年5月6日 星期五 上午10時45分25秒 GMT+08:00??


    您也可以使用getDateInstance()取得DateFormat實 例,并同時指定日期的區(qū)域顯示方式,例如:


    • DateDemo.java????


    import java.text.DateFormat;
    import java.util.Date;
    import java.util.Locale;

    public class DateDemo {
    ????public static void main(String[]
    args) {
    ????????Date date = new Date();

    ????????Locale locale = new
    Locale("en", "US");
    ????????DateFormat shortFormat =
    ????????????DateFormat.getDateInstance(
    ????????????????DateFormat.SHORT,
    locale);

    ????????DateFormat mediumFormat =
    ????????????DateFormat.getDateInstance(
    ????????????????DateFormat.MEDIUM,
    locale);

    ????????DateFormat longFormat =
    ????????????DateFormat.getDateInstance(
    ????????????????DateFormat.LONG, locale);

    ????????DateFormat fullFormat =
    ????????????DateFormat.getDateInstance(
    ????????????????DateFormat.FULL, locale);

    ????????System.out.println(shortFormat.format(date));
    ????????System.out.println(mediumFormat.format(date));
    ????????System.out.println(longFormat.format(date));
    ????????System.out.println(fullFormat.format(date));
    ????}
    }



    這邊指定了美國的時間顯示方式,執(zhí)行結(jié)果如下:

    ??

    5/6/05
    ??May 6, 2005
    ??May 6, 2005
    ??Friday, May 6, 2005


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

    1. 怎樣計算兩個時間之間的間隔?

    間隔=Date1.getTime()-Date2.getTime();得出來的是毫秒數(shù).
    除1000是秒,再除60是分,再除60是小時..............................

    記住java標準庫中所有時間類都以此為基礎(chǔ)轉(zhuǎn)化的,只是他寫好了一些
    轉(zhuǎn)化的方法給你用而已.但都離不開這個毫秒數(shù)為基礎(chǔ).

    2. t=Calendar.getInstance();m=t.get(t.MONTH)+1;這里為什么要加一?

    在java語言里,date的month的取值范圍是:0~11,與人們的自然表達上相差1。

    3. 系統(tǒng)時間與當前日期的區(qū)別?

    系統(tǒng)時間確切的說應(yīng)該是
    System.currentTimeMillis();
    new Date()是當前日期,雖然它getTime();和System.currentTimeMillis();
    一樣,但System.currentTimeMillis();

    4. 如何計算兩個日期的天數(shù)差值?

    long beginTime = beginDate.getTime();
    long endTime2 = endDate.getTime();
    long betweenDays = (long)((endTime - beginTime) / (1000 * 60 * 60 *24) + 0.5);

    5. 如何比較日期時間大小?

    第一種方法:
    use Calendar object to compare
    java.util.Calendar class can be used to compare date. In order to do this,
    you guy should parse that string into int year, month, day and construct a
    Calendar object, and then do comparison.

    Below is a sample

    StringTokenizer token = new StringTokenizer(your string,"-");
    int year = Integer.parseInt(token.nextToken());
    int month = Integer.parseInt(token.nextToken());
    int day = Integer.parseInt(token.nextToken());
    Calendar date = Calendar.getInstance();
    date.set(year,month,day);
    Calendar today = Calendar.getInstacne();
    if(date.after(today)){
    //......
    }
    第二種方法
    Date nowDate=new Date();//當前時間\r
    long nowTime=nowDate.getTime;
    long lastTime=userTime.longValue();//以前的時間\r
    long time=nowTime-lastTime;//時間相減比較。
    if(time>(long)60000)//1分鐘{}

    另外可用以下參考
    用時間戳,Date.getTime()可以把當前時間改成時間戳,
    用CompareTo();
    用before(),after(),equals();

    6. 格式化日期的問題\r

    目的:
    第一次求日期
    java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd");
    String riqi=formatter.format(currentTime_1);
    第二次求時間\r
    java.text.DateFormat format1 = new java.text.SimpleDateFormat("hhmmss");
    java.util.Date currentTime_2 = new java.util.Date();
    String shijian=format1.format(currentTime_2);
    得到的結(jié)果是
    2002-02-19和115324(11點53分24秒)

    實現(xiàn):
    java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd-H-mm-ss");
    java.util.Date currentTime_1 = new java.util.Date();
    String str_date = formatter.format(currentTime_1);
    StringTokenizer token = new StringTokenizer(str_date,"-");
    String year = token.nextToken();
    String month= token.nextToken();
    String day = token.nextToken();
    String hh = token.nextToken();
    String mm = token.nextToken();
    String ss = token.nextToken();
    String riqi=year+"年\\"+month+"月"+day+"日"+" "+hh+"點\\"+mm+"分"+ss+"秒\\";
    String newdir=year+month+day;
    String wenjian = hh+mm+ss;

    7. 怎么得到一個月的天數(shù)?

    java.util.Calendar date = java.util.Calendar.getInstance();
    System.out.println(date.getActualMaximum(date.DAY_OF_MONTH));


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

    ?
    取得指定月份的第一天與取得指定月份的最后一天??
    ?????? /**??
    ???????? *??取得指定月份的第一天??
    ???????? *??
    ???????? *??@param??strdate??String??
    ???????? *??@return??String??
    ???????? */??
    ?????? public??String??getMonthBegin(String??strdate)??
    ?????? {??
    ?????????????? java.util.Date??date??=??parseFormatDate(strdate);??
    ?????????????? return??formatDateByFormat(date,"yyyy-MM")??+??"-01";??
    ?????? }??

    ?????? /**??
    ???????? *??取得指定月份的最后一天??
    ???????? *??
    ???????? *??@param??strdate??String??
    ???????? *??@return??String??
    ???????? */??
    ?????? public??String??getMonthEnd(String??strdate)??
    ?????? {??
    ?????????????? java.util.Date??date??=??parseFormatDate(getMonthBegin(strdate));??
    ?????????????? Calendar??calendar??=??Calendar.getInstance();??
    ?????????????? calendar.setTime(date);??
    ?????????????? calendar.add(Calendar.MONTH,1);??
    ?????????????? calendar.add(Calendar.DAY_OF_YEAR,??-1);??
    ?????????????? return??formatDate(calendar.getTime());??
    ?????? }??

    ?????? /**??
    ???????? *??常用的格式化日期??
    ???????? *??
    ???????? *??@param??date??Date??
    ???????? *??@return??String??
    ???????? */??
    ?????? public??String??formatDate(java.util.Date??date)??
    ?????? {??
    ?????????????? return??formatDateByFormat(date,"yyyy-MM-dd");??
    ?????? }??

    ?????? /**??
    ???????? *??以指定的格式來格式化日期??
    ???????? *??
    ???????? *??@param??date??Date??
    ???????? *??@param??format??String??
    ???????? *??@return??String??
    ???????? */??
    ?????? public??String??formatDateByFormat(java.util.Date??date,String??format)??
    ?????? {??
    ?????????????? String??result??=??"";??
    ?????????????? if(date??!=??null)??
    ?????????????? {??
    ?????????????????????? try??
    ?????????????????????? {??
    ?????????????????????????????? SimpleDateFormat??sdf??=??new??SimpleDateFormat(format);??
    ?????????????????????????????? result??=??sdf.format(date);??
    ?????????????????????? }??
    ?????????????????????? catch(Exception??ex)??
    ?????????????????????? {??
    ?????????????????????????????? LOGGER.info("date:"??+??date);??
    ?????????????????????????????? ex.printStackTrace();??
    ?????????????????????? }??
    ?????????????? }??
    ?????????????? return??result;??
    ?????? }??
    ---------------------------------------------------------------??

    package??com.app.util;??

    /**??
    *??日期操作??
    *????
    *??@author??xxx??
    *??@version??2.0??jdk1.4.0??tomcat5.1.0??*??Updated??Date:2005/03/10??
    */??
    public??class??DateUtil??{??
    ?????????? /**??
    ???????????? *??格式化日期??
    ???????????? *????
    ???????????? *??@param??dateStr??
    ???????????? *????????????????????????字符型日期??
    ???????????? *??@param??format??
    ???????????? *????????????????????????格式??
    ???????????? *??@return??返回日期??
    ???????????? */??
    ?????????? public??static??java.util.Date??parseDate(String??dateStr,??String??format)??{??
    ?????????????????????? java.util.Date??date??=??null;??
    ?????????????????????? try??{??
    ?????????????????????????????????? java.text.DateFormat??df??=??new??java.text.SimpleDateFormat(format);??
    ?????????????????????????????????? String??dt=Normal.parse(dateStr).replaceAll(??
    ?????????????????????????????????????????????????????????? "-",??"/");??
    ?????????????????????????????????? if((!dt.equals(""))&&(dt.length()<format.length())){??
    ?????????????????????????????????????????????? dt+=format.substring(dt.length()).replaceAll("[YyMmDdHhSs]","0");??
    ?????????????????????????????????? }??
    ?????????????????????????????????? date??=??(java.util.Date)??df.parse(dt);??
    ?????????????????????? }??catch??(Exception??e)??{??
    ?????????????????????? }??
    ?????????????????????? return??date;??
    ?????????? }??

    ?????????? public??static??java.util.Date??parseDate(String??dateStr)??{??
    ?????????????????????? return??parseDate(dateStr,??"yyyy/MM/dd");??
    ?????????? }??

    ?????????? public??static??java.util.Date??parseDate(java.sql.Date??date)??{??
    ?????????????????????? return??date;??
    ?????????? }??
    ????????????
    ?????????? public??static??java.sql.Date??parseSqlDate(java.util.Date??date)??{??
    ?????????????????????? if??(date??!=??null)??
    ?????????????????????????????????? return??new??java.sql.Date(date.getTime());??
    ?????????????????????? else??
    ?????????????????????????????????? return??null;??
    ?????????? }??

    ?????????? public??static??java.sql.Date??parseSqlDate(String??dateStr,??String??format)??{??
    ?????????????????????? java.util.Date??date??=??parseDate(dateStr,??format);??
    ?????????????????????? return??parseSqlDate(date);??
    ?????????? }??

    ?????????? public??static??java.sql.Date??parseSqlDate(String??dateStr)??{??
    ?????????????????????? return??parseSqlDate(dateStr,??"yyyy/MM/dd");??
    ?????????? }??

    ????????????
    ?????????? public??static??java.sql.Timestamp??parseTimestamp(String??dateStr,??
    ?????????????????????????????????? String??format)??{??
    ?????????????????????? java.util.Date??date??=??parseDate(dateStr,??format);??
    ?????????????????????? if??(date??!=??null)??{??
    ?????????????????????????????????? long??t??=??date.getTime();??
    ?????????????????????????????????? return??new??java.sql.Timestamp(t);??
    ?????????????????????? }??else??
    ?????????????????????????????????? return??null;??
    ?????????? }??

    ?????????? public??static??java.sql.Timestamp??parseTimestamp(String??dateStr)??{??
    ?????????????????????? return??parseTimestamp(dateStr,??"yyyy/MM/dd??HH:mm:ss");??
    ?????????? }??

    ?????????? /**??
    ???????????? *??格式化輸出日期??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@param??format??
    ???????????? *????????????????????????格式??
    ???????????? *??@return??返回字符型日期??
    ???????????? */??
    ?????????? public??static??String??format(java.util.Date??date,??String??format)??{??
    ?????????????????????? String??result??=??"";??
    ?????????????????????? try??{??
    ?????????????????????????????????? if??(date??!=??null)??{??
    ?????????????????????????????????????????????? java.text.DateFormat??df??=??new??java.text.SimpleDateFormat(format);??
    ?????????????????????????????????????????????? result??=??df.format(date);??
    ?????????????????????????????????? }??
    ?????????????????????? }??catch??(Exception??e)??{??
    ?????????????????????? }??
    ?????????????????????? return??result;??
    ?????????? }??

    ?????????? public??static??String??format(java.util.Date??date)??{??
    ?????????????????????? return??format(date,??"yyyy/MM/dd");??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回年份??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回年份??
    ???????????? */??
    ?????????? public??static??int??getYear(java.util.Date??date)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTime(date);??
    ?????????????????????? return??c.get(java.util.Calendar.YEAR);??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回月份??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回月份??
    ???????????? */??
    ?????????? public??static??int??getMonth(java.util.Date??date)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTime(date);??
    ?????????????????????? return??c.get(java.util.Calendar.MONTH)??+??1;??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回日份??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回日份??
    ???????????? */??
    ?????????? public??static??int??getDay(java.util.Date??date)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTime(date);??
    ?????????????????????? return??c.get(java.util.Calendar.DAY_OF_MONTH);??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回小時??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回小時??
    ???????????? */??
    ?????????? public??static??int??getHour(java.util.Date??date)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTime(date);??
    ?????????????????????? return??c.get(java.util.Calendar.HOUR_OF_DAY);??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回分鐘??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回分鐘??
    ???????????? */??
    ?????????? public??static??int??getMinute(java.util.Date??date)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTime(date);??
    ?????????????????????? return??c.get(java.util.Calendar.MINUTE);??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回秒鐘??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回秒鐘??
    ???????????? */??
    ?????????? public??static??int??getSecond(java.util.Date??date)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTime(date);??
    ?????????????????????? return??c.get(java.util.Calendar.SECOND);??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回毫秒??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回毫秒??
    ???????????? */??
    ?????????? public??static??long??getMillis(java.util.Date??date)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTime(date);??
    ?????????????????????? return??c.getTimeInMillis();??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回字符型日期??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回字符型日期??
    ???????????? */??
    ?????????? public??static??String??getDate(java.util.Date??date)??{??
    ?????????????????????? return??format(date,??"yyyy/MM/dd");??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回字符型時間??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回字符型時間??
    ???????????? */??
    ?????????? public??static??String??getTime(java.util.Date??date)??{??
    ?????????????????????? return??format(date,??"HH:mm:ss");??
    ?????????? }??

    ?????????? /**??
    ???????????? *??返回字符型日期時間??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回字符型日期時間??
    ???????????? */??
    ?????????? public??static??String??getDateTime(java.util.Date??date)??{??
    ?????????????????????? return??format(date,??"yyyy/MM/dd??HH:mm:ss");??
    ?????????? }??

    ?????????? /**??
    ???????????? *??日期相加??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@param??day??
    ???????????? *????????????????????????天數(shù)??
    ???????????? *??@return??返回相加后的日期??
    ???????????? */??
    ?????????? public??static??java.util.Date??addDate(java.util.Date??date,??int??day)??{??
    ?????????????????????? java.util.Calendar??c??=??java.util.Calendar.getInstance();??
    ?????????????????????? c.setTimeInMillis(getMillis(date)??+??((long)??day)??*??24??*??3600??*??1000);??
    ?????????????????????? return??c.getTime();??
    ?????????? }??

    ?????????? /**??
    ???????????? *??日期相減??
    ???????????? *????
    ???????????? *??@param??date??
    ???????????? *????????????????????????日期??
    ???????????? *??@param??date1??
    ???????????? *????????????????????????日期??
    ???????????? *??@return??返回相減后的日期??
    ???????????? */??
    ?????????? public??static??int??diffDate(java.util.Date??date,??java.util.Date??date1)??{??
    ?????????????????????? return??(int)??((getMillis(date)??-??getMillis(date1))??/??(24??*??3600??*??1000));??
    ?????????? }??????????????
    }??
    ------------------------------------------------------------------------------------------------------------------

    來個簡單點的,也許有點用??

    Calendar??now??=??Calendar.getInstance();??
    int??year??=??now.get(Calendar.YEAR);??
    int??date??=??now.get(Calendar.DAY_OF_MONTH);??
    int??month??=??now.get(Calendar.MONTH)??+??1;??
    int??hour??=??now.get(Calendar.HOUR);??
    int??min??=??now.get(Calendar.MINUTE);??
    int??sec??=??now.get(Calendar.SECOND);??



    轉(zhuǎn)自http://www.513pc.net/bbs/dispbbs.asp?boardid=4&id=239&star=1&page=1

    posted @ 2006-04-03 10:56 hopeshared 閱讀(2461) | 評論 (1)編輯 收藏

    kXML is a small XML pull parser, specially designed for constrained environments such as Applets, Personal Java or MIDP devices.

    最小的版本只有11k,比那些龐大的xml解析起確實小好多。當你對xml解析不需要很嚴格時可以使用它。

    下面是使用kxml的一段示例代碼:
    import org.xmlpull.v1.*;
    
    import java.util.*;
    import java.io.*;
    import java.net.*;
    
    /** 
     * A simple example illustrationg some differences of the XmlPull API 
     * and SAX. For the corresponding SAX based implementation, please refer to 
     * http://www.cafeconleche.org/slides/sd2001east/xmlandjava/81.html ff. */publicclassWeblogs {
    
        static List listChannels()
            throws IOException, XmlPullParserException {
            return listChannels("http://static.userland.com/weblogMonitor/logs.xml");
        }
    
        static List listChannels(String uri)
            throws IOException, XmlPullParserException {
    
            Vector result = new Vector();
    
            InputStream is = new URL(uri).openStream();
            XmlPullParser parser =
                XmlPullParserFactory.newInstance().newPullParser();
    
            parser.setInput(is, null);
    
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, "", "weblogs");
    
            while (parser.nextTag() == XmlPullParser.START_TAG) {
                String url = readSingle(parser);
                if (url != null)
                    result.addElement(url);
            }
            parser.require(XmlPullParser.END_TAG, "", "weblogs");
    
            parser.next();
            parser.require(XmlPullParser.END_DOCUMENT, null, null);
    
    		is.close ();
    		parser.setInput (null);
    
            return result;
        }
    
        publicstatic String readSingle(XmlPullParser parser)
            throws IOException, XmlPullParserException {
    
            String url = null;
            parser.require(XmlPullParser.START_TAG, "", "log");
    
            while (parser.nextTag() == XmlPullParser.START_TAG) {
                String name = parser.getName();
                String content = parser.nextText();
                if (name.equals("url"))
                    url = content;
                parser.require(XmlPullParser.END_TAG, "", name);
            }
            parser.require(XmlPullParser.END_TAG, "", "log");
            return url;
        }
    
        publicstaticvoid main(String[] args)
            throws IOException, XmlPullParserException {
    
            List urls =
                args.length > 0
                    ? listChannels(args[0])
                    : listChannels();
    
            for (Iterator i = urls.iterator(); i.hasNext();)
                System.out.println(i.next());
        }
    }
    



    摘自http://www.21tx.com/dev/2004/11/27/11901.html
    posted @ 2006-04-03 10:34 hopeshared 閱讀(683) | 評論 (0)編輯 收藏

    在本系列的第一篇文章中,我研究了一些用 Java 編寫的主要的 XML 文檔模型的性能。但是,在開始選擇這種類型的技術(shù)時,性能只是問題的一部分。使用方便至少是同樣重要的,并且它已是一個主要理由,來支持使用 Java 特定的模型,而不是與語言無關(guān)的 DOM 。

    為切實了解哪個模型真正的作用,您需要知道它們在可用性程度上是如何排名的。本文中,我將嘗試進行這個工作,從樣本代碼開始,來演示如何在每個模型中編碼公共類型的操作。并對結(jié)果進行總結(jié)來結(jié)束本文,而且提出了促使一種表示比另一種更容易使用的一些其它因素。

    請參閱以前的文章(請參閱參考資料或本文“內(nèi)容”下的便捷鏈接)來獲取這個對比中使用的各個模型的背景資料,包含實際的版本號。還可以參閱“參考資料”一節(jié)中關(guān)于源代碼下載、到模型主頁的鏈接以及其它相關(guān)信息。

    代碼對比
    在對不同文檔表示中用法技術(shù)的這些對比中,我將顯示如何在每種模型中實現(xiàn)三種基本操作:

    根據(jù)輸入流構(gòu)建文檔
    遍歷元素和內(nèi)容,并做一些更改:
    從文本內(nèi)容中除去前導(dǎo)和尾隨的空白。
    如果結(jié)果文本內(nèi)容為空,就刪除它。
    否則,將它包裝到父元素的名稱空間中一個名為“text”的新元素中。
    將已修改的文檔寫入輸出流

    這些示例的代碼是以我在上篇文章中使用的基準程序為基礎(chǔ)的,并進行了一些簡化。基準程序的焦點是為了顯示每個模型的最佳性能;對于本文,我將嘗試顯示在每種模型中實現(xiàn)操作的最簡便方法。

    我已經(jīng)將每個模型的示例結(jié)構(gòu)化為兩個獨立的代碼段。第一段是讀取文檔、調(diào)用修改代碼和編寫已修改文檔的代碼。第二段是真正遍歷文檔表示和執(zhí)行修改的遞歸方法。為避免分散注意力,我已在代碼中忽略了異常處理。

    您可以從本頁底部參考資料一節(jié)鏈接到下載頁,以獲取所有樣本的完整代碼。樣本的下載版本包括一個測試驅(qū)動程序,還有一些添加的代碼用于通過計算元素、刪除和添加的個數(shù)來檢查不同模型的操作。

    即使您不想使用 DOM 實現(xiàn),但還是值得瀏覽下面對 DOM 用法的描述。因為 DOM 示例是第一個示例,所以與后面的模型相比,我用它來探究有關(guān)該示例的一些問題和結(jié)構(gòu)的更詳細信息。瀏覽這些內(nèi)容可以補充您想知道的一些細節(jié),如果直接閱讀其它模型之一,那么將錯過這些細節(jié)。

    DOM
    DOM 規(guī)范涵蓋了文檔表示的所有類型的操作,但是它沒有涉及例如對文檔的語法分析和生成文本輸出這樣的問題。包括在性能測試中的兩種 DOM 實現(xiàn),Xerces 和 Crimson,對這些操作使用不同的技術(shù)。清單 1 顯示了 Xerces 的頂級代碼的一種形式。

    清單 1. Xerces DOM 頂級代碼
    1 // parse the document from input stream ("in")
    2 DOMParser parser = new DOMParser();
    3 parser.setFeature("http://xml.org/sax/features/namespaces", true);
    4 parser.parse(new InputSource(in));
    5 Document doc = parser.getDocument();

    6 // recursively walk and modify document
    7 modifyElement(doc.getDocumentElement());

    8 // write the document to output stream ("out")
    9 OutputFormat format = new OutputFormat(doc);
    10 XMLSerializer serializer = new XMLSerializer(out, format);
    11 serializer.serialize(doc.getDocumentElement());



    正如我在注釋中指出的,清單 1 中的第一塊代碼(第 1-5 行)處理對輸入流的語法分析,以構(gòu)建文檔表示。Xerces 定義了 DOMParser 類,以便從 Xerces 語法分析器的輸出構(gòu)建文檔。InputSource 類是 SAX 規(guī)范的一部分,它能適應(yīng)供 SAX 分析器使用的幾種輸入形式的任何之一。通過單一調(diào)用進行實際的語法分析和文檔構(gòu)造,如果成功完成了這一操作,那么應(yīng)用程序就可以檢索并使用已構(gòu)造的 Document。

    第二個代碼塊(第 6-7 行)只是將文檔的根元素傳遞給我馬上要談到的遞歸修改方法。這些代碼與本文中所有文檔模型的代碼在本質(zhì)上是相同的,所以在剩余的示例中我將跳過它,不再做任何討論。

    第三個代碼塊(第 8-11 行)處理將文檔作為文本寫入輸出流。這里,OutputFormat 類包裝文檔,并為格式化生成的文本提供了多種選項。XMLSerializer 類處理輸出文本的實際生成。

    Xerces 的 modify 方法只使用標準 DOM 接口,所以它還與任何其它 DOM 實現(xiàn)兼容。清單 2 顯示了代碼。

    清單 2. DOM Modify 方法
    1 protected void modifyElement(Element element) {

    2 // loop through child nodes
    3 Node child;
    4 Node next = (Node)element.getFirstChild();
    5 while ((child = next) != null) {

    6 // set next before we change anything
    7 next = child.getNextSibling();

    8 // handle child by node type
    9 if (child.getNodeType() == Node.TEXT_NODE) {

    10 // trim whitespace from content text
    11 String trimmed = child.getNodeValue().trim();
    12 if (trimmed.length() == 0) {

    13 // delete child if nothing but whitespace
    14 element.removeChild(child);

    15 } else {

    16 // create a "text" element matching parent namespace
    17 Document doc = element.getOwnerDocument();
    18 String prefix = element.getPrefix();
    19 String name = (prefix == null) ? "text" : (prefix + ":text");
    20 Element text =
    21 doc.createElementNS(element.getNamespaceURI(), name);

    22 // wrap the trimmed content with new element
    23 text.appendChild(doc.createTextNode(trimmed));
    24 element.replaceChild(text, child);

    25 }
    26 } else if (child.getNodeType() == Node.ELEMENT_NODE) {

    27 // handle child elements with recursive call
    28 modifyElement((Element)child);

    29 }
    30 }
    31 }



    清單 2 中顯示的方法所使用的基本方法與所有文檔表示的方法相同。 通過一個元素調(diào)用它,它就依次遍歷那個元素的子元素。如果找到文本內(nèi)容子元素,要么刪除文本(如果它只是由空格組成的),要么通過與包含元素相同的名稱空間中名為“text”的新元素來包裝文本(如果有非空格的字符)。如果找到一個子元素,那么這個方法就使用這個子元素,遞歸地調(diào)用它本身。

    對于 DOM 實現(xiàn),我使用一對引用:child 和 next 來跟蹤子元素排序列表中我所處的位置。在對當前子節(jié)點進行任何其它處理之前,先裝入下個子節(jié)點的引用(第 7 行)。這樣做使得我能夠刪除或替代當前的子節(jié)點,而不丟失我在列表中的蹤跡。

    當我創(chuàng)建一個新元素來包裝非空白的文本內(nèi)容(第 16-24 行)時,DOM 接口開始有點雜亂。用來創(chuàng)建元素的方法與文檔關(guān)聯(lián)并成為一個整體,所以我需要在所有者文檔中檢索當前我正在處理的元素(第 17 行)。我想將這個新元素放置在與現(xiàn)有的父元素相同的名稱空間中,并且在 DOM 中,這意味著我需要構(gòu)造元素的限定名稱。根據(jù)是否有名稱空間的前綴,這個操作會有所不同(第 18-19 行)。利用新元素的限定名稱,以及現(xiàn)有元素中的名稱空間 URI,我就能創(chuàng)建新元素(第 20-21 行)。

    一旦創(chuàng)建了新元素,我只要創(chuàng)建和添加文本節(jié)點來包裝內(nèi)容 String,然后用新創(chuàng)建的元素來替代原始文本節(jié)點(第 22-24 行)。

    清單 3. Crimson DOM 頂級代碼
    1 // parse the document from input stream
    2 System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
    3 "org.apache.crimson.jaxp.DocumentBuilderFactoryImpl");
    4 DocumentBuilderFactory dbf = DocumentBuilderFactoryImpl.newInstance();
    5 dbf.setNamespaceAware(true);
    6 DocumentBuilder builder = dbf.newDocumentBuilder();
    7 Document doc = builder.parse(in);

    8 // recursively walk and modify document
    9 modifyElement(doc.getDocumentElement());

    10 // write the document to output stream
    11 ((XmlDocument)doc).write(out);



    清單 3 中的 Crimson DOM 示例代碼使用了用于語法分析的 JAXP 接口。JAXP 為語法分析和轉(zhuǎn)換 XML 文檔提供了一個標準化的接口。本示例中的語法分析代碼還可以用于 Xerces(對文檔構(gòu)建器類名稱的特性設(shè)置有適當?shù)母模﹣硖娲^早給定的 Xerces 特定的示例代碼。

    在本示例中,我首先在第 2 行到第 3 行中設(shè)置系統(tǒng)特性來選擇要構(gòu)造的 DOM 表示的構(gòu)建器工廠類(JAXP 僅直接支持構(gòu)建 DOM 表示,不支持構(gòu)建本文中討論的任何其它表示)。僅當想選擇一個要由 JAXP 使用的特定 DOM 時,才需要這一步;否則,它使用缺省實現(xiàn)。出于完整性起見,我在代碼中包含了設(shè)置這個特性,但是更普遍的是將它設(shè)置成一個 JVM 命令行參數(shù)。

    接著我在第 4 行到第 6 行中創(chuàng)建構(gòu)建器工廠的實例,對使用那個工廠實例構(gòu)造的構(gòu)建器啟用名稱空間支持,并從構(gòu)建器工廠創(chuàng)建文檔構(gòu)建器。最后(第 7 行),我使用文檔構(gòu)建器來對輸入流進行語法分析并構(gòu)造文檔表示。

    為了寫出文檔,我使用 Crimson 中內(nèi)部定義的基本方法。不保證在 Crimson 未來版本中支持這個方法,但是使用 JAXP 轉(zhuǎn)換代碼來將文檔作為文本輸出的替代方法需要諸如 Xalan 那樣的 XSL 處理器的。那超出了本文的范圍,但是要獲取詳細信息,可以查閱 Sun 中的 JAXP 教程。

    JDOM
    使用 JDOM 的頂級代碼比使用 DOM 實現(xiàn)的代碼稍微簡單一點。為構(gòu)建文檔表示(第 1-3 行),我使用帶有由參數(shù)值禁止驗證的 SAXBuilder。通過使用提供的 XMLOutputter 類,將已修改的文檔寫入輸出流同樣簡單(第 6-8 行)。

    清單 4. JDOM 頂級代碼
    1 // parse the document from input stream
    2 SAXBuilder builder = new SAXBuilder(false);
    3 Document doc = builder.build(in);

    4 // recursively walk and modify document
    5 modifyElement(doc.getRootElement());

    6 // write the document to output stream
    7 XMLOutputter outer = new XMLOutputter();
    8 outer.output(doc, out);



    清單 5 中 JDOM 的 modify 方法也比 DOM 的同一方法簡單。我獲取包含元素所有內(nèi)容的列表并掃描了這張列表,檢查文本(象 String 對象那樣的內(nèi)容)和元素。這張列表是“活的”,所以我能直接對它進行更改,而不必調(diào)用父元素上的方法。

    清單 5. JDOM modify 方法
    1 protected void modifyElement(Element element) {

    2 // loop through child nodes
    3 List children = element.getContent();
    4 for (int i = 0; i < children.size(); i++) {

    5 // handle child by node type
    6 Object child = children.get(i);
    7 if (child instanceof String) {

    8 // trim whitespace from content text
    9 String trimmed = child.toString().trim();
    10 if (trimmed.length() == 0) {

    11 // delete child if only whitespace (adjusting index)
    12 children.remove(i--);

    13 } else {

    14 // wrap the trimmed content with new element
    15 Element text = new Element("text", element.getNamespace());
    16 text.setText(trimmed);
    17 children.set(i, text);

    18 }
    19 } else if (child instanceof Element) {

    20 // handle child elements with recursive call
    21 modifyElement((Element)child);

    22 }
    23 }
    24 }



    創(chuàng)建新元素的技術(shù)(第 14-17 行)非常簡單,而且與 DOM 版本不同,它不需要訪問父文檔。

    dom4j
    dom4j 的頂級代碼比 JDOM 的稍微復(fù)雜些,但是它們的代碼行非常類似。這里的主要區(qū)別是我保存了用來構(gòu)建 dom4j 文檔表示的 DocumentFactory(第 5 行),并在輸出已修改的文檔文本之后刷新了 writer(第 10 行)。

    清單 6. dom4j 的頂級代碼
    1 // parse the document from input stream
    2 SAXReader reader = new SAXReader(false);
    3 Document doc = reader.read(in);

    4 // recursively walk and modify document
    5 m_factory = reader.getDocumentFactory();
    6 modifyElement(doc.getRootElement());

    7 // write the document to output stream
    8 XMLWriter writer = new XMLWriter(out);
    9 writer.write(doc);
    10 writer.flush();



    正如您在清單 6 中看到的,dom4j 使用一個工廠方法來構(gòu)造文檔表示(從語法分析構(gòu)建)中包含的對象。根據(jù)接口來定義每個組件對象,所以實現(xiàn)其中一個接口的任何類型的對象都能包含在表示中(與 JDOM 相反,它使用具體類:這些類在某些情況中可以劃分子類和被繼承,但是在文檔表示中使用的任何類都需要以原始 JDOM 類為基礎(chǔ))。通過使用不同工廠進行 dom4j 文檔構(gòu)建,您能獲取不同系列的組件中構(gòu)造的文檔。

    在樣本代碼(第 5 行)中,我檢索了用于構(gòu)建文檔的(缺省)文檔工廠,并將它存儲在一個實例變量(m_factory)中以供 modify 方法使用。并不嚴格需要這一步 — 可以在一個文檔中同時使用來自不同工廠的組件,或者可以繞過工廠而直接創(chuàng)建組件的實例 — 但在該例中,我只想創(chuàng)建與在文檔其余部分中使用的同一類型的組件,并且使用相同的工廠來確保完成這個步驟。

    清單 7. dom4j modify 方法
    1 protected void modifyElement(Element element) {

    2 // loop through child nodes
    3 List children = element.content();
    4 for (int i = 0; i < children.size(); i++) {

    5 // handle child by node type
    6 Node child = (Node)children.get(i);
    7 if (child.getNodeType() == Node.TEXT_NODE) {

    8 // trim whitespace from content text
    9 String trimmed = child.getText().trim();
    10 if (trimmed.length() == 0) {

    11 // delete child if only whitespace (adjusting index)
    12 children.remove(i--);

    13 } else {

    14 // wrap the trimmed content with new element
    15 Element text = m_factory.createElement
    16 (QName.get("text", element.getNamespace()));
    17 text.addText(trimmed);
    18 children.set(i, text);

    19 }
    20 } else if (child.getNodeType() == Node.ELEMENT_NODE) {

    21 // handle child elements with recursive call
    22 modifyElement((Element)child);

    23 }
    24 }
    25 }



    清單 7 中 dom4j modify 方法與 JDOM 中使用的方法非常類似。不通過使用 instanceof 運算符來檢查內(nèi)容項的類型,我可以通過 Node 接口方法 getNodeType 來獲取類型代碼(也可以使用 instanceof,但類型代碼方法看起來更清晰)。通過使用 QName 對象來表示元素名稱和通過調(diào)用已保存的工廠的方法來構(gòu)建元素可以區(qū)別新元素的創(chuàng)建技術(shù)(第 15-16 行)。

    Electric XML
    清單 8 中 Electric XML(EXML)的頂級代碼是任何這些示例中最簡單的一個,通過單一方法調(diào)用就可以讀取和編寫文檔。

    清單 8. EXML 頂級代碼
    1 // parse the document from input stream
    2 Document doc = new Document(in);

    3 // recursively walk and modify document
    4 modifyElement(doc.getRoot());

    5 // write the document to output stream
    6 doc.write(out);



    清單 9 中 EXML modify 方法盡管與 JDOM 一樣,需要使用 instanceof 檢查,但它與 DOM 方法最相似。在 EXML 中,無法創(chuàng)建一個帶名稱空間限定的名稱的元素,所以取而代之,我創(chuàng)建新元素,然后設(shè)置其名稱來達到相同的效果。

    清單 9. EXML modify 方法
    1 protected void modifyElement(Element element) {

    2 // loop through child nodes
    3 Child child;
    4 Child next = element.getChildren().first();
    5 while ((child = next) != null) {

    6 // set next before we change anything
    7 next = child.getNextSibling();

    8 // handle child by node type
    9 if (child instanceof Text) {

    10 // trim whitespace from content text
    11 String trimmed = ((Text)child).getString().trim();
    12 if (trimmed.length() == 0) {

    13 // delete child if only whitespace
    14 child.remove();

    15 } else {

    16 // wrap the trimmed content with new element
    17 Element text = new Element();
    18 text.addText(trimmed);
    19 child.replaceWith(text);
    20 text.setName(element.getPrefix(), "text");

    21 }
    22 } else if (child instanceof Element) {

    23 // handle child elements with recursive call
    24 modifyElement((Element)child);

    25 }
    26 }
    27 }



    XPP
    XPP 的頂級代碼(在清單 10 中)是所有示例中最長的一個,與其它模型相比,它需要相當多的設(shè)置。

    清單 10. XPP 頂級代碼
    1 // parse the document from input stream
    2 m_parserFactory = XmlPullParserFactory.newInstance();
    3 m_parserFactory.setNamespaceAware(true);
    4 XmlPullParser parser = m_parserFactory.newPullParser();
    5 parser.setInput(new BufferedReader(new InputStreamReader(in)));
    6 parser.next();
    7 XmlNode doc = m_parserFactory.newNode();
    8 parser.readNode(doc);

    9 // recursively walk and modify document
    10 modifyElement(doc);

    11 // write the document to output stream
    12 XmlRecorder recorder = m_parserFactory.newRecorder();
    13 Writer writer = new OutputStreamWriter(out);
    14 recorder.setOutput(writer);
    15 recorder.writeNode(doc);
    16 writer.close();



    因為使用 JAXP 接口,所以我必須首先創(chuàng)建分析器工廠的實例并在創(chuàng)建分析器實例之前啟用名稱空間處理(第 2-4 行)。一旦獲取了分析器實例,我就能將輸入設(shè)置到分析器中,并真正構(gòu)建文檔表示(第 5-8 行),但是這涉及比其它模型更多的步驟。

    輸出處理(第 11-16 行)也涉及比其它模型更多的步驟,主要因為 XPP 需要 Writer 而不是直接將 Stream 作為輸出目標接受。

    清單 11 中 XPP modify 方法盡管需要更多代碼來創(chuàng)建新元素(第 13-21 行),但它與 JDOM 方法最類似。名稱空間處理在這里有點麻煩。我首先必須創(chuàng)建元素的限定名稱(第 15-16 行),然后創(chuàng)建元素,最后在稍后設(shè)置名稱和名稱空間 URI(第 18-21 行)。

    清單 11. XPP modify 方法
    1 protected void modifyElement(XmlNode element) throws Exception {

    2 // loop through child nodes
    3 for (int i = 0; i < element.getChildrenCount(); i++) {

    4 // handle child by node type
    5 Object child = element.getChildAt(i);
    6 if (child instanceof String) {

    7 // trim whitespace from content text
    8 String trimmed = child.toString().trim();
    9 if (trimmed.length() == 0) {

    10 // delete child if only whitespace (adjusting index)
    11 element.removeChildAt(i--);

    12 } else {

    13 // construct qualified name for wrapper element
    15 String prefix = element.getPrefix();
    16 String name = (prefix == null) ? "text" : (prefix + ":text");

    17 // wrap the trimmed content with new element
    18 XmlNode text = m_parserFactory.newNode();
    19 text.appendChild(trimmed);
    20 element.replaceChildAt(i, text);
    21 text.modifyTag(element.getNamespaceUri(), "text", name);

    22 }
    23 } else if (child instanceof XmlNode) {

    24 // handle child elements with recursive call
    25 modifyElement((XmlNode)child);

    26 }
    27 }
    28 }



    結(jié)束語
    DOM、dom4j 和 Electric XML 都得到這些幾乎同樣易于使用的代碼樣本,其中 EXML 可能最簡單,而 dom4j 受一些小條件限制而較困難。DOM 提供了與語言無關(guān)的非常實在的好處,但是如果你只使用 Java 代碼,那么通過與 Java 特定的模型相比較,它看上去有點麻煩。我認為這表明 Java 特定的模型通常成功地實現(xiàn)簡化 Java 代碼中的 XML 文檔處理這個目標。

    超越基礎(chǔ):真實世界可用性
    代碼樣本顯示 JDOM 和 EXML 為基本文檔操作(使用元素、屬性和文本)提供了簡單和清晰的接口。根據(jù)我的經(jīng)驗,它們的方法并不能很好地完成處理整個文檔表示的編程任務(wù)。要完成這些類型的任務(wù),DOM 和 dom4j 使用的組件方法 — 其中從屬性到名稱空間的所有文檔組件實現(xiàn)一些公共接口 — 工作得更好。
    相關(guān)的例子是最近我為 JDOM 和 dom4j 實現(xiàn)的 XML 流型(XML Streaming (XMLS) )編碼。這個代碼遍歷整個文檔并編碼每個組件。JDOM 實現(xiàn)比 dom4j 實現(xiàn)復(fù)雜得多,主要是因為 JDOM 使用一些沒有公共接口的獨特類來表示每個組件。

    因為 JDOM 缺少公共接口,所以即使處理 Document 對象的代碼與處理 Element 對象的代碼都有一些諸如子組件那樣相同類型的組件,但是它們必須有所不同。還需要特殊方法來檢索與其它類型的子組件相對的 Namespace 組件。甚至當處理被認為是內(nèi)容的子組件類型時,您需要在組件類型上使用多個帶 instanceof 檢查的 if 語句,而不是使用一條更清晰更快速的 switch 語句。

    具有諷刺意味的可能是 JDOM 的最初目標之一是利用 Java Collection 類,這些類本身在很大程度上以接口為基礎(chǔ)。庫中接口的使用增加了許多靈活性,而這是以增加了一些復(fù)雜性為代價的,并且這對于為重用而設(shè)計的代碼來說,通常是一個很好的折衷。這可能還主要歸功于 dom4j,它達到一個成熟并且穩(wěn)定的狀態(tài),比 JDOM 要快得多。

    盡管如此,對于使用多種語言的開發(fā)人員來說,DOM 仍是一個非常好的選擇。DOM 實現(xiàn)廣泛應(yīng)用于多種編程語言。它還是許多其它與 XML 相關(guān)的標準的基礎(chǔ),所以即使您使用 Java 特定的模型,也還有一個您逐步熟悉 DOM 所需要的好機會。因為它正式獲得 W3C 推薦(與基于非標準的 Java 模型相對),所以在某些類型的項目中可能也需要它。

    就使用方便這一范疇而言,在 JDOM、dom4j 和 Electric XML 這三個主要競爭者中,dom4j 與其它兩個的區(qū)別在于它使用帶有多個繼承層的基于接口的方法。這會使得遵循 API JavaDocs 更為困難些。例如,您正在尋找的一個方法(例如 content(),在我們 dom4j 的 modify 方法示例的第 3 行中使用的)可能是 Element 擴展的 Branch 接口的一部分,而不是 Element 接口本身的一部分。盡管如此,這種基于接口的設(shè)計添加了許多靈活性(請參閱側(cè)欄超越基礎(chǔ):真實世界可用性)。考慮到 dom4j 的性能、穩(wěn)定性和特性設(shè)置的優(yōu)點,您應(yīng)把它當作多數(shù)項目中的一個有力的候選者。

    在任一 Java 特定的文檔模型之中,JDOM 可能擁有最廣泛的用戶基礎(chǔ),并且它的確是使用起來最簡單的模型之一。盡管如此,作為項目開發(fā)的一個選擇,它還是必須容忍 API 的不固定性和從一個版本到下一個版本的更新,在性能對比中它也表現(xiàn)得很糟糕。基于當前實現(xiàn),我愿為著手新項目的人們推薦 dom4j,而不是 JDOM。

    除了 XPP 以外,EXML 比其它任何模型占用的資源都要少得多,并且考慮到 EXML 易于使用的優(yōu)點,您應(yīng)肯定會認為它適用于 jar 文件大小很重要的應(yīng)用程序。但是,EXML 的 XML 支持的局限性和受限的許可證,以及在較大文件上所表現(xiàn)出的相對拙劣的性能,不得不在許多應(yīng)用程序中放棄使用它。

    XPP 在語法分析和編寫文本文檔時需要更多步驟,并且在處理名稱空間時也需要更多步驟。如果 XPP 打算添加一些便利的方法來處理其中一些常見情況,那么在對比中它可能會更勝一籌。正如它現(xiàn)在所表現(xiàn)的,上篇文章中性能方面的領(lǐng)先者卻成了本文中的可用性方面的失敗者。盡管如此,因為 XPP 性能方面的優(yōu)勢,所以對于需要較小的 jar 文件大小的應(yīng)用程序還是值得將它作為 EXML 的替代方法。

    下一次...
    到目前為止在我寫的兩篇文章中,涉及到用 Java 編寫的 XML 文檔模型的性能和可用性。在本系列的后兩篇文章中,我將討論用 Java 技術(shù)進行 XML 數(shù)據(jù)綁定的方法。這些方法與文檔模型的方法有許多相似處,但是它們更進一步將 XML 文檔映射到實際應(yīng)用程序數(shù)據(jù)結(jié)構(gòu)中。我們將看到這一操作在使用的簡便性和提高性能方面是如何做得如此好的。

    回到 developerWorks,檢查 Java 代碼的 XML 數(shù)據(jù)綁定的實質(zhì)。同時,您可以通過下面鏈接的論壇,給出您對本文的評論和問題。

    參考資料

    單擊本文頂部或底部的討論,參與本文的論壇。
    如果您需要背景資料,嘗試 developerWorks 的 XML Java 編程 教程、理解 SAX 教程和 理解 DOM 教程。
    從下載頁面下載本文中使用的測試程序和文檔模型庫。
    查找有關(guān) Java APIs for XML Processing (JAXP) 或者閱讀 JAXP Tutorial。
    獲取作者有關(guān) XML Streaming 的著作的詳細信息,它作為程序間傳送 XML 文檔的 Java 序列化的另一種選擇。
    回顧作者以前的文章:XML in Java: Document models, part 1。
    根據(jù) Tony Darugar 的團隊對幾個大型 XML 項目的分析,參考他對 Effective DOM with Java 的建議。
    Java 的 XML 文檔模型:
    Xerces Java
    Crimson
    JDOM
    dom4j
    Electric XML
    XML Pull Parser (XPP)



    原文:http://www.daima.com.cn/Info/127/Info37907/
    posted @ 2006-04-03 10:30 hopeshared 閱讀(548) | 評論 (0)編輯 收藏

    我找到的兩種方法,希望大家補充

    第一種:利用Action
    IWorkbenchWindow window = getViewSite().getWorkbenchWindow();
    IWorkbenchAction max = ActionFactory.MAXIMIZE.create(window);
    max.run();


    這段代碼要放在何適的位置上才會起到合適的作用。

    第二種:利用Zoom
    在ApplicationWorkbenchWindowAdvisor#postWindowOpen中做到
    public void postWindowOpen() {
    ??? ?IWorkbenchWindow window = Plugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
    ??? ?IViewPart part=null;
    ?????try {
    ?????????part = window.getActivePage().showView(View.ID);
    ?????} catch (PartInitException e) {
    ?????????e.printStackTrace();
    ?????}
    ??
    ?????if(part!=null){
    ????????window.getActivePage().activate(part);?
    ????????window.getActivePage().bringToTop(part);
    ??
    ????????WorkbenchPage realPage = (WorkbenchPage) window.getActivePage();

    ??????? IWorkbenchPartReference partRef = window.getActivePage().getActivePartReference();

    ??????? if (partRef != null) {
    ??????????? ((WorkbenchPage) window.getActivePage()).toggleZoom(partRef);
    ??????? }else{
    ??????? ?System.out.println("partRef is null!");
    ??????? }
    ????}
    }

    posted @ 2006-03-27 17:10 hopeshared 閱讀(1754) | 評論 (1)編輯 收藏

    僅列出標題
    共30頁: First 上一頁 14 15 16 17 18 19 20 21 22 下一頁 Last 
    主站蜘蛛池模板: 国产无遮挡无码视频免费软件 | 大胆亚洲人体视频| 99热在线免费观看| jizz免费一区二区三区| 亚洲欧美综合精品成人导航| 亚洲视屏在线观看| 亚洲中文字幕无码专区 | 亚洲精品无码成人片久久不卡| 亚洲色欲色欲综合网站| 在线精品亚洲一区二区三区| 国产一卡二卡≡卡四卡免费乱码| 很黄很色很刺激的视频免费| 中文字幕在线免费观看| 免费91麻豆精品国产自产在线观看| h视频免费高清在线观看| 亚洲欧美日韩一区二区三区在线| 亚洲电影在线免费观看| 久久亚洲日韩精品一区二区三区| 国产亚洲av片在线观看16女人| 亚洲精品人成无码中文毛片| 全部免费毛片在线| 国产区卡一卡二卡三乱码免费| 在线播放免费播放av片| 久久亚洲国产成人亚| 中文字幕第一页亚洲| 91成年人免费视频| 最近中文字幕免费完整| 16女性下面扒开无遮挡免费| 2022久久国产精品免费热麻豆| 久久A级毛片免费观看| 日韩插啊免费视频在线观看| 99久久免费精品高清特色大片| 99精品免费观看| 亚洲一区免费视频| 免费成人激情视频| a毛片基地免费全部视频| 成年人网站在线免费观看| 免费无遮挡无码视频网站| 国产成人3p视频免费观看| 免费人成激情视频| 中文字幕不卡亚洲 |