泛型定义以及其带来的好处

泛型使类型(类和接口)能够在定义类、接口和方法时成为参数。与方法声明中使用的更熟悉的形式参数非常相似,类型参数为您提供了一种通过不同输入重复使用相同代码的方法。区别在于形式参数的输入是值,而类型参数的输入是类型。

使用泛型的代码比非泛型代码有很多好处:

  1. 编译时更强的类型检查。 Java 编译器对泛型代码应用强类型检查,如果代码违反类型安全,则会发出错误。修复编译时错误比修复运行时错误更容易,后者很难发现。
  1. 避免类型转换

以下没有泛型的代码片段需要强制转换:

1
2
3
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

当重写为使用泛型时,代码不需要转换:

1
2
3
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
  1. 使程序员能够实现通用算法。 通过使用泛型,程序员可以实现适用于不同类型集合的泛型算法,可以自定义,并且类型安全且更易于阅读。

绕过泛型定义

使用反射

1
2
3
4
5
6
7
8
9
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);
}

输出结果:

1
[aa, bb, 123]

注意:

如果通过循环遍历输出list的元素,比如

1
2
3
for(String str : list) {
System.out.println(str);
}

或者

1
list.stream().forEach(p -> System.out.println(p));

就会报错:

1
2
3
4
5
6
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类型的值,因此造成类型转换错误。

除非我们这样遍历输出:

1
2
3
for(Object str : list) {
System.out.println(str);
}

输出结果:

1
2
3
aa
bb
123
⬆︎TOP