泛型定义以及其带来的好处
泛型使类型(类和接口)能够在定义类、接口和方法时成为参数。与方法声明中使用的更熟悉的形式参数非常相似,类型参数为您提供了一种通过不同输入重复使用相同代码的方法。区别在于形式参数的输入是值,而类型参数的输入是类型。
使用泛型的代码比非泛型代码有很多好处:
-
编译时更强的类型检查。 Java 编译器对泛型代码应用强类型检查,如果代码违反类型安全,则会发出错误。修复编译时错误比修复运行时错误更容易,后者很难发现。
-
避免类型转换
以下没有泛型的代码片段需要强制转换:
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
当重写为使用泛型时,代码不需要转换:
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
- 使程序员能够实现通用算法。 通过使用泛型,程序员可以实现适用于不同类型集合的泛型算法,可以自定义,并且类型安全且更易于阅读。
绕过泛型定义
使用反射
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
Class clazz = Class.forName("java.util.ArrayList");
Method method = clazz.getMethod("add", Object.class);
method.invoke(list, 123);
System.out.println(list);
}
输出结果:
[aa, bb, 123]
注意:
如果通过循环遍历输出list的元素,比如
for(String str : list) {
System.out.println(str);
}
或者
list.stream().forEach(p -> System.out.println(p));
就会报错:
aa
bb
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at com.springcloud.business.controller.BusinessController.main(BusinessController.java:45)
这是因为遍历的时候,会把集合里的元素拿出来,作为泛型定义的String
类型输出,而我们通过反射添加了一个Integer
类型的值,因此造成类型转换错误。
除非我们这样遍历输出:
for(Object str : list) {
System.out.println(str);
}
输出结果:
aa
bb
123