1 简述你对泛型的理解
泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。
泛型可以用在如下地方:
- 泛型方法
- <? extends T>表示通配符所代表的类型是T类型的子类;<? super T>表示通配符所代表的的类型是 T 类型的超类。
- 泛型类
- 声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
-
2 泛型标识符含义
Collection、Enum:E element 元素,在 Collection 中应用
- Map
: K,V key,value 键值,在 Map 中应用 Class: T Type 类型,在 Java 类中应用
- N - Number(数值类型)
- ? - 表示不确定的java类型(通用类型)
- S、U、V - 2nd、3rd、4th types
类型通配符的上限:< ? extends Number > :泛型值接受 Number 及其下层子类类型实现。
- 类型通配符下限: < ? super Number> : 类型只能接受 Number 及其上层父类类型。
3 为什么要引入泛型
引入泛型是为了让多种数据类型执行相同的代码(代码复用)。
可以看一个简单的例子: ```java package org.example;
import java.util.ArrayList; import java.util.List;
// 泛型简单示例 public class GenericTest1 { public static void main(String[] args) { Show1 show1 = new Show1(); Show2 show2 = new Show2(); // 非泛型方法需要为每个类型都指定一个重载方法 System.out.println(show1.add(1, 2)); System.out.println(show1.add(1.0f, 2.0f)); System.out.println(show1.add(1.0, 2.0));
System.out.println("===============");
// 泛型方法可以复用一个方法,具体参数类型在调用方法的时候确定
System.out.println(show2.add(1, 2));
System.out.println(show2.add(1.0f, 2.0f));
System.out.println(show2.add(1.0, 2.0));
}
// 如果没有使用泛型,那么不同类型的加法,需要若干个重载方法
static class Show1 {
private int add(int a, int b) {
//System.out.println(a + "+" + b + "=" + (a + b));
System.out.println("------int-------");
return a + b;
}
private float add(float a, float b) {
//System.out.println(a + "+" + b + "=" + (a + b));
System.out.println("------float---------");
return a + b;
}
private double add(double a, double b) {
//System.out.println(a + "+" + b + "=" + (a + b));
System.out.println("--------double-------");
return a + b;
}
}
// 通过泛型,可以复用一个方法
static class Show2 {
private <T extends Number> double add(T a, T b) {
System.out.println("----------------");
return a.doubleValue() + b.doubleValue();
}
}
}
使用了泛型,之后就不需要进行强制类型转换(类型安全,编译器会检查类型)。
```java
package org.example;
import java.util.ArrayList;
import java.util.List;
public class GenericTest2 {
public static void main(String[] args) {
// 不使用泛型,强制转换可能存在问题
List list = new ArrayList();
list.add(123);
list.add("123");
for (int i = 0; i < list.size(); i++) {
String s = (String) list.get(i);
System.out.println(s); //会报错:java.lang.Integer cannot be cast to java.lang.String
}
// 使用泛型指定类型后,非法类型将无法使用
List<String> list2 = new ArrayList<>();
// list2.add(123); // 编译阶段就直接报错
list2.add("123");
}
}
4 泛型擦除
Java 中的泛型基本上都是在编译器这个层次来实现的。在生成的 Java 字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。
比如在代码中定义的 List
package org.example;
import java.util.ArrayList;
import java.util.List;
// 泛型擦除
public class GenericTest3 {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
Class<? extends List> stringListClass = stringList.getClass();
Class<? extends List> integerListClass = integerList.getClass();
if (stringListClass.equals(integerListClass)) {
System.out.println("泛型擦除");
}
}
}
5 泛型类、泛型接口、泛型方法
请参考:java 泛型详解