泛型是Java 5开始引入的一个语言级别的特性,目的是为了让你的程序更为可靠(reliable)。
程序总是有bug,而bug分为编译时bug和运行时bug,编译时bug是比较令人舒服的bug,因为大部分的IDE比如eclipse,就能让你在写代码的时候就能发现并及时fix。但是运行时bug就很难受了,必须在运行时的某个条件下才能出现,当你想去找它的时候还不一定那么好找,尤其是多线程环境下的bug,更难重现。我们如果能尽量使bug可以在编译时发现,那就再好不过了。
泛型的引入就是为了让你尽量在编译时就发现某些类型的bug。典型的例子就是Collection类,如果你在用Collection的时候放入的对象的类型不匹配,编译器就能告诉你,要不然,得在运行时才能发现。
这个问题的核心在于强制类型转换。既然是强制类型转换,就存在转换失败的可能,比如你想将String强转成Integer,就是出强制类型转换失败的错误。作为容器类,或者说集合类,如果对放入容器的对象编译器不做类型检查,那就只能到运行的时候检查了,这显然不利于发现bug。通过Generic,编译器就可以知道容器里应该放入对象的类型,那么,编译器就能帮我们发现这类bug了。所以,当你用强制类型转换的时候,你就得考虑是否需要设计Generic来保护你的程序不会发生ClassCastException。
泛型本质上是将类型作为参数,类,接口和方法的定义中都可以带有这种参数。也可以这样想,你可以在定义类,接口和方法的时候,加上某个或某几个参数,而这个参数必须得是某个类或者接口。这样定义了类或者接口以后,当别的类使用这些类或接口的时候就得带上具体的类型(当然也可以不带,但是不推荐这样)。
下面看一个例子:
package jdk.generic;
class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
class BoxClient {
public static void fillBox(Integer o, Box<Integer> box) {
System.out.println("fillBox Integer");
box.add(o);
}
public static <U> void fillBox(U u, Box<U> box) {
System.out.println("fillBox U");
box.add(u);
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.add(new Integer(10));
fillBox(1, integerBox);
Box<String> stringBox = new Box<String>();
fillBox("abc", stringBox);
BoxClient.<Integer>fillBox(1, integerBox);
}
}
这个例子定义了一个容器类Box,里面可以放一个任意类型的对象,但是你得在new这个容器的时候声明你到底要放什么类型的对象在里面。
BoxClient类里面定义了两个fillBox方法,其中一个就是参数化的方法定义。没有这个定义能力你就得像那个传入Integer方法一样,一一列举你要传入的类型。
有意思的是,在29行,调用的是哪一个呢?因为两个fillBox方法都能符合?看看输出你就知道了。你也可以试一试把第一个fillBox方法删除,在运行一下看看。
实际上,你大可以删除第一个fillBox方法。
输出:
fillBox Integer
fillBox U
fillBox U
泛型只是为了让编译器帮我们找到类型上的错误,在编译以后生成的class文件里面并没有泛型的概念,也就是说,下面的使用是不合法的:
public void myMethod(Object item) {
// Compiler error
if (item instanceof T) {
}
T item2 = new T(); // Compiler error
T[] iArray = new T[10]; // Compiler error
}
[b]
使用陷阱(pitfall)[/b]
1. 泛型不是协变的(covariant)
Java里面的数组是协变的。我们知道Integer是Number的子类,那么Integer[]是不是Number[]的子类呢?答案是肯定的。这就是协变的意义所在。
那么List<Integer> 是不是 List<Number>的子类呢?不是的。也就是泛型没有协变性。
这样,你就不能把List<Integer>变量赋值给List<Number>变量。看下面的例子:
public class Covariant {
public static void main(String[] args) {
Integer[] i = new Integer[1];
Number[] n = i; //legal
List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li;//illegal
ln.add(new Float(3.1415)); //legal
li.add(new Float(3.1415)); //illegal
}
}
如果ln=li可以的话,那么它的下一句类型的转化就有问题了,相当于将Float强转给Integer了。这样也就破坏了
Generic用来保证类型安全的意义了。
[url]
http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html[/url]
[url]
http://www.ibm.com/developerworks/java/tutorials/j-generics/section6.html[/url]
分享到:
相关推荐
在Java编程语言中,泛型(Generic)是一个强大的特性,它允许我们在编译时检查类型安全,并且可以消除运行时的类型转换。泛型引入的主要目的是提高代码的重用性、安全性和效率,同时减少类型转换的繁琐工作。这篇...
对于不熟悉类似概念的新手来说,这是一个从零开始学习的好机会,可以避免被其他语言的概念误导。 #### 定义简单的泛型 在Java中,泛型允许开发者抽象出类型,最典型的例子是容器类型,比如`Collection`层次结构中...
在基础知识方面,本资源涵盖了变量、循环、分支、数组、常用类、I/O Stream、Collection/Generic、Thread、TCP/UDP、GUI、Meta Data等知识点。 在面向对象编程方面,本资源强调了面向对象是最重要的,涵盖了对象、...
示例描述:本章学习Java的输入和输出。 CopyFile.java 文件复制实例 dir.java 显示目录下的所有文件和目录 encrypt.java 文件加密 FileList.java 自己实现的一个文件名称枚举类 MyDataIO.java 数据输入输出示例...
### Java基础学习词汇详解 #### Abstract (抽象) 在Java中,`abstract`是一个关键字,用于定义抽象类或抽象方法。抽象类是不能被实例化的类,通常用来作为其他类的基础框架,提供了一些基本功能实现的同时,也定义...
Java泛型是Java编程语言中的一个特性,它允许在定义类、接口和方法时使用类型参数,从而增强了代码的重用性、安全性和效率。在Java中,泛型的引入是为了提供编译时类型安全检查,并减少在运行时进行类型转换的需要。...
Java编程语言是面向对象的编程语言,学习Java的过程中掌握一些核心的英语单词是十分必要的,因为许多编程概念和关键字都是英文原词。以下是一些重要的Java相关英语词汇及其详细解释: 1. **abstract** - 抽象:在...
Java Bluetooth API.pdf文档可能包含了这些概念的详细解释、示例代码以及API参考,是学习和开发蓝牙应用的重要资源。建议仔细阅读该文档,结合实践来提升蓝牙编程能力。通过熟练掌握Java蓝牙API,你可以开发出各种...
在Java编程中,连接到微软数据库,如...总的来说,这个"java链接微软数据库包"是Java开发者,尤其是初学者连接SQL Server数据库的必备工具,通过它,他们可以学习和实践JDBC技术,进而实现Java程序与数据库的高效交互。
【Japag - Java generic command line GUI 开源项目详解】 Japag,全称为 Java Application for Providing a Generic GUI,是一个开源项目,专为那些希望通过图形用户界面(GUI)而非命令行来运行各种命令行应用...
Java虚拟机(JVM)是Java程序运行的核心组件,它为Java代码提供了跨平台的运行环境。Java SE 7(Java Standard ...这份文档是Java开发者必备的学习资料,无论你是初学者还是经验丰富的程序员,都能从中受益匪浅。
本篇学习笔记将围绕Java JDK 6的关键特性、语法改进、API更新以及开发实践进行详细讲解。 1. **Java JDK 6概述** - JDK(Java Development Kit)是Java开发的核心组件,包含了Java运行环境(JRE)、编译器(javac...
Java JDK 7是Java开发工具集的一个重要版本,它在Java SE(标准版)平台中引入了许多新特性,对开发者来说具有重要的学习价值。本学习笔记聚焦于这一关键版本,旨在帮助读者深入理解和掌握Java 7的核心技术。下面将...
通过深入学习和理解Java 1.7英文API,开发者可以更高效地编写代码,充分利用Java 7的新特性,并提升自己的编程能力。同时,阅读英文API也有助于跟踪最新的技术发展,为未来接触更高级的Java版本做好准备。
JAVA还提供了泛型(Generic)来增强集合的安全性,避免类型转换异常。同时,接口如List、Set和Map定义了集合的基本操作,而Collections类提供了对集合的静态方法,如排序、填充和搜索等。此外,JAVA的并发集合如...
以上是Spring和Java学习笔记中涉及的一些关键知识点,这些知识对于理解和使用Spring框架进行开发至关重要。此外,附录中提供的方法表可以帮助深入理解和记忆Java中常用类和接口的方法,进一步提升编程能力。
10. **Type inference for generic instance creation**:Java8改进了类型推断,使得创建泛型实例更加简洁,如`List<String> list = new ArrayList();` 以上就是Java8的一些主要新特性,它们不仅增强了Java的表达力...
通过深入学习这本书,你可以掌握Java 7中的新特性,优化你的代码,并提升开发效率。下面将详细探讨Java 7中的关键知识点。 1. **自动资源管理(try-with-resources)** Java 7引入了自动资源管理,它允许你在`try`...