1.什么是泛型
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,
JDK1.5之 后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。
Collection<E>, List<E>, ArrayList<E> 这个<E>就是类型参数,即泛型。
泛型:就是一种不确定的数据类型。
泛型可以省略,如果省略,默认泛型是Object类型。
2.使用泛型的好处是什么?
实际上引入泛型的主要目标有以下几点:
-
- 类型安全
- 泛型的主要目标是提高 Java 程序的类型安全
- 编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常
- 符合越早出错代价越小原则(加入泛型的优点:在编译时期就会对类型进行检查,不是泛型对应的类型就不可以添加入这个集合。)
- 消除强制类型转换
- 泛型的一个附带好处是,使用时直接得到目标类型,消除许多强制类型转换
- 所得即所需,这使得代码更加可读,并且减少了出错机会
- 类型安全
与非泛型代码相比,使用泛型有三大优点:更健壮(在编译时进行更强的类型检查)、更简洁(消除强转,编译后自动会增加强转)、更通用(代码可适用于多种类型)
3.Java的泛型是如何工作的 ? 什么是类型擦除 ?如何工作?
面试官问我:“泛型擦除是什么,会带来什么问题?” - 知乎 (zhihu.com)
- 类型检查:在生成字节码之前提供类型检查
- 类型擦除:所有类型参数都用它们的限定类型替换,包括类,变量,方法(类型擦除)
- 如果类型擦除和多态性发生了冲突时,则在子类中生成桥方法解决
- 如果调用泛型方法的返回类型被擦除,则在调用该方法时插入强制类型转换
- 「Java 路线」| 泛型(含Kotlin) - 简书 (jianshu.com)
类型擦除:
4.为什么擦除后,反编译还是看到类型参数 T
泛型中所谓的类型擦除,其实只是擦除Code 属性
中的泛型信息,在类常量池属性(Signature属性、LocalVariableTypeTable属性)中其实还保留着泛型信息,这也是在运行时可以反射获取泛型信息的根本依据,我在第 4 节说
5.Java中List和原始类型List之间的区别?
原始类型和带参数类型< Object >之间的主要区别:在编译时编译器不会对原始类型进行类型安全检查,却会对带参数的类型进行检查,通过使用Object作为类型,可以告知编译器该方法可以接受任何类型的对象,比如String或Integer
这道题主要考察点在于对泛型中原始类型的正确理解,他们之间的第二点区别是,你可以把任何带参数的类型传递原始类型List,但却不能把List< String >传递给接受List< Object >方法,因为会产生编译错误
上界通配符 < ? extends E>
上届:用 extends 关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。
下界通配符 < ? super E>
下界: 用 super 进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object
在类型参数中使用 super 表示这个泛型中的参数必须是 E 或者 E 的父类。
6.Array中可以用泛型吗?
这可能是java泛型面试中最简单的一个了,当然前提是你要直到Array事实上并不支持泛型,这也是为什么Joshua Bloch在Effective java一书中建议使用List来代替Array,因为List可以提供编译期的类型安全保证,而Array却不能
因为这样做会破坏类型安全
(7 封私信) java为什么不支持泛型数组? - 知乎 (zhihu.com)