Java泛型(4)通配符、上限通配符、下限通配符

1.官方文档

概述 https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
上限通配符 https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html
下限通配符 https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
未限定的通配符 https://docs.oracle.com/javase/tutorial/java/generics/unboundedWildcards.html
Wildcard Capture and Helper Methods https://docs.oracle.com/javase/tutorial/java/generics/capture.html

2.简介

2.1 通配符与通配符类型定义

    List<?>                   list1;
    List<? super  Integer>    list2;
    List<? extends Number>    list3;
  • 上面代码中的 ? 就是通配符,表示当前未知的泛型实参,该泛型实参由List<?>赋值时推断而来。如果该类型推断失败,该调用报错。如List.add(E),需要推断,而   List.add(null)和List.clear()等则无需类型推断。
  • ? super  Integer 通配符类型,限制泛型实参类型为Integer及其父类。
  • ? extends Number 是通配符类型,限制泛型实参为Number及子类型。

2.2 应用范围

可用范围

泛型形参 class A<? extends Number>{}
成员变量 List<?>  mData;
局部变量 Class<?> clazz;
函数形参

void foo(List<? extends Number> numbers){  }

void fun(List<? super Integer> numbers ){  }

返回值 List<? super Integer> foo() { return null; }
禁用范围 泛型形参声明

class A<? extends Number> {}  //error

class C<? super Integer> {  }    //error

泛型函数调用 this.<?>foo(2);      //error
泛型类实例创建 new B<?>();

示例如下:

public class Wildcards {
    List<?> mData   ;                           //成员变量
    //class A<? extends Number>         {  }    //error
    //class B<? super Integer>          {  }    //error
    class C <T>                         {  }
    public List<? super Integer> foo()  { return null; }
    public <T> void foo(T t)            {  }

    @Test
    public void test1(){
        this.<Float>foo(2f);
        //this.<?>foo(2);                       //error
        Class<?> clazz;                         //局部变量

        C<?> objB    = new C<>() ;              //ok
        //Object obj = new C<?>();              //error
    }
}

2.3 通配符类型父子关系示例图

3.上限通配符

3.1 语法

? extends XXX ,XXX是类型 、接口 或 泛型类型,如

    List<? extends Number>               list1      //extends 类
    List<? extends Serializable>         list2      //extends 接口
    List<? extends Comparable<Integer>>  list3      //extends 泛型接口

注意 :

通配符上限与泛型形参的限定不一样,后者可以指定多个限定,而前者只能指定一个

    @Test
    public void wildcards_test4(){
        class MyNumber extends Number implements Serializable,Comparable<MyNumber>{
            @Override public int compareTo(MyNumber o)  { return this.intValue() - o.intValue(); }
            @Override public int    intValue        ()  { return 0; }
            @Override public long   longValue       ()  { return 0; }
            @Override public float  floatValue      ()  { return 0; }
            @Override public double doubleValue     ()  { return 0; }
        }
        class MyInteger extends Number{
            @Override public int    intValue        () { return 0; }
            @Override public long   longValue       () { return 0; }
            @Override public float  floatValue      () { return 0; }
            @Override public double doubleValue     () { return 0; }
        }
        class MyByte  extends Number implements     Comparable{             //warning,raw type
            @Override public int    intValue        () { return 0; }
            @Override public long   longValue       () { return 0; }
            @Override public float  floatValue      () { return 0; }
            @Override public double doubleValue     () { return 0; }

            @Override public int compareTo(Object   o) { return 1; }        //这里意义,与Object比较
        }
        class MyFloat extends Number implements     Comparable<Float>{      //warning,raw type
            @Override public int    intValue        () { return 0; }
            @Override public long   longValue       () { return 0; }
            @Override public float  floatValue      () { return 0; }
            @Override public double doubleValue     () { return 0; }

            @Override public int compareTo(Float    o) { return floatValue() > o ? 1 : (floatValue() == 0 ? 0 : -1); }
        }
        //ArrayList<? extends Number & Serializable> ee;                //error
        class A  <T extends Number & Serializable & Comparable<?>> {}   //ok
        class B  <T extends Number & Serializable & Comparable<T>> {}   //ok
        class C  <T extends Number & Serializable & Comparable   > {}   //warning,raw type

        A<MyNumber>     am = new A<>();
        //B<String>     bm = new B<>();                 //error String 不是number
        //C<MyInteger>  cm = new C<>();                 //error,MyInteger没有实现Comparable
        C<MyByte>       cb = new C<>();                 //ok
        C<MyFloat>      cf = new C<>();                 //ok
    }

3.2 作用

  • 限制泛型实参的必需为xxx及其子类
  • 约定 List<? extends Number> 是 List<Integer>的父类,其它泛型类型同理,如Vector<? extends Number>是Vector<Float>父类。

3.3 示例

    //Upper Bounded
    public void process1(List<? extends Number> list) {          //extends 类
        for (Number elem : list) { /* */ }
    }
    @Test
    public void test_upper_bounded (){
        List<Number>            list0  = new ArrayList<Byte>();  //error
        List<Number>            list1  = new ArrayList<>()    ;
        List<Integer>           list2  = new ArrayList<>()    ;
        List<? extends Number>  list3  = new ArrayList<Byte>();
        List<Object>            list4  = new ArrayList<>();

        List<? extends Number> argument;
        List<?>                  parent;
        Object               forefather;

        argument = list0;
        argument = list1;
        argument = list4;       //error : 泛型实参Object 是 Number父类

        process1(list1);
        process1(list2);
        process1(list3);
        process1(list4);        //error : 泛型实参Object 是 Number的父类。

        parent     = argument; parent     = list1   ; //...
        forefather = parent  ; forefather = argument; //...

    }

3.4 ? extends 泛型类型

    public void process4(List<? extends Comparable<Integer>> list) {  //extends 接口
        for (Comparable<Integer> s : list){
        }
    }
    public void process5(List<? extends Comparable<?>> list)       {  //extends 接口
        for (Comparable<?> s : list){
        }
    }
    public void process6(List<? extends Comparable> list)          {  //extends 接口
        for (Comparable s : list){
        }
    }
    @Test
    public void wildcards_test3(){
    }

4. 未限定的通配符

4.1 作用

        在定义泛型类型时,如果只用一个?表示泛型实参。这就是未限定通配符.如: List<?> list; 它是其它List<XXX>的父类,是Object的子类。

4.2 示例

    public void printList(List<?> list) {
        for (Object elem: list)
            System.out.print(elem + " ");
        System.out.println();
    }
    @Test
    public void wildcards_test5(){
        List<Integer> listInt = Arrays.asList(1,2,3);
        List<String>  listStr = Arrays.asList("a","b","c");

        Object   obj  = listInt;
        List<?> list1 = listInt;
        List<?> list2 = listStr;

        obj           = list1;
        obj           = list2;

        printList(listInt);
        printList(listStr);
        printList(list1  );
        printList(list2  );
    }

结果

1 2 3 
a b c 
1 2 3 
a b c 

4.3 List<?>与List<Object> 区别

List<?>只能add(null),而List<Object>可add(Object及其子类)。

    @Test
    public void wildcards_test6(){
        ArrayList<Integer>  tmp   = new ArrayList<>();
        List<?>             list1 = tmp;
        List<?>             list2 = Arrays.asList(1,2,3);
        List<Object>        list3 = Arrays.asList("a","b","c");
        Object              obj1  = list1;
        Object              obj2  = list3;

        tmp.add(1)      ;       //ok
        tmp.add(2)      ;       //ok
        //list1.add(3)  ;       //error ,incompatible types: int cannot be converted to CAP#1
        out.println(ClassLayout.parseInstance(tmp).toPrintable());
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        list1.add(null) ;       //ok
        //list1  = list3;       //ok
        out.println(ClassLayout.parseInstance(list1).toPrintable());
        list1.clear()   ;       //ok


        list3.add(1)    ;       //error,运行时错误。UnsupportedOperationException
        list3.add(3f)   ;       //error,运行时错误。UnsupportedOperationException
        list3.add(null) ;       //error,运行时错误。UnsupportedOperationException
        list3.clear()   ;       //error,运行时错误。UnsupportedOperationException
    }

结果:

java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           0d 00 00 00 (00001101 00000000 00000000 00000000) (13)
      4     4                      (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                      (object header)                           57 60 00 20 (01010111 01100000 00000000 00100000) (536895575)
     12     4                  int AbstractList.modCount                     2
     16     4                  int ArrayList.size                            2
     20     4   java.lang.Object[] ArrayList.elementData                     [1, 2, null, null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           0d 00 00 00 (00001101 00000000 00000000 00000000) (13)
      4     4                      (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                      (object header)                           57 60 00 20 (01010111 01100000 00000000 00100000) (536895575)
     12     4                  int AbstractList.modCount                     11
     16     4                  int ArrayList.size                            11
     20     4   java.lang.Object[] ArrayList.elementData                     [1, 2, null, null, null, null, null, null, null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total


java.lang.UnsupportedOperationException
	at java.base/java.util.AbstractList.add(AbstractList.java:153)
	at java.base/java.util.AbstractList.add(AbstractList.java:111)
	at com.example.sjjg.java.generic.Wildcards.wildcards_test6(Wildcards.java:178)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	

5.下限通配符

5.1 语法

?  super  xxx  , xxx为类型、接口、泛型类型,如下:

    List<? super  Integer>   list5 = new ArrayList<Number>();
    List<? super   Number>   list6 = new ArrayList<>();
    List<? super   Object>   list7 = new ArrayList<>();
    List<? super A<Integer>> list1 = new ArrayList<>();
    List<? super    A<E> >   list2 = new ArrayList<>();

5.2 作用

  • 限定泛型实参的类型为xx及其父类。
  • 让List<? super Integer> 成为 List<Object>,List<Number>的父类。

5.3 示例

    //Lower Bounded
    private void foo_lower(List<? super Number> list){
        //? super Number 限制传进来的类型一定是 List<Object>,List<Number> 其中 之一
        list.add(0)             ; //ok
        list.add(1f)            ; //ok
        list.add(2L)            ; //ok
        list.add(3)             ; //ok
        list.add("4")           ; //error : List<Object>可以add(String),但是List<Number>无法add(String)
        list.add(new Object())  ; //error : List<Object>可以add(Object),但是List<Number>无法add(Object)
        List<Object> ll = new ArrayList<>();
        ll.add("eee");

        Integer elem0   = (Integer) list.get(0) ;
        int     elem1   = (int) list.get(1)     ;
        Object  elem2   = list.get(2)           ;
        Number  elem3   = (Number) list.get(3)  ;

        out.println(String.format("elem0 = %s,elem1 = %s,elem2 = %s,elem3 = %s",elem0,elem1,elem2,elem3));

    }
    @Test
    public <T> void lower_bounded1(){
        List<Integer>           list1  = new ArrayList<>();
        List<Number>            list2  = new ArrayList<>();
        List<Object>            list3  = new ArrayList<>();
        List<String>            list4  = new ArrayList<>();
        List<? super  Integer>  list5  = new ArrayList<Number>();//虽然实际new 的是 ArrayList<Number>
        List<? super   Number>  list6  = new ArrayList<>();
        List<? super   Object>  list7  = new ArrayList<>();
        List<? extends Number>  list8  = new ArrayList<>();

        List<?>                parent  ;
        Object             forefather  ;
        List<? super Number>  argument ;

        argument = new ArrayList<Integer>();    //error : 泛型实参为Integer
        argument = new ArrayList<Number>() ;
        argument = new ArrayList<Object>() ;
        argument = new ArrayList<String>() ;    //error : 泛型实参实参为String
        argument = new ArrayList<T>()      ;    //error : T为不确定

        argument = list1;       //error : 泛型实参为Integer
        argument = list2;
        argument = list3;
        argument = list4;       //error : 泛型实参实参为String
        argument = list5;       //error : 泛型实参实参可能为Integer,list5 = argument; //ok
        argument = list6;
        argument = list7;
        argument = list8;       //error : 泛型实参实参为Number及子类。

        foo_lower(list1);       //error : 泛型实参为integer不是Number及其父类
        foo_lower(list2);       //ok
        foo_lower(list3);       //ok
        foo_lower(list4);       //error : 泛型实参String   不是Number及其父类
        foo_lower(list5);       //error : ? super Integer 不完全保证是泛型实参是Number,比如Integer就不是
        foo_lower(list6);       //ok
        foo_lower(list7);       //ok
        foo_lower(list8);       //error : ? extends Number 无法保证是泛型实参是Number,比如Float就不是


        // List<?> 是List<xxx>父类 Object是所有类父类。
        parent      = list1 ; parent     = list2; /*...*/   parent   = list8; //ok
        forefather  = parent; forefather = list1; /*...*/ forefather = list8; //ok

    }

5.4  ? super 泛型类型<T>

    @Test
    public <E> void lower_bounded2(){
        class A <T> { }
        List<? super A<Integer>> list1 = new ArrayList<>();
        List<? super A<E>>       list2 = new ArrayList<>();
    }

6.通配符类型提取

6.1 通配符提取

        In some cases, the compiler infers the type of a wildcard. For example, a list may be defined as List<?> but, when evaluating an expression, the compiler infers a particular type from the code. This scenario is known as wildcard capture.

        带有 ? 的泛型实参由赋值时推断而来。如果该类型推断失败,该调用报错。

        ?extends Number 确保泛型实参一定是Number及其子类,但无法确定是哪一个子类,示例如下:

    private void upper(List<? extends Number> list){
        Object obj  = list.get(0);  //ok      get(int)      不需要泛型类型E
        list.set(0,100f)         ;  //error   set(int,E)    需要泛型实参
        list.remove(0)           ;  //ok      remove(int)   不需要泛型类型E
        list.clear()             ;  //ok      clear()       不需要泛型类型E
        list.add(0)              ;  //error   add(E)        需要泛型类型E,这里推断失败
        list.add(null)           ;  //ok      add(null)     不需要泛型类型E
        if(list.contains("aa")){    //ok   contains(Object) 不需要泛型类型E
        }
    }

? super Integer 可以确保推断出来 泛型实参一定是Integer及其父类,示例如下:

private void lower(List<? super Integer> list){
        Object obj  = list.get(0);  //ok      get(int)      不需要泛型类型E
        list.set(0,1)            ;  //ok      set(int,E)    1,ok
        list.set(0,1f)           ;  //error   set(int,E)    1f是对应Float,不是Integer及其父类
        list.remove(0)           ;  //ok      remove(int)   不需要泛型类型E
        list.clear()             ;  //ok      clear()       不需要泛型类型E
        list.add(0)              ;  //ok      add(E)        Integer
        list.add(null)           ;  //ok      add(null)     需要泛型类型E,这里推断失败
        if(list.contains("aa")){    //ok   contains(Object) 不需要泛型类型E
        }
    }

6.2 通配符的help函数

public class WildcardFixed {

    void foo(List<?> i) {
        fooHelper(i);
    }


    // Helper method created so that the wildcard can be captured
    // through type inference.
    private <T> void fooHelper(List<T> l) {
        l.set(0, l.get(0));
    }

}

 

posted @ 2015-07-29 19:18  f9q  阅读(1248)  评论(0编辑  收藏  举报