`
chenk008
  • 浏览: 26807 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java 泛型学习--类型通配符

    博客分类:
  • java
 
阅读更多
假设您具有该方法:
void printList(List l) { 
  for (Object o : l) 
    System.out.println(o); 
}

上面的代码在 JDK 5.0 上编译通过,但是如果试图用List<Integer>调用它,则会得到警告。出现警告是因为,您将泛型(List<Integer>)传递给一个只承诺将它当作List(所谓的原始类型)的方法,这将破坏使用泛型的类型安全。
如果试图编写像下面这样的方法,那么将会怎么样?
void printList(List<Object> l) { 
  for (Object o : l) 
    System.out.println(o); 
} 

它仍然不会通过编译,因为一个List<Integer>不是一个List<Object>(正如前一屏泛型不是协变的 中所学的)。这才真正烦人——现在您的泛型版本还没有普通的非泛型版本有用!
解决方案是使用类型通配符:
void printList(List<?> l) { 
  for (Object o : l) 
    System.out.println(o); 
}

上面代码中的问号是一个类型通配符。它读作“问号”。List<?>是任何泛型List的父类型,所以您完全可以将List<Object>、List<Integer>或List<List<List<Flutzpah>>>传递给printList()。

引入了类型通配符,这让您可以声明List<?>类型的变量。您可以对这样的List做什么呢?非常方便,可以从中检索元素,但是不能添加元素(可以添加null)。原因不是编译器知道哪些方法修改列表哪些方法不修改列表,而是(大多数)变化的方法比不变化的方法需要更多的类型信息。下面的代码则工作得很好:
List<Integer> li = new ArrayList<Integer>(); 

li.add(new Integer(42)); 

List<?> lu = li; 

System.out.println(lu.get(0)); 

为什么该代码能工作呢?对于lu,编译器一点都不知道List的类型参数的值。但是编译器比较聪明,它可以做一些类型推理。在本例中,它推断未知的类型参数必须扩展Object。(这个特定的推理没有太大的跳跃,但是编译器可以作出一些非常令人佩服的类型推理,后面就会看到(在底层细节 一节中)。所以它让您调用List.get()并推断返回类型为Object。
另一方面,下面的代码不能工作:
List<Integer> li = new ArrayList<Integer>(); 

li.add(new Integer(42)); 

List<?> lu = li; 

lu.add(new Integer(43)); // error 

在本例中,对于lu,编译器不能对List的类型参数作出足够严密的推理,以确定将Integer传递给List.add()是类型安全的。所以编译器将不允许您这么做。
以免您仍然认为编译器知道哪些方法更改列表的内容哪些不更改列表内容,请注意下面的代码将能工作,因为它不依赖于编译器必须知道关于lu的类型参数的任何信息:
List<Integer> li = new ArrayList<Integer>(); 

li.add(new Integer(42)); 

List<?> lu = li; 

lu.clear(); 
分享到:
评论

相关推荐

    全面总结Java泛型--实例

    Java泛型是Java编程语言的一个强大特性,它允许在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率和安全性。 ### Java泛型概述 Java泛型是在JDK 5中引入的一种新特性,用于创建参数...

    Java泛型通配符

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

    java泛型技术之发展

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

    Java泛型类型擦除后的补偿

    总结来说,Java泛型的类型擦除虽然在运行时消除了类型信息,但通过编译时的类型检查、桥接方法、通配符等补偿机制,仍然实现了强大的类型安全和便利性。开发者应理解这些补偿机制,以便更好地利用Java泛型进行类型...

    Java泛型三篇文章,让你彻底理解泛型(super ,extend等区别)

    Java 泛型中还有一种特殊的类型:通配符类型。通配符类型可以看作是一种特殊的类型,用于表示未知类型。例如: List&lt;?&gt; flist = new ArrayList(); 这里,List&lt;?&gt; 表示“具有任何类型的列表”,编译器无法确定 List...

    java泛型学习全面页面下载资料

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了类型安全性和代码可读性。泛型允许我们在编写代码时指定容器(如集合)可以存储的数据类型,从而在编译阶段就能捕获...

    关于java基础的泛型的练习

    Java泛型是Java SE 5.0引入的一个重要特性,它极大地增强了代码的类型安全性和可读性。泛型在编程中的应用广泛,特别是在集合框架中,使得我们可以在编译时就检查类型,避免了不必要的类型转换,并且提高了代码的...

    java泛型源码-Java-Generics-Tutorial:教程的源代码

    java泛型源码Java泛型用法 步骤1 原始类型有问题。 第2步 使用泛型类型。 第三步 车库和车辆。 原始类型。 第四步 首先尝试生成车库。 木星在我的车库里。 第5步 泛型上限。 第6步 TripleGarage 步骤7 试图使用泛型...

    Java泛型和集合-英文版

    1. Java泛型(Generics):泛型是Java SE 5.0引入的一个新特性,它允许在编译时提供类型检查,并消除类型转换,从而提高代码的可读性和安全性。泛型使得代码能够与多种数据类型一起工作,而不是仅限于原始类型。使用...

    Java 泛型通配符的一个实例

    * 一个参数通配符的实例 * 说明:对一个包含了数值元素的集合进行汇总运算。在这种情况下,用户并不关心 * 集合中的每一个对象是什么类型,只要它是数值型即可,而且,用户也希望集合中可以 * 存放不同类型的数值...

    Java泛型应用实例

    Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...

    java 泛型接口示例

    综上所述,Java泛型接口提供了强大的类型安全性,允许我们在接口中定义通用的方法,并在实现时指定具体的类型。通过类型参数约束、通配符、类型擦除和类型推断等机制,我们可以灵活地设计和使用泛型接口,提高代码的...

    Java泛型_Java中的泛型结构_

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

    java基础-泛型通配符

    java基础-泛型通配符

    Java泛型技术之发展.pdf

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

Global site tag (gtag.js) - Google Analytics