John Jiang

          a cup of Java, cheers!
          https://github.com/johnshajiang/blog

             :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
            131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
          在泛型中使用通配符和繼承
              本文是Sun官方以Blog形式發布的Java核心技術竅門(JavaCoreTechTip)中的一篇,它以非常簡潔的示例展示了泛型通配符的使用,初學Java泛型的朋友可以看看。(2009.12.30最后更新)
              Java2平臺,標準版5.0(J2SE 5.0)為Java程序設計語言及其平臺引入了泛型。在最簡單的案例和典型的應用中,泛型能夠識別集合容器中所存儲的是否是你所期望的對象。所以,你可以特別說你有一個String或其它類型對象的List,而不是聲稱你的程序有一個Object的List。所以,如果你不小心向該List中加入了錯誤類型的對象,編譯器會告之你這個錯誤。該錯誤將在編譯時進行修復,而不用等到你運行該程序,且在程序運行到該處代碼時,在獲取對象的操作中產生一個運行時的強制類型轉換異常。
          這就提出了泛型的第二個好處。迭代器將變得類型安全了。Iterator接口中的next()方法將會返回集合中下一個元素的類型安全版本。
              但這并不是本文要介紹的泛型應用的竅門,那些竅門已由2005 Core Java Technologies Tip描述過了。在使用泛型時,大多數人都不能很好地理解對extends關鍵字的使用。一個典型的描述如何使用extends關鍵字的示例與繪制圖形有關。與其不同的是,此處竅門所用的示例將使用Swing組件,以便你不必創建額外的新類。在一個非常有限的例子中,Swing按鈕組件的類層次結構如下所示,當然,Object是實際上的根。
          Component
          |- Container
             
          |- JComponent
                
          |- AbstractButton
                   
          |- JButton
                   
          |- JMenuItem
                      
          |- JCheckBoxMenuItem
                      
          |- JMenu
                      
          |- JRadioButtonMenuItem
                   
          |- JToggleButton
                      
          |- JCheckBox
                      
          |- JRadioButton

              所有AbstractButton的子類都共同享有的一個東西就是方法getText。這就是泛型的精髓,你能定義一個方法去處理以AbstractButton為元素的List,并返回這些按鈕的String類型的標簽的List。下面是該方法的第一個版本:
          public static List<String> getLabels(List<AbstractButton> list) {
              List
          <String> labelList = new ArrayList<String>(list.size());
              
          for (AbstractButton button: list) {
                  labelList.add(button.getText());
              }
              
          return labelList;
          }

              下面就是如何使用該方法。首先,定義一個AbstractButton類型的List,然后向其中填充值,并調用該方法:
          List<AbstractButton> buttonList = new ArrayList<AbstractButton>();
          buttonList.add(
          new JButton("Hello"));
          buttonList.add(
          new JCheckBox("World"));
          buttonList.add(
          new JRadioButton("Hola"));
          buttonList.add(
          new JMenuItem("Mundo"));

          List labels 
          = getLabels(buttonList);
          System.out.println(labels);

              根據Google,"Hola, Mundo"是"Hello, World"的西班牙譯文。調用println()方法的結果如下所示:
          [Hello, World, Hola, Mundo]

              對于AbstractButtonList對象,一切都能正常運行,但當是其它類型,特別是AbstractButton子類型的List時,就不能正常工作了。從邏輯上,有人可能認為對于以JButton為元素的List,一切仍能正常工作。因為JButton是AbstractButton的子類。難道不能對AbstractButton子類型的List調用方法getLabels(List<AbstractButton>)
          然而,事實并非如此。因為這是一個編譯時檢查,同時也因為getLabels方法被定義為只接受AbstractButton的List,你不能向該方法中傳入任何其它類型的List。
          GetList.java:13: getLabels(java.util.List<javax.swing.AbstractButton>)
            in GetList cannot be applied to (java.util.List
          <javax.swing.JButton>)

              List
          <String> labels = getLabels(buttonList);
                                    
          ^
          1 error

          這也就是extends關鍵字發揮作用的地方了。不將getLabes方法定義為僅僅接受AbstractButton List,而是將它定義為接受AbstractButton子類的List
          public static List<String> getLabels(
                  List
          <? extends AbstractButton> list)

          此處的通配符?表明該方法并不關心確切的類型是什么,只要它是AbstractButton的子類型即可。下面是綜合了前述所有代碼片斷的完整示例程序:
          import java.util.*;
          import javax.swing.*;

          public class GetList {
              
          public static void main(String args[]) {
                  List
          <JButton> buttonList =
                          
          new ArrayList<JButton>();
                  buttonList.add(
          new JButton("Hello"));
                  buttonList.add(
          new JButton("World"));
                  buttonList.add(
          new JButton("Hola"));
                  buttonList.add(
          new JButton("Mundo"));

                  List labels 
          = getLabels(buttonList);
                  System.out.println(labels);
              }

              
          public static List<String> getLabels(
                      List
          <? extends AbstractButton> list) {
                  List
          <String> labelList = new ArrayList<String>(list.size());
                  
          for (AbstractButton button: list) {
                      labelList.add(button.getText());
                  }
                  
          return labelList;
              }
          }

          現在,當你要用泛型來定義你自己的類和方法時,就要考慮接受作為泛型參數的抽象類,或它的任一超類,記得使用通配符以便相同的方法對于子類也能很好地工作。
          更多關于泛型的信息,請見兩篇較早前由Gilad Bracha撰寫的教程:一篇是2004年的教程(PDF),另一篇是在線的Java Tutorial中的泛型章節。

          posted on 2009-12-28 13:44 John Jiang 閱讀(2100) 評論(0)  編輯  收藏 所屬分類: JavaSEGenericsJava翻譯CoreJavaTechTips
          主站蜘蛛池模板: 武强县| 阿瓦提县| 棋牌| 芒康县| 白朗县| 南阳市| 鸡泽县| 南郑县| 濮阳市| 太和县| 崇阳县| 新乐市| 当涂县| 广丰县| 马山县| 武胜县| 蒙山县| 雷山县| 壤塘县| 阿瓦提县| 康马县| 营山县| 九龙县| 永嘉县| 曲阳县| 蒲江县| 天台县| 邢台县| 永顺县| 灵石县| 手游| 河池市| 廊坊市| 衡阳县| 南宫市| 义乌市| 桂林市| 柳江县| 盐源县| 龙门县| 万盛区|