`
toplchx
  • 浏览: 341608 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

泛型定义中的通配符

    博客分类:
  • java
阅读更多
泛型定义中的通配符

List<? extends Number> foo3
 
含义是:变量foo3可以包含任何继承自Number的类型。
以下都是合法的定义:
List<? extends Number> foo3 = new ArrayList<Number>();  //Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>();  //Integer "extends" Number
List<? extends Number> foo3 = new ArrayList<Double>();  //Double "extends" Number
 
因此,考虑到以上可能的定义,什么类型的对象可以被合法的添加到List<? extends Number> foo3中呢?
  • 你不能添加Integer对象,因为foo3可能被定义为 List<Double>。
  • 你不能添加Double对象,因为foo3可能被定义为 List<Integer>。
  • 你不能添加Number对象,因为foo3可能被定义为 List<Integer>。
你不能添加任何对象到List<? extends T>中,因为你不能确定List真正被定义成什么,也就不能确定某个类型是否可以被List接受。
唯一可以确定的是你可以从List中读取一个Number类型的对象或一个Number类型的子类对象。

相反的逻辑也使用于super,如List<? super T>。一下定义都是合法的:
List<? super Number> foo3 = new ArrayList<Number>();  //Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>();  //Object is a "super" of Number
 
你不能从List<? super T>中读取一个特定类型的类(如Number),因为你不能确定List真正被定义成什么。(但是可以读取一个Object对象)
唯一可以确定的是你可以向List添加一个T类型的对象或T类型的超类对象。

一个很好的例子是Collection.copy()的定义:
public static <T> void copy(List<? super T> dest, List<? extends T> src)
 
注意src的定义,用extends允许接受任何值为T类型或T类型的子类型的List,并从中读取值,但你不能向src执行添加操作。
dest的定义,用super允许接受任何值为T类型或T类型的超类的List,并向其写入值,但你不能向dest执行读取操作。

由此,感谢泛型通配符,通过如上的一个定义,我们可以做以下这些调用。
//copy(dest, src)
Collection.copy(new ArrayList<Number>(), new ArrayList<Number());
Collection.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collection.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collection.copy(new ArrayList<Object>(), new ArrayList<Double());


下面做一些练习。被注释掉的代码是错误的
List<Number> listNumber_ListNumber = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>();
//错误 - 只能接受Number类型。
//List<Number> listNumber_ListDouble = new ArratList<Double>();
//错误 - 只能接受Number类型。
List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble  = new ArrayList<Double>();
//错误 - 只能接受Integer类型

List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>();
List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>();

List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListNumber  = new ArrayList<Number>();
//错误 - Number不是Integer的子类
//List<? extends Integer> listExtendsInteger_ListDouble  = new ArrayList<Double>();
//错误 - Double不是Integer的子类

List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>();
//错误 - Integer不是Number的超类
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>();
//错误 - Double不是Number的超类
//List<Integer> listInteger_ListNumber = new ArrayList<Number>();
//错误 - 只能接受Integer类型

List<? super Integer> listSuperInteger_ListNumber  = new ArrayList<Number>();
List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble  = new ArrayList<Double>();    
//错误 - Double is not a superclass of Integer

listNumber_ListNumber.add(3);
//正确 - 允许添加Integer对象到List<Number>中

//下面的代码将出现编译错误。
//他们有相同的原因:你不知道List<T>真正指向那个类,它也许不能处理Integer。
//所以你不能添加任何类(Object, Number, Integer, Double等)到List<? extends Number>
//listExtendsNumber_ListNumber.add(3);
//错误 - 不能添加Integer,list可能是List<Double>,即使List就是被定义为List<Number>也不行。
//listExtendsNumber_ListInteger.add(3);   
//错误 - 不能添加Integer,list可能是List<Double>,即使List就是被定义为List<Integer>也不行。
//listExtendsNumber_ListDouble.add(3);    
//错误 - 不能添加Integer,list可能是List<Double>, 特别是List真的是List<Double>。
//listExtendsInteger_ListInteger.add(3);  
//错误 - 不能添加Integer,list可能是List<X>,它只接受X类型的对象。

listSuperNumber_ListNumber.add(3);
//正确 - 允许添加Integer到List<Number>或者List<Object>
listInteger_ListInteger.add(3);         
//正确 - 允许添加Integer到List<Integer>
listSuperInteger_ListNumber.add(3);     
//正确 - 允许添加Integer到List<Integer>, List<Number>或List<Object>
listSuperInteger_ListInteger.add(3);    
//正确 - 允许添加Integer到List<Integer>, List<Number>或List<Object>
 
总结:
参数和返回类型是:List<Foo>
1、可以作为参数传递给List方法的类型:
  • List< Foo>
2、可以作为List方法结果的类型:
  • List< Foo>
  • List< ? super Foo>
  • List< ? super SubFoo>
  • List< ? extends Foo>
  • List< ? extends SuperFoo>
3、用原生方法可以被写入List的元素类型:
  • Foo & subtypes
4、用原生方法读取List,返回的元素类型:
  • Foo & supertypes (up to Object)
参数和返回类型是:List< ? extends Foo>
1、可以作为参数传递给List方法的类型:
  • List< Foo>
  • List< Subfoo>
  • List< SubSubFoo>
  • List< ? extends Foo>
  • List< ? extends SubFoo>
  • List< ? extends SubSubFoo>
2、可以作为List方法结果的类型:
  • List< ? extends Foo>
  • List< ? extends SuperFoo>
  • List< ? extends SuperSuperFoo>
3、用原生方法可以被写入List的元素类型:
  • None! Not possible to add.
4、用原生方法读取List,返回的元素类型:
  • Foo & supertypes (up to Object)

参数和返回类型是:List< ? super Foo>
1、可以作为参数传递给List方法的类型:
  • List< Foo>
  • List< Superfoo>
  • List< SuperSuperFoo>
  • List< ? super Foo>
  • List< ? super SuperFoo>
  • List< ? super SuperSuperFoo>
2、可以作为List方法结果的类型:
  • List< ? super Foo>
  • List< ? super SubFoo>
  • List< ? super SubSubFoo>
3、用原生方法可以被写入List的元素类型:
  • Foo & supertypes
4、用原生方法读取List,返回的元素类型:
  • Object
分享到:
评论

相关推荐

    泛型讲解 类型通配符

    泛型是Java语言中的一种机制,它允许在定义类、接口时指定类型形参,这个类型形参将在声明变量、创建对象时确定。泛型的引入解决了Java集合的缺陷,即集合会“忘记”对象的类型,导致ClassCastException。 泛型的...

    1.泛型类 、通配符的使用、通配符的上限和下限 编写泛型类Stack<E>,该类中定义一个成员变量和如下方法:

    通过使用泛型,我们可以定义类型参数化的类或方法,从而避免了代码重复并且可以在运行时提供类型检查。 #### 2. 泛型类Stack 在这个实验中,我们需要实现一个泛型类`Stack&lt;E&gt;`。其中`E`表示任何类型的元素。为了...

    Java泛型通配符

    Java泛型通配符是Java编程语言中一个重要的特性,它允许我们在定义泛型类型时使用问号(?)作为占位符,表示任意类型的参数。这种通配符的使用大大提高了代码的灵活性和可复用性,同时也帮助开发者遵循强类型检查的...

    Java 泛型最全指南(定义和使用+继承泛型类/实现泛型接口+泛型的边界+通配符+类型擦除)

    泛型定义是在类、接口或方法中声明类型参数,使用尖括号 `和 `&gt;`括起来。例如,`public class Holder&lt;T&gt; { ... }` 声明了一个名为 `Holder` 的泛型类,类型参数为 `T`。在使用时,可以指定具体的类型,例如 `Holder...

    泛型java的泛型知识,非常有用

    泛型允许我们在类、接口和方法中使用类型参数,这样在编译时期就能检查类型匹配,减少运行时类型转换异常。 1. **泛型的基本概念** - 泛型的本质是在类、接口或方法中使用类型参数,让它们能够处理多种数据类型。...

    泛型&通配符常见面试题总结

    泛型和通配符是Java编程中的重要概念,它们在处理类型安全和代码复用方面起着关键作用。本文将深入探讨这两个主题,并提供一些常见的面试题,帮助开发者理解和掌握这些知识点。 首先,我们来理解泛型。泛型是Java 5...

    十三、集合进阶 泛型的继承和通配符

    本节将深入探讨“集合进阶”中的泛型继承和通配符这两个关键概念。 首先,让我们了解泛型。泛型是Java 5引入的一项特性,它允许在类、接口和方法中使用类型参数,从而实现参数化类型。通过使用泛型,我们可以在编译...

    Java语言 泛型讲解案例代码 (泛型类、泛型接口、泛型方法、无界及上下限通配符、泛型对协变和逆变的支持、类型擦除 ...)

    泛型方法:演示如何在普通类中定义泛型方法,以及如何调用和使用泛型方法。 类型通配符:展示如何使用类型通配符来增加灵活性,以及如何进行类型边界约束。 泛型接口:演示如何定义和实现泛型接口,并通过示例代码...

    关于java的泛型.doc

    在非泛型时代,从集合中获取元素后通常需要进行类型转换,否则会抛出`ClassCastException`。使用泛型后,编译器会在编译时检查类型一致性,从而消除运行时类型转换错误的风险。 ### 总结 Java泛型是一项强大的特性...

    泛型的通配符.java

    允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种...

    Java1.5泛型指南中文版(Java1.5Gene....pdf

    本资源为 Java 1.5 泛型指南中文版的详细笔记,涵盖了泛型的基础知识、泛型类、泛型方法、通配符、擦除和翻译、类型安全、类型参数、实际类型参数、擦除、翻译、转型和 instanceof、数组、Class Literals as Run-...

    Java中的泛型

    #### 泛型定义 泛型是一种抽象概念,它允许你在定义类、接口或方法时使用类型参数。这些类型参数在编译时会被具体的实际类型替换。如果你定义了一个类`MyClass&lt;T&gt;`,这里的`T`就是一个类型参数。当你创建`MyClass`...

    泛型实例详解

    泛型是Java编程语言中的一个重要特性,它允许在定义类、接口和方法时指定类型参数,从而提高了代码的重用性和安全性。在这个“泛型实例详解”中,我们将通过7个具体的实例深入理解泛型的各种应用场景。 1. 普通泛型...

    java泛型[定义].pdf

    除了泛型类,我们还可以定义泛型方法。泛型方法的类型参数声明在方法签名中,例如: ```java public &lt;T&gt; void printList(List&lt;T&gt; list) { for (T item : list) { System.out.println(item); } } ``` 在这个例子...

    Java泛型_Java中的泛型结构_

    Java泛型是Java编程语言中一个强大的特性,它允许在定义类、接口和方法时使用类型参数,从而实现参数化类型。泛型的主要目标是提高代码的类型安全性和重用性,减少类型转换的麻烦,并在编译时捕获可能的类型错误。...

    java泛型指南 经典

    泛型方法可以在非泛型类中定义,并且可以独立于类的其他部分使用泛型。例如: ```java public class Utility { public static &lt;T&gt; void swap(T[] array, int i, int j) { T temp = array[i]; array[i] = array[j]...

    实例189 - 使用通配符增强泛型

    在Java编程语言中,泛型是一种强大的特性,它允许我们在定义类、接口和方法时,引入类型参数,从而实现参数化的类型。实例189 - 使用通配符增强泛型,着重探讨了如何通过通配符来提升泛型的灵活性和可复用性。这个...

    一看就懂 详解JAVA泛型通配符T,E,K,V区别

    在Java中,我们经常会看到一些通配符,例如T、E、K、V等,这些通配符都是Java泛型的通配符,它们的区别在于它们的名称和使用场景。 * T (type):表示不确定的Java类型,通常用作泛型类型参数。 * E (element):代表...

Global site tag (gtag.js) - Google Analytics