人在江湖

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            82 Posts :: 10 Stories :: 169 Comments :: 0 Trackbacks

          從JDK1.4到JDK5中間經(jīng)歷了兩年半左右的時(shí)間,從JDK5到JDK6經(jīng)歷了兩年左右的時(shí)間,從JDK6到JDK7經(jīng)歷了4年半多的時(shí)間。JDK5,6,7這三個(gè)版本,只有JDK5有橫空出世的驚艷,一系列new feature明顯改變了Java程序員日常的coding工作:Generics, Annotation, Autoboxing, for each statement.... 其中Java Generics是一個(gè)大的新feature. 相較于C++ templates, Java Generics有諸多限制和陷阱,所以用起來有些不爽, 但越是陷阱多,越有必要好好學(xué)學(xué)。Thinking in java 第四版除了最后一章GUI外一共900頁,其中Generics這一章就90多頁,這篇博客主要是Thinking in java的Generics這章的筆記。

           

          Java Generics 可以應(yīng)用于Class和Interface,比如:

          public class LinkedStack<T>{}

          public interface Generator<T> {}

          也可以應(yīng)用于方法,比如:

          public <T> void f(T x) { }

          使用泛型時(shí),需要時(shí)時(shí)牢記的是,運(yùn)行時(shí)的泛型代碼中不真的保留泛型參數(shù)類型(There’s no information about generic parameter types available inside generic code.  )所以運(yùn)行時(shí),List<String>和List<Integer>是一回事。

           

          注意泛型不總是實(shí)用,比如:

             1: class Manipulator2<T extends HasF> { 
             2:   private T obj; 
             3:   public Manipulator2(T x) { obj = x; } 
             4:   public void manipulate() { obj.f(); } 
             5: } 

          完全可以替代成:

             1: class Manipulator3 { 
             2:   private HasF obj; 
             3:   public Manipulator3(HasF x) { obj = x; } 
             4:   public void manipulate() { obj.f(); } 
             5: } 

          但是如果原本的code有一點(diǎn)變化,泛型帶來的好處就體現(xiàn)出來了:

             1: class ReturnGenericType<T extends HasF> { 
             2:   private T obj; 
             3:   public ReturnGenericType(T x) { obj = x; } 
             4:   public T get() { return obj; } 
             5: } 

          注意這個(gè)例子里get()方法返回了特定的類型T。

           

          因?yàn)閞un time時(shí)泛型丟掉了真正的類型,所以一些操作是不被允許的:

             1: public class Erased<T> { 
             2:   private final int SIZE = 100; 
             3:   public static void f(Object arg) { 
             4:     if(arg instanceof T) {}          // Error 
             5:     T var = new T();                 // Error 
             6:     T[] array = new T[SIZE];         // Error 
             7:     T[] array = (T)new Object[SIZE]; // Unchecked warning 
             8:   } 
             9: } 

          這時(shí)候可以顯式地傳入Class object參數(shù),書里稱之為Type Tag

             1: public class ClassTypeCapture<T> { 
             2:   Class<T> kind; 
             3:   public ClassTypeCapture(Class<T> kind) { 
             4:     this.kind = kind; 
             5:   } 
             6:  
             7:   public boolean f(Object arg) { 
             8:     return kind.isInstance(arg); 
             9:   }  
            10: }

          Dimension是Class, HasColor是Interface, 可以有如下的寫法

          class ColoredDimension<T extends Dimension & HasColor> { }

          注意extends后可以有多項(xiàng),這與Class的繼承不同,并且,Class要放在Interface前面

           

          注意Array對(duì)數(shù)據(jù)類型檢查是很嚴(yán)格的:

             1: class Fruit {} 
             2: class Apple extends Fruit {} 
             3: class Jonathan extends Apple {} 
             4: class Orange extends Fruit {} 
             5:  
             6: public class CovariantArrays { 
             7:   public static void main(String[] args) { 
             8:     Fruit[] fruit = new Apple[10]; 
             9:     fruit[0] = new Apple(); // OK 
            10:     fruit[1] = new Jonathan(); // OK 
            11:     // Runtime type is Apple[], not Fruit[] or Orange[]: 
            12:     try { 
            13:       // Compiler allows you to add Fruit: 
            14:       fruit[0] = new Fruit(); // ArrayStoreException 
            15:     } catch(Exception e) { System.out.println(e); } 
            16:     try { 
            17:       // Compiler allows you to add Oranges: 
            18:       fruit[0] = new Orange(); // ArrayStoreException 
            19:     } catch(Exception e) { System.out.println(e); } 
            20:   } 
            21: } 

          注意這一句,F(xiàn)ruit[] fruit = new Apple[10]; 實(shí)際類型是Apple,那么fruit里就不能加入Fruit或Orange了.

           

          Container不存在upcast, 別混淆了被包含的元素:

             1: public class NonCovariantGenerics { 
             2:   // Compile Error: incompatible types: 
             3:   List<Fruit> flist = new ArrayList<Apple>(); 
             4: }

          如果非要upcast的話可以這樣寫:

          List<? extends Fruit> flist = new ArrayList<Apple>(); 

          需要注意的是,flist不能再往里加new Apple()或new Fruit()或任何東西了,因?yàn)閏ompiler看到List<? extends Fruit>, 就會(huì)認(rèn)為里面可能是Apple,也可能是Orange, 你往里填什么他都不認(rèn)為一定對(duì)。

           

          如果想往List里添加,可以這樣寫:

             1: public class SuperTypeWildcards { 
             2:   static void writeTo(List<? super Apple> apples) { 
             3:     apples.add(new Apple()); 
             4:     apples.add(new Jonathan()); 
             5:     // apples.add(new Fruit()); // Error 
             6:   } 
             7: } 

           

           

          代碼片段:

           

             1: static <T> 
             2:  T wildSubtype(Holder<? extends T> holder, T arg) { 
             3:    // holder.set(arg); // Error: 
             4:    //   set(capture of ? extends T) in 
             5:    //   Holder<capture of ? extends T> 
             6:    //   cannot be applied to (T) 
             7:    T t = holder.get(); 
             8:    return t; 
             9:  }  
            10:  static <T> 
            11:  void wildSupertype(Holder<? super T> holder, T arg) { 
            12:    holder.set(arg); 
            13:    // T t = holder.get();  // Error: 
            14:    //   Incompatible types: found Object, required T 
            15:  
            16:    // OK, but type information has been lost: 
            17:    Object obj = holder.get(); 
            18:  } 

           

          <? extends T> 和 <? super T>兩者中,前者適合get到特定類型T, 但是不能做set操作。后者相反, 可以set特定類型,但是不能get到特定類型。

           

          Holder, Holder<?>這兩個(gè)類不一樣,Holder代表可以包含任何類型,Holder<?>代表可以包含一系列同種類型,但不知道是哪種類型,甚至于你不能往里面加入Object

          posted on 2012-08-20 08:13 人在江湖 閱讀(7152) 評(píng)論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 堆龙德庆县| 婺源县| 天台县| 绥化市| 北碚区| 台中县| 城市| 时尚| 八宿县| 胶州市| 康保县| 东源县| 婺源县| 呼图壁县| 马山县| 衡水市| 吴旗县| 余干县| 南木林县| 东乌珠穆沁旗| 河曲县| 全南县| 彭州市| 石景山区| 婺源县| 肇庆市| 陆河县| 山丹县| 白朗县| 叶城县| 台中市| 竹北市| 盐津县| 惠东县| 红安县| 孝义市| 皋兰县| 九江市| 宝清县| 肃北| 绥德县|