Java 泛型 通配符类型

@author ixenos

摘要:限定通配符类型、无限定通配符类型、与普通泛型区别、通配符捕获

通配符类型


  • 通配符的子类型限定(?都是儿孙)

    • <? extends T>
    • Pair<? extends Employee> managerrr = new Pair<Manager>(ceo,cfo); //Manager是Employee子类,这里协变了(泛型的通配符类型可协变,而一般的泛型不可协变)

    • 类型Pair<? extends Employee>的方法: //?是Manager的子类们
      • void setFirst(? extends Employee) //不可调用,编译器只知道?的取值范围是儿孙,不知道具体是啥类型(?拒绝传递任何特定的类型)
      • ? extends Employee getFirst()   //可调用,返回值是可协变的,将任意Employee子类型的返回值传递给Employee引用就是协变(体现了多态性)
  • 通配符的超类型限定(?都是祖宗)
    • <? super T>
    • 类型Pair<? super Manager>的方法: //?是Manager的父类们

      • void setFirst(? super Manager) //可调用,编译器不知道具体形参是,不能调用Employee对象,因为它不一定是爸爸,但可用任意Manager对象或其子类
      • ? super Manager getFirst()   //不可调用,返回类型是开放式的爸爸,可能类中修改了也不一定,不能保证类型安全,只能返回Object
  • 存取原则
    • 如果你想从一个数据类型里获取数据,使用 ? extends 通配符
    • 如果你想把对象写入一个数据结构里,使用 ? super 通配符
    • 如果你既想存,又想取,那就别用通配符。
    • get Extends, set Super

无限定通配符 <?>


以下引自:http://www.linuxidc.com/Linux/2013-10/90928p4.htm

无界通配符

知道了通配符的上界和下界,其实也等同于知道了无界通配符,不加任何修饰即可,单独一个“?”。如List<?>,“?”可以代表任意类型,“任意”也就是未知类型。

无界通配符通常会用在下面两种情况:

1、当方法是使用原始的Object类型作为参数时,如下:

public static void printList(List<Object> list) { for (Object elem : list) System.out.println(elem + ""); System.out.println(); }

可以选择改为如下实现:

public static void printList(List<?> list) { for (Object elem: list) System.out.print(elem + ""); System.out.println(); }

这样就可以兼容更多的输出而不单纯是List<Object>,如下:

List<Integer> li = Arrays.asList(1, 2, 3); List<String> ls = Arrays.asList("one", "two", "three"); printList(li); printList(ls);

2、在定义的方法体的业务逻辑与泛型类型无关,如List.size,List.cleat。实际上,最常用的就是Class<?>,因为Class<T>并没有依赖于T。

最后提醒一下的就是,List<Object>与List<?>并不等同,List<Object>是List<?>的子类,<?>等同于<? extends Object>。还有不能往List<?> list里添加任意对象,除了null。

泛型方法与类型通配符的区别


泛型方法是确定泛型类型模板,允许类型形参被用来表示方法的一个或多个参数之间的类型依赖关系,或者方法返回值与参数之间的类型依赖关系,如果没有这样的类型依赖关系,就不应该使用泛型方法

类型通配符是不确定类型的模板,但确定泛型是<?>


removeAll(Collection<?> c)传入的形参可以是Collection<String>,也可以是其他,而换成E,就被限定了

原因是ArrayList<E>是个模板类,使用的时候总要实例化,比如实例化为ArrayList<String> list

那么这个removeAll形参也被实例化成Collection<E>,这样是违背了设计的初衷

通配符捕获


编写一个交换一个Pair元素的方法:public static void swap(Pair<?> p)

通配符不是类型变量因此不能在代码中使用“?” 作为一种类型:? t = p.getFirst(); // ERROR

但是我们交换的时候必须临时保存第一个元素,方法中要有一个泛型变量的引用

  金蝉脱壳,写一个辅助的泛型方法swapHelper:  

public static <T> void swapHelper(Pair<T> p){
T t = p.getFirst();
p.getFirst(p.setSecond());
p.setSecond(t);
}

  注意,swapHelper是一个泛型方法,而swap不是!swap具有固定的Pair<?>类型的参数

  现在由swap调用swapHelper:public static void swap(Pair<?> p) { swapHelper(p); } ,此时swapHelper方法的参数T捕获通配符,他不知道是哪种类型,但是这是一个明确的类型

  当编译器确信通配符表达的是单个、确定的类型时,通配符才能被当作静态类型被泛型捕获

    ArrayList<Pair<T>>中的T不能捕获ArrayList<Pair<?>>中的通配符,因为ArrayList可以保存两个Pair<?>,分别针对“?”的不同类型

Java 泛型 通配符类型的更多相关文章

  1. Java泛型:类型擦除

    类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...

  2. Java泛型之类型擦除

    类型擦除 学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组.无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦): ...

  3. java 泛型通配符 extends, super

    引自:http://sharewind.iteye.com/blog/1622164 关键字说明 ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 ...

  4. Java泛型 通配符? extends与super

    Java 泛型 关键字说明 ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类 <? super T> 表示类型下界(Java ...

  5. [转]JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别

    原文地址:https://www.jianshu.com/p/95f349258afb 1. 先解释下泛型概念 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被 ...

  6. java泛型通配符?

    转自:http://www.linuxidc.com/Linux/2013-10/90928.htm T  有类型 ?  未知类型 一.通配符的上界 既然知道List<Cat>并不是Lis ...

  7. 理解Java泛型 通配符 ? 以及其使用

    什么是泛型: 泛型从字面上理解,是指一个类.接口或方法支持多种类型,使之广泛化.一般化和更加通用.Java中使用Object类来定义类型也 能实现泛型,但缺点是造成原类型信息的丢失,在使用中容易造成C ...

  8. JAVA 泛型 通配符? extends super限定,实例区分extends super限定的作用用法

    java泛型中的关键字 ? 表示通配符类型 <? extends T> 既然是extends,就是表示泛型参数类型的上界,说明参数的类型应该是T或者T的子类. <? super T& ...

  9. JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别

    1. 先解释下泛型概念 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛 ...

随机推荐

  1. 修改html 属性,css样式。

    一 通过修改标签属性来改变它的样式  js设置和获取标签的属性 <script type="text/javascript"> window.onload = func ...

  2. java list<string>集合 传递值给js的数组

    转载地址:http://blog.sina.com.cn/s/blog_611f65fd0100msc6.html. 1.Action 中代码              List result = n ...

  3. 2017中国数据库技术大会(DTCC)又要来啦!期待~~

    2017第八届中国数据库技术大会(DTCC2017)将于2017年5月11-13日如约而至.2017中国数据库技术大会(DTCC)以"数据驱动•价值发现"为主题,汇集来自互联网.电 ...

  4. 图片上传插件用法,net语法【二】

    之前一直写过KindeEditor中的小控件作为单独上次,但业务要求需要另一种方式 现在改用ajaxfileupload.js试试,这个一百度 一.首页引用 <script src=" ...

  5. centos7安装mariadb后无法启动的问题

    MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可.开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险,因此社区采用分支的方 ...

  6. 2、表单form

    只要使用input,就用form,使用方法是在所有的input之外加一个总的form双标签 切记给每个input都加name,提交表单时同时会提交name属性 input可以做的事:文本框.密码框.单 ...

  7. emguCv3.x 实现字符分割,轮廓检测

    /// <summary> /// 获取区域 /// </summary> /// <param name="bitmap"></para ...

  8. jarring type lambda

    object IntStateMonad extendsMonad[({type IntState[A] = State[Int, A]})#IntState] {...}This syntax ca ...

  9. @property (nonatomic, getter = isExpanded) BOOL expanded;

    如果这个property是 BOOL on, 那么Objc默认创建的 setter 为: - (void)on:(BOOL)setOn { } getter 为: - (BOOL)on { retur ...

  10. freemarker(FTL)常见语法大全

    [转载]freemarker(FTL)常见语法大全 FreeMarker的插值有如下两种类型:1,通用插值${expr};2,数字格式化插值:#{expr}或#{expr;format}  ${boo ...