概述

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型只在编译阶段有效。

类型擦除

Java是因为 Java 在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。

  1. List<Integer> list = new ArrayList<>();
  2. list.add(12);
  3. //这里直接添加会报错
  4. list.add("a");
  5. Class<? extends List> clazz = list.getClass();
  6. Method add = clazz.getDeclaredMethod("add", Object.class);
  7. //但是通过反射添加,是可以的
  8. add.invoke(list, "kl");
  9. System.out.println(list);

常用的通配符

  • ? 表示不确定的 java 类型
  • T (type) 表示具体的一个 java 类型
  • K V (key value) 分别代表 java 键值中的 Key Value
  • E (element) 代表 Element

    三种使用方式

    泛型类

    1. //此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
    2. //在实例化泛型类时,必须指定T的具体类型
    3. public class Generic<T> {
    4. private T key;
    5. public Generic(T key) {
    6. this.key = key;
    7. }
    8. public T getKey() {
    9. return key;
    10. }
    11. }

    如何实例化泛型类:

    1. Generic<Integer> genericInteger = new Generic<Integer>(123456);

    泛型接口

    1. public interface Generator<T> {
    2. public T method();
    3. }

    实现泛型接口,不指定类型:

    1. class GeneratorImpl<T> implements Generator<T>{
    2. @Override
    3. public T method() {
    4. return null;
    5. }
    6. }

    实现泛型接口,指定类型:

    1. class GeneratorImpl implements Generator<String>{
    2. @Override
    3. public String method() {
    4. return "hello";
    5. }
    6. }

    泛型方法

    1. public static <E> void printArray(E[] inputArray) {
    2. for (E element : inputArray) {
    3. System.out.printf("%s ", element);
    4. }
    5. System.out.println();
    6. }

    使用:

    1. // 创建不同类型数组: Integer, Double 和 Character
    2. Integer[] intArray = { 1, 2, 3 };
    3. String[] stringArray = { "Hello", "World" };
    4. printArray(intArray);
    5. printArray(stringArray);