之前面试和这两天用到泛型解决了一些问题,才发现自己对泛型的了解只停留用的时候会想起来一点点....没有真正的准确梳理泛型,所以想写一写总结一下自己对泛型对理解
1、代码用泛型的好处
在写代码的时候经常不同数据类型,而泛型可以统一数据类型,便于操作。
将运行时的异常提前到了编译时,提高了效率(在jdk1.5中引入了新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法类型)。
避免了强制类型转换。
实现代码到模版化,把数据类型当作参数传递,提高了可重用性。
2、泛型
泛型,其实是"参数化类型"。泛型的本质是参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。换句话说在泛型使用过程中,操作数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别成为泛型类,泛型参数,泛型方法。
在jdk 1.5之前,没有泛型的情况下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,这种转换需要开发者对实际参数类型可以预知的情况下进行。对于强制类型转换错误的情况,编译气可能不提示错误,在运行的时候才出现异常。这时候泛型的好处就体现出来,使用泛型就可以首先通过IDE进行代码类型初步检测,然后在编译阶段进行编译类型检查,保证了类型转换的安全性;并且所有的强制转换都是自动和隐式的,可以提高代码重用率。
泛型是一种把类型的明确工作推迟到创建对象或者调用方法的时候才去明确的特殊类型。
注意:类型参数只能代表引用类型,不能是原始类型(int,double,char等)。
3、泛型类、泛型方法、泛型接口
泛型类: class 类名称 <泛型类型标识>{} 如:public class User<T>{}
/** * Created by mhSui on 2019/09/23. * * @author mhSui */ public class Generics<T>{ private T data; public void setData(T data){ this.data = data; } public T getData(){ return data; } }
注意:一旦在类上声明泛型,在类里面所有非静态成员都可以使用。
泛型方法:[作用域修饰符] <泛型类型标识> [返回类型] 方法名称(参数列表){} 如:public <T> 返回值 方法名(T a){}
public <E> void show(E s ) { System.out.println(s);}
方法上的泛型和类上的泛型很像,唯一不同的是类型的作用域不同。
在jdk 1.7之后,编译器可以通过type inference(类型推导),根据实参的类型自动推导出相应的类型参数。
泛型接口:与泛型类的定义很相似。
实现接口的时,声明类的同时,需要将泛型的声明也一起放在类中。我们可以为泛型传入任意实参,形成不同类型的接口。
4、泛型通配符
想象一下一个场景:Ingeter是Number的一个子类,由于泛型擦除的存在,对于编译器来说Generic<Ingeter>与Generic<Number>实际上是同一种基本类型。那么,使用Generics<Number>作为形参方法中,能否使用Generics<Integer>的实例传入呢?结果会发现:同一种泛型可以对应多个版本(因为参数类型是不确定的),而不同版本的泛型类实例之间是不兼容的。
<?>:类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类
<? extends T>:向下限定,只能是T及其子类,泛型上限。
<? super T>:向上限定,只能是T及其父类,泛型下限。
5、类型擦除
类型擦除就是说Java泛型只能用于在编译期间的静态类型检查,然后编译器生成的代码会擦除相应的类型信息,这样到了运行期间实际上JVM根本就知道泛型所代表的具体类型。这样做的目的是因为Java泛型是1.5之后才被引入的,为了保持向下的兼容性,所以只能做类型擦除来兼容以前的非泛型代码。
6、不允许使用泛型的场景
a) 不能是静态的类型
public class GenericsExample<T> { private static T member; //This is not allowed }
b) 不能创建T的实例
public class GenericsExample<T> { public GenericsExample(){ new T(); } }
c)在声明时不能和原生类型一起使用
final List<int> ids = new ArrayList<>(); //不允许 final List<Integer> ids = new ArrayList<>(); //允许
d) 不能创建泛型的异常类
// 引起编译错误 public class GenericException<T> extends Exception {}