泛型是jdk1.5之后出的新语法,他有一个核心,根据这个核心衍生出很多的用法,
核心:帮助用户在编译期就能检测到代码运行期的一些错误
用法:避免手动强转与通用模板
避免手动强转
看一个例子,
在没有泛型之前:
/*** Son extends Father** @author myllxy* @create 2019-12-15 22:04*/
public class GenericTest1 {
public static void main(String[] args) {
testDemo1(new Father());
}
/*** 该方法中参数object是静态类型,静态类型的变化仅仅在使用时发生,* 变量本身的静态类型不会改变,并且最终的静态类型是在编译期可知的;* 而实际类型变化的结果在运行期在可以知道,编译器在编译程序的时候病* 不知道一个对象的实际类型是什么** 所以,在这个案例中我们可以看到,虽然最后报类型转换错误,但是编译期* 不会报错,因为Father确实能够直接向上转型成Object,注意着后面,* (Son)object是在=右边,相当于编译期编译期并不知道object是什么了* 他只是为了通过编码规定将object加了个(Son),但至于是否真的能转换* 看运行期了*/
private static void testDemo1(Object object) {
Son son = (Son) object;
}
}
在有了泛型之后:
/*** Son extends Father** @author myllxy* @create 2019-12-15 22:04*/
public class GenericTest1 {
public static void main(String[] args) {
testDemo1(new Father());
}
/*** 在加上泛型后上面的testDemo1(new Father())就会报错了* 具体T extends Son牵涉到的泛型的协变与逆变问题不在这里赘述了*/
private static void testDemo1(T t) {
Son son = (Son) t;
}
}
这就是泛型,它为我们在编译期就将运行期可能的类型转换错误提前预知出来了,注意它是作用与编译期的,比如我们可以通过反射来绕过泛型的约束,通过反射获取ArrayList的add方法,这个时候你发现即使加了泛型,我也啥都能扔进去:
通用模板
我们先来看看泛型在jdk中的一个经典的用法:
List list = new ArrayList()
list.add("xx")
String xx = list.get(0)
相信这段代码大家都看得懂,
但是在jdk1.5之前你得这么写:
List list = new ArrayList();
list.add("xx");
// 获取到Object,必须强制转型为String:String xx = (String) list.get(0);
所以泛型在这里的作用就是给我的容器指定可以放入的数据的类型E,而我get方法返回的时候就返回这个类型E,就避免了转型的操作可能带来的一系列问题比如类型转换异常等:
如果不使用反省,我们就只能为每一种数据类型设计一种ArrayList,比如StringArrayList,通过这种方式来规避转型问题,
这个ArrayList就是一个模板,哦,应该说是ArrayList,
除开这个例子,模板与泛型结合使用的案例在源码与开发中到处都是:mybatis-plus中的BaseMapper
RedisTemplate
......
关于模板方法设计模式:反正我手长:模板方法模式zhuanlan.zhihu.com