【面试题】泛型
泛型是什么
泛型是 Java SE 1.5 的新特性,泛型的本质是参数化类型,这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型的好处
在 Java SE 1.5 之前没有泛型的情况的下只能通过对类型 Object 的引用来实现参数的任意化,其带来的缺点是要做显式强制类型转换,而这种强制转换编译期是不做检查的,容易把问题留到运行时,所以 泛型的好处是在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率,避免在运行时出现 ClassCastException。
Java 泛型是如何工作的?什么是类型擦除?
在JVM中是没有泛型这个概念的,泛型在java中只存在于API层面,也就是编译器层次上,出现的错误也都是编译错误,编译时会进行类型擦除,编译形成的字节码文件中没有泛型,所以Java中的泛型被称为“伪泛型”。
泛型是通过类型擦除来实现的,编译器在编译时擦除了所有泛型类型相关的信息,所以在运行时不存在任何泛型类型相关的信息。泛型擦除具体来说就是在编译成字节码时首先进行类型检查,接着进行类型擦除(即所有类型参数都用他们的限定类型替换,包括类、变量和方法),接着如果类型擦除和多态性发生冲突时就在子类中生成桥方法解决,接着如果调用泛型方法的返回类型被擦除则在调用该方法时插入强制类型转换。
什么是泛型中的限定通配符和非限定通配符
1.限定通配符对类型进行了限制。
有两种限定通配符,一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界,另一种是<? super T>*它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。
关键字 | 限定名称 | 作用 |
---|---|---|
extends | 子类型限定,类型的上界 | 主要用来安全地访问数据,可以访问X及其子类型,可用于的返回类型限定,不能用于参数类型限定 |
super | 父类型限定,类型的下界 | 主要用来安全地写入数据,可以写入X及其子类型可用于参数类型限定,不能用于返回类型限定 |
之所以extends和无限定不能安全的写入,是因为限定之后类型不确定,举个例子:
List<? extends Number> list = new ArrayList<>();中,泛型是Number和Number的子类,可能是Number,也可能是Integer、Double类型,JVM不知道这个泛型究竟是类型。
List<? super Number> list = new ArrayList<>();可以安全写入,泛型是Number和Number的超类,JVM会以最小的子类,也就是Number类为泛型。
import java.util.*;public class Practice_bb { public static void main(String[] args) { List<? super Number> list = new ArrayList<>();//用super来限定可以安全的写入,所以下边的add方法可以 list.add(15); list.add(30); list.add(55.2); list.add(null);//null是在不符合条件的情况下唯一能写入或是读取的元素 }}
import java.util.*;public class Practice_bb { public static void main(String[] args) { List<? extends Number> list = new ArrayList<>(); list.add(15);//报错 list.add(30);//报错 list.add(55.2);//报错 list.add(null);//null是在不符合条件的情况下唯一能写入或是读取的元素 }}
2.<?>表 示了非限定通配符,因为<?>可以用任意类型来替代
List<? extends T>和List <? super T>之间有什么区别
List<? extends T>可以接受任何继承自T的类型的List,而List<? super T>可以接受任何T的父类构成的List。
你可以把List传递给一个接受List参数的方法吗?
对任何一个不太熟悉泛型的人来说,这个Java泛型题目看起来令人疑惑,因为乍看起来String是一种Object,所以 List应当可以用在需要List的地方,但是事实并非如此。真这样做的话会导致编译错误。如 果你再深一步考虑,你会发现Java这样做是有意义的,因为List可以存储任何类型的对象包括String, Integer等等,而List却只能用来存储Strings。
List<Object> objectList;List<String> stringList;objectList = stringList; //compilation error incompatible types
Array中可以用泛型吗?
这可能是Java泛型面试题中最简单的一个了,当然前提是你要知道Array事实上并不支持泛型,这也是为什么Joshua Bloch在Effective Java一书中建议使用List来代替Array,因为List可以提供编译期的类型安全保证,而Array却不能。
JDK 不同版本的泛型有什么区别?
JDK 1.5 引入了泛型来允许强类型在编译时进行类型检查;JDK 1.7 泛型实例化类型具备了自动推断能力,譬如 List list = new ArrayList(); 可以写成 List llist = new ArrayList<>(); 了,JDK 具备自动推断能力。下面几种写法可以说是不同版本的兼容性了:
//JDK 1.5 推荐使用的写法
List list =new ArrayList();
//JDK 1.7 推荐使用的写法
List llist =new ArrayList<>();
//可以使用,但不推荐,是为了兼容老版本,IDE 会提示警告,可以通过注解屏蔽警告
List list =new ArrayList();
//可以使用,但不推荐,是为了兼容老版本,IDE 会提示警告,可以通过注解屏蔽警告
List list =new ArrayList();
参考链接:https://www.jianshu.com/p/918f85dc0932
参考链接: https://blog.csdn.net/yxueny/article/details/84653247