<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      標簽列表

      everest33

      自制力

      導航

      Java泛型之通配符

      原文點此鏈接

      使用通配符的原因:Java中的數組是協變的,但是泛型不支持協變。

      數組的協變

      首先了解下什么是數組的協變,看下面的例子:

      Number[] nums = new Integer[10]; // OK
      

      因為Integer是Number的子類,一個Integer對象也是一個Number對象,所以一個Integer的數組也是一個Number的數組,這就是數組的協變。

      Java把數組設計成協變的,在一定程度上是有缺陷的。因為盡管把Integer[]賦值給Number[],Integer[]可以向上轉型為Number[],但是數據元素的實際類型是Integer,只能向數組中放入Integer或者Integer的子類。如果向數組中放入Number對象或者Number其他子類的對象,對于編譯器來說也是可以通過編譯的。但是運行時JVM能夠知道數組元素的實際類型是Integer,當其它對象加入數組是就會拋出異常(java.lang.ArrayStoreException)。

      泛型的設計目的之一就是保證了類型安全,讓這種運行時期的錯誤在編譯期就能發現,所以泛型是不支持協變的。例如:

      List<Number> nums = new ArrayList<Integer>(); // incompatible types
      

      當確實需要建立這種向上轉型的類型關系的時候,就需要用到泛型的通配符特性了。例如:

      List<? extends Number> nums = new ArrayList<Integer>(); // OK
      

      無邊界通配符(Unbounded Wildcards)

      語法:

      class-name<?> var-name

      例子:

      public static void print(List<?> list) {
          for (Object obj : list) {
              System.out.println(o);
          }
      }
      

      List<?> list和List list的區別:

      • List<?> list是表示持有某種特定類型對象的List,但是不知道是哪種類型;List list是表示持有Object類型對象的List。
      • List<?> list因為不知道持有的實際類型,所以不能add任何類型的對象,但是List list因為持有的是Object類型對象,所以可以add任何類型的對象。
        注意:List<?> list可以add(null),因為null是任何引用數據類型都具有的元素。

      Pair<?> 和 Pair 的區別

      • Pair<?>的  ? getFirst()方法,返回值只能賦值給一個Object對象,它的void setFirst(? )方法不能被調用,甚至不能用Object調用。
      • 為什么要使用這樣脆弱的類型?它對于許多簡單的操作非常有用。例如 ,下面這個方法將用來測試一個 pair 是否包含一個 mill 引用,它不需要實際的類型。
        public static boolean hasNulls (Pair<?> p)
        {
            return p.getFirstO = null | | p.getSecondO = null ;
        }
        通過將 hasNulls 轉換成泛型方法,可以避免使用通配符類型:
        public static <T> boolean hasNulls (Pair<T> p)
        但是,帶有通配符的版本可讀性更強。

         


      上邊界限定的通配符(Upper Bounded Wildcards)

      語法:

      class-name<? extends superclass> var-name

      例子:

      public static double sum(List<? extends Number> list) {
          double s = 0.0;
          for (Number num : list) {
              s += num.doubleValue();
          }
          
          return s;
      }
      
      List<? extends Number> list = new ArrayList<Integer>(); // OK
      List<? extends Number> list = new ArrayList<Object>(); // error
      

      特性:

      • List<? extends Number> list表示某種特定類型(Number或者Number的子類)對象的List。跟無邊界通配符一樣,因為無法確定持有的實際類型,所以這個List也不能add除null外的任何類型的對象
      list.add(new Integer(1)); // error
      list.add(null); // OK
      
      • 從list中獲取對象是是可以的(比如get(0)),因為在這個List中,不管實際類型是什么,但肯定都能轉型為Number。
      Number n = list.get(0); // OK
      Integer i = list.get(0); // error
      
      • 事實上,只要是形式參數有使用類型參數的方法,在使用無邊界或者上邊界限定的通配符的情況下,都不能調用。比如以java.util.ArrayList為例:
      public E get(int index) // 可以調用
      public int indexOf(Object o) // 可以調用
      public boolean add(E e) // 不能調用
      

      下邊界限定的通配符(Lower Bounded wildcards)

      語法:

      class-name<? super subclass> var-name

      例子:

      public static void writeTo(List<? super Integer> list) {
          // ...
      }
      
      List<? super Number> list = new ArrayList<Number>(); // OK
      List<? super Number> list = new ArrayList<Object>(); // OK
      List<? super Number> list = new ArrayList<Integer>(); // error
      

      特性:

      • List<? super Integer> list表示某種特定類型(Integer或者Integer的父類)對象的List。可以確定這個List持有的對象類型肯定是Integer或者其父類,所以往list里面add一個Integer或者其子類的對象是安全的,因為Integer或者其子類的對象都可以向上轉型為Integer的父類對象。但是因為無法確定實際類型,所以往list里面add一個Integer的父類對象是不安全的
      list.add(new Integer(1)); // OK
      list.add(new Object()); // error
      
      • 當從List<? super Integer> list獲取具體的數據的時候,JVM在編譯的時候知道實際類型可以是任何Integer的父類,所以為了安全起見,要用一個最頂層的父類對象來指向取出的數據,這樣就可以避免發生強制類型轉換異常了。
      Object obj = list.get(0); // OK
      Integer i = list.get(0); // error
      

      PECS原則(Producer Extends Consumer Super)

      從上面上邊界限定的通配符和下邊界限定的通配符的特性,可以知道:

      • 對于上邊界限定的通配符,無法向其中加入任何對象,但是可以從中正常取出對象。
      • 對于下邊界限定的通配符,可以存入subclass對象或者subclass的子類對象,但是取出時只能用Object類型變量指向取出的對象。

      簡而言之,上邊界限定(extends)的通配符適合于內容的獲取,而下邊界限定(super)的通配符更適合于內容的存入。所以就有了一個PECS原則來很好的解釋這兩種通配符的使用原則。

      • 當一個數據結構作為producer對外提供數據的時候,應該只能取數據而不能存數據,所以適合使用上邊界限定(extends)的通配符。
      • 當一個數據結構作為consumer獲取并存入數據的時候,應該只能存數據而不能取數據,所以適合使用下邊界限定(super)的通配符。
      • 如果既需要取數據也需要存數據,就不適合使用泛型的通配符。
      public static <T> void copy(List<? super T> dest, List<? extends T> src) {
          for (int i = 0; i < src.size(); i++) {
              dest.set(i, src.get(i));
          }
      }
      

      posted on 2019-09-25 23:33  everest33  閱讀(369)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 亚洲日本精品一区二区| 亚洲国产精品综合久久2007| 国产精品毛片一区二区| 色综合视频一区二区三区| 无码AV无码免费一区二区| 99久久精品国产免费看| 久久亚洲人成网站| 国产日韩一区二区天美麻豆 | 亚洲中文字幕一区二区| 一区二区亚洲人妻精品| 亚洲一区二区三区在线播放无码| 国产另类ts人妖一区二区| 99久久国产宗和精品1上映| 韩国 日本 亚洲 国产 不卡| 成人一区二区人妻不卡视频| 男人天堂亚洲天堂女人天堂| 377P欧洲日本亚洲大胆| 亚洲中文字幕一区二区| 又粗又大又黄又硬又爽免费看| 久久国产精品久久精品国产| 欧美成人va免费大片视频| 亚洲无人区视频在线观看| 欧美成人精品一级在线观看| 亚洲日韩AV秘 无码一区二区 | 亚洲av日韩av一区久久| 18禁黄无遮挡网站免费| 国产激情精品一区二区三区| 91国在线啪精品一区| 天堂V亚洲国产V第一次| 欧美黑人又粗又大又爽免费| 国产精品 无码专区| 久久精品国产亚洲av麻豆不卡| 国产欧美精品一区aⅴ影院| 成年美女黄网站色大片免费看| 股票| av天堂亚洲天堂亚洲天堂| 蜜臀av无码一区二区三区| 国产成人无码aa精品一区| 好吊视频在线一区二区三区| 国产精品国三级国产av| 国产96在线 | 亚洲|