背景:泛型这个知识点平时用的很少,可是在面试的时候很容就被问到,因此仍是要准备一些基础的知识储备。java
“泛型” 意味着编写的代码能够被不一样类型的对象所重用。编程
泛型是在JDK1.5以后出现的。数组
泛型的本质是参数化类型,也就是说所操做的数据类型被指定为一个参数。安全
能够看到,使用 Object 来实现通用、不一样类型的处理,有这么两个缺点:性能
根据《Java 编程思想》中的描述,泛型出现的动机在于:spa
有许多缘由促成了泛型的出现,而最引人注意的一个缘由,就是为了建立容器类。.net
实际上引入泛型的主要目标有如下几点:翻译
泛型类 code
泛型接口
泛型方法
无限制通配符
extends 关键字声明了类型的上界,表示参数化的类型多是所指定的类型,或者是此类型的子类
super 关键字声明了类型的下界,表示参数化的类型多是指定的类型,或者是此类型的父类
经过上面的例子咱们能够知道,无限制通配符 < ?> 和 Object 有些类似,用于表示无限制或者不肯定范围的场景。
两种有限制通配形式 < ? super E> 和 < ? extends E> 也比较容易混淆,咱们再来比较下。
ps:上下限用图说明
它们的目的都是为了使方法接口更为灵活,能够接受更为普遍的类型。
用《Effective Java》 中的一个短语来加深理解:
为了得到最大限度的灵活性,要在表示 生产者或者消费者 的输入参数上使用通配符,使用的规则就是:生产者有上限、消费者有下限:
PECS: producer-extends, costumer-super
所以使用通配符的基本原则:
小总结一下:
Java 中的泛型和 C++ 中的模板有一个很大的不一样:
(摘自:blog.csdn.net/fw0124/arti…)
在 Java 中,泛型是 Java 编译器的概念,用泛型编写的 Java 程序和普通的 Java 程序基本相同,只是多了一些参数化的类型同时少了一些类型转换。
实际上泛型程序也是首先被转化成通常的、不带泛型的 Java 程序后再进行处理的,编译器自动完成了从 Generic Java 到普通 Java 的翻译,Java 虚拟机运行时对泛型基本一无所知。
当编译器对带有泛型的java代码进行编译时,它会去执行类型检查和类型推断,而后生成普通的不带泛型的字节码,这种普通的字节码能够被通常的 Java 虚拟机接收并执行,这在就叫作 类型擦除(type erasure)。
当类中要操做的引用数据类型不肯定的时候,过去使用 Object 来完成扩展,JDK 1.5后推荐使用泛型来完成扩展,同时保证安全性。
1.上面说到使用 Object 来达到复用,会失去泛型在安全性和直观表达性上的优点,那为何 ArrayList 等源码中的还能看到使用 Object 做为类型?
根据《Effective Java》中所述,这里涉及到一个 “移植兼容性”:
泛型出现时,Java 平台即将进入它的第二个十年,在此以前已经存在了大量没有使用泛型的 Java 代码。人们认为让这些代码所有保持合法,而且可以与使用泛型的新代码互用,很是重要。
这样都是为了兼容,新代码里要使用泛型而不是原始类型。
2.泛型是经过擦除来实现的。所以泛型只在编译时强化它的类型信息,而在运行时丢弃(或者擦除)它的元素类型信息。擦除使得使用泛型的代码能够和没有使用泛型的代码随意互用。
3.若是类型参数在方法声明中只出现一次,能够用通配符代替它。
好比下面的 swap 方法,用于交换指定 List 中的两个位置的元素:
private void swap(List list, int i, int j) { //... }
只出现了一次 类型参数,没有必要声明,彻底能够用通配符代替:
private void swap(List list, int i, int j){ //... }
对比一下,第二种更加简单清晰吧。
4.数组中不能使用泛型
这多是 Java 泛型面试题中最简单的一个了,固然前提是你要知道 Array 事实上并不支持泛型,这也是为何 Joshua Bloch 在 《Effective Java》一书中建议使用 List 来代替 Array,由于 List 能够提供编译期的类型安全保证,而 Array 却不能。
5.Java 中 List
和原始类型 List
之间的区别?
原始类型和带参数类型 之间的主要区别是:
这道题的考察点在于对泛型中原始类型的正确理解。
ps:这个地方还没理解。。。。