如鵬網(wǎng) 大學(xué)生計算機(jī)學(xué)習(xí)社區(qū)

          CowNew開源團(tuán)隊(duì)

          http://www.cownew.com 郵件請聯(lián)系 about521 at 163.com

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            363 隨筆 :: 2 文章 :: 808 評論 :: 0 Trackbacks

          類型轉(zhuǎn)化

          Java是一種強(qiáng)類型語言,每個實(shí)例都必須有指定的類型。實(shí)際上,Java類型有兩種聲明類型運(yùn)行時類型 (也可以相應(yīng)的說是靜態(tài)類型動態(tài)類型 ). 像Python這樣的弱類型語言通常稱為無類型,但是這樣說并不嚴(yán)謹(jǐn),因?yàn)槊總€實(shí)例都有它的運(yùn)行時類型。你只是不用事先聲明一個實(shí)例的類型而已。

          要想調(diào)用一個對象中的方法,這個方法需要在聲明類型中存在。也就是說,你只能調(diào)用定義在父類中的方法,即使該實(shí)例是一個確定的子類型:

          List list = new ArrayList();
          list.add("data");       // 在這里沒問題
          list.ensureCapacity(4); // 這里就不行了ensureCapacity() 只在ArrayList中才有。
          

          如果我們要調(diào)用實(shí)際類型中的方法,我們首先要將它轉(zhuǎn)為正確的類型。在本例中,我們可以把 ArrayList 轉(zhuǎn)為List,因?yàn)?code>ArrayList實(shí)現(xiàn)了List 接口. 也可以在運(yùn)行時動態(tài)的檢驗(yàn),使用 list instanceof ArrayList.

          可擴(kuò)展的接口

          糟糕的是,一個類不能總是實(shí)現(xiàn)你所需要實(shí)現(xiàn)的接口。可能是因?yàn)檫@只對少數(shù)幾種情況才有效,或者它是一個沒有被關(guān)聯(lián)的庫中的類型,或者這個接口在后期又被改變了。

          這種情況就可以使用IAdaptable。 你可以把 IAdaptable 動態(tài)的進(jìn)行類型轉(zhuǎn)化。使用如下方法避免直接的類型轉(zhuǎn)化:

          Object o = new ArrayList();
          List list = (List)o;
          

          我們可以這樣做:

          IAdaptable adaptable = new ArrayList();
          List list = (List)adaptable.getAdapter(java.util.List.class);
          

          你可認(rèn)為它是一種類型動態(tài)轉(zhuǎn)化; 我們把adaptable轉(zhuǎn)為List實(shí)例。

          為什么不直接轉(zhuǎn)化,而要用額外的getAdapter() 呢?這種機(jī)制可以使我們將目標(biāo)類轉(zhuǎn)化為沒有實(shí)現(xiàn)的接口。例如, 我們可能想使用HashMap 作為一個 List, 盡管他們并不兼容。

          IAdaptable adaptable = new HashMap();
          List list = (List)adaptable.getAdapter(java.util.List.class);
          

          實(shí)現(xiàn)IAdaptable

          大多數(shù)IAdaptable的實(shí)現(xiàn)看起來就想是為支持類型構(gòu)造多個if表達(dá)式的疊加。如果要為HashMap實(shí)現(xiàn)getAdapter() 可以這樣:

          public class HashMap implements IAdaptable {
            public Object getAdapter(Class clazz) {
              if (clazz == java.util.List.class) {
                List list = new ArrayList(this.size());
                list.addAll(this.values());
                return list;
              }
              return null;
            }
            // ...
          }
          

          返回的是一個對自身的代理,而不是直接轉(zhuǎn)化類型。如果請求的是不支持的類型,可以直接返回null表明失敗,這樣比拋出異常要好。

          PlatformObject

          當(dāng)你想添加新的要擴(kuò)展的類型時,只是簡單的修改一下就可以了。在任何情況下,如果已經(jīng)得到了類型,為什么不修改接口?不修改類(如果使用接口,不容易保證向后兼容)或者改變它的類型(HashMap不是 List,但是可以轉(zhuǎn)化)是有原因的。要解決這個問題,在Eclipse中,使用了一個抽象類 HashMap is not a List, but can be conveted into one).

          To solve this problem, there's an abstract class that is used by most parts of Eclipse called -->PlatformObject。它為你實(shí)現(xiàn)了 IAdaptable接口,你就可以不用再操心了。

          PlatformObject 代理所有的它對getAdapter()的請求到 IAdapterManager. IAdapterManager是平臺默認(rèn)提供的,通過 Platform.getAdapterManager()來訪問。你可以將它想象為一個巨大的 Map ,它負(fù)責(zé)關(guān)聯(lián)類和適當(dāng)?shù)倪m配器。PlatformObjectgetAdapter() 方法可以訪問到這個Map.

          適配已存在的類

          這樣的好處是可以為每一個PlatformObject對象動態(tài)的關(guān)聯(lián)新的適配器,而不用重新編譯。在Eclipse中的很多地方都是這樣來支持?jǐn)U展的。

          這里希望將裝有StringList轉(zhuǎn)為XML節(jié)點(diǎn)。 XML節(jié)點(diǎn)顯示為:

          <List>
            <Entry>First String</Entry>
            <Entry>Second String</Entry>
            <Entry>Third String</Entry>
          </List>
          

          因?yàn)?code>List的toString方法可能有別的用途,所以不能使用。 可以為List添加一個工廠,當(dāng)有轉(zhuǎn)為XML節(jié)點(diǎn)的請求時,一個Node對象就會自動返回。

          這里需要3個步驟:

          1. 從List中生成Node

          使用IAdapterFactory 來封裝轉(zhuǎn)換機(jī)制:

          import nu.xom.*;
          public class NodeListFactory implements IAdapterFactory {
            /** The supported types that we can adapt to */
            private static final Class[] types = {
              Node.class,
            };
            public Class[] getAdapterList() {
              return types;
            }
            /** The actual conversion to a Node */
            public Object getAdapter(Object list, Class clazz) {
              if (clazz == Node.class && list instanceof List) {
                Element root = new Element("List");
                Iterator it = list.iterator();
                while(it.hasNext()) {
                  Element item = new Element("Entry");
                  item.appendChild(it.next().toString());
                  root.appendChild(item);
                }
                return root;
              } else {
                return null;
              }
            }
          }
          

          2. 注冊工廠到PlatformAdapterManager

          我們需要注冊工廠到適配器工廠,當(dāng)我們向 List實(shí)例請求Node時, 它就會知道是使用我們注冊的工廠。 Platform為我們管理IAdapterManager ,而且注冊過程相當(dāng)簡單:

          Platform.getAdapterManager().registerAdapters(
            new NodeListFactory(), List.class
          );
          

          上面的代碼要求平臺管理者關(guān)聯(lián)NodeListFactoryList。但我們要求List實(shí)例的適配器,它會調(diào)用這個工廠。根據(jù)我們對工廠的定義,會獲得一個Node對象。在Eclispe中,這一步必須在插件啟動的時候顯式的執(zhí)行,要隱式執(zhí)行可以通過 org.eclipse.core.runtime.adapters 擴(kuò)展點(diǎn)。

          3. 向List要求Node

          這里是要求適配器返回一個 Node 對象:

          Node getNodeFrom(IAdaptable list) {
            Object adaptable = list.getAdapter(Node.class);
            if (adaptable != null) {
              Node node = (Node)adaptable;
              return node;
            }
            return null;
          }
          

          總結(jié)

          如果你要在運(yùn)行時為已存在的類添加功能,只要定義一個能完成轉(zhuǎn)換功能的工廠,然后注冊工程到 PlatformAdapterManager就可以了. 這項(xiàng)功能可以用來為一個非UI組件注冊一個指定的UI組件,同時保持兩部分的完全分離。就像在org.rcpapps.rcpnews.uiorg.rcpapps.rcpnews 插件中的使用。在這些例子中, IPropertySource 在UI插件中,它需要與非UI插件的數(shù)據(jù)相關(guān)聯(lián)。當(dāng)UI插件初始化時,它注冊IPropertySourcePlatform, 當(dāng)數(shù)據(jù)對象在瀏覽器中被選中時,屬性視圖中就會顯示相應(yīng)的屬性。

          很明顯, java.util.List不能擴(kuò)展PlatformObject, 所以你不能指望例子中的代碼能夠編譯通過,你可以重新構(gòu)造 List的子類來實(shí)現(xiàn)目的.繼承PlatformObject 也不是必須的:

          public class AdaptableList implements IAdaptable, List {
            public Object getAdapter(Class adapter) {
               return Platform.getAdapterManager().getAdapter(this, adapter);
            }
            private List delegate = new ArrayList();
            public int size() {
              return delegate.size();
            }
            // ...
          }
          

          本例中使用了XOM 來生成XML。

          from:
          http://www.javathink.org/bbs/read.php?tid-1469-page-e.html

          posted on 2006-07-19 21:49 CowNew開源團(tuán)隊(duì) 閱讀(359) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 富平县| 时尚| 万源市| 天长市| 通河县| 手游| 德州市| 榆社县| 云龙县| 兴隆县| 玉林市| 晋州市| 四子王旗| 连州市| 金堂县| 阳东县| 秭归县| 阳谷县| 德州市| 廊坊市| 容城县| 和政县| 佛山市| 于都县| 马公市| 宾阳县| 青浦区| 玉树县| 大理市| 阿荣旗| 合水县| 南城县| 通辽市| 阿坝县| 中阳县| 将乐县| 建始县| 蕉岭县| 两当县| 福贡县| 格尔木市|