它可以帮助我们建立类型安全的集合泛型的本质是数据类型的参数化
泛型提供了编译期间检查数据类型,减少数据类型的转换
在类的声明处增加泛型列表,如:

泛型类

  1. // E:表示泛型 泛型E像一个占位符表示未知的数据类型,在调用的时候传入这个数据类型
  2. @Data
  3. @AllArgsConstructor
  4. @NoArgsConstructor
  5. public class Generic<T> {
  6. private T key;
  7. }
  • 泛型类在创建对象时没有指定数据类型,就按照Object类型处理
  • 泛型的类型参数只能是类类型,不能是基本数据类型(因为泛型底层在泛型参数编译时是转换成Object去处理,再转换成传入的数据类型;而Object类是不持有基本数据类型的;可以用它们的包装类;Number类是基本数据类型包装类的父类
  • 同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型

泛型类派生子类

  • 子类也是泛型类,子类的泛型标识要和父类一致;子类可以进行泛型扩展但至少要有一种类型和父类一样 ```java public class GenericSec extends Generic{ }

public class GenericSec extends Generic{ }

  1. - **子类不是泛型类,父类要明确泛型的数据类型**
  2. ```java
  3. public class GenericSec extends Generic<String>{ }

泛型接口

  1. //泛型接口
  2. public interface Genertor <T>{
  3. T getKey();
  4. }
  • 实现类也是泛型类,实现类和接口的泛型类型要一致

    1. //要保证实现接口的泛型类泛型标识包含泛型接口的泛型标识
    2. public class GenericImp<T,E,V> implements Genertor<T>{
    3. @Override
    4. public T getKey() {
    5. return null;
    6. }
    7. }
  • 实现类不是泛型类,接口要明确数据类型

    1. public class GenericImp implements Genertor<String>{
    2. @Override
    3. public String getKey() {
    4. return null;
    5. }
    6. }

泛型方法

泛型方法上面的 是泛型标识,具体类型由调用方法的时候来指定
能用泛型方法解决就不要用泛型类(泛型方法独立于泛型类使用)

  • 只有声明了 的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法(成员方法的泛型遵从泛型类的泛型)
  • < T >表明该方法将使用泛型类型T,此时才可以在方法中或返回值、参数列表内使用泛型类型T

    1. public static <T,E,V> E getPro(List<E> E, T t) {
    2. System.out.println(t);
    3. return E.get(0);
    4. }
  • 泛型方法能使方法独立于类而产生变化

  • 如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法

泛型方法与可变参数

  1. public static <E> E get(E... e){
  2. return e[0];
  3. }

类型通配符

使用 ? 代替具体的实参类型; 类型通配符是类型实参,不是类型形参

通配符的上限

要求该泛型的类型,只能是实参类型或者实参类型的子类型
不能在内部填充元素;(不能确定传入的参数类型)
实例:TreeSet(_Collection<_? extends E_> c)_

  1. public static void show(Generic<? extends Number> generic) {
  2. System.out.println(generic.getKey());
  3. }
  4. Generic<Integer> generic = new Generic<>();
  5. generic.setKey(555);
  6. show(generic);
  7. Generic<Number> generic2 = new Generic<>();
  8. generic2.setKey(222);
  9. show(generic2);

通配符的下限

要求该泛型的类型,只能是实参类型或者实参类型的父类型
可以在内部填充元素(填充实参类型或者子类类型);
遍历元素时用的是Object接收
实例:TreeSet(_Comparator<_? super E_> comparator)_

  1. public static void show(Generic<? Super Integer> generic) {
  2. System.out.println(generic.getKey());
  3. }

类型擦除

泛型信息只存在于代码编译阶段, 编译器对参数的简化 ;在进入JVM编译之前 , 与泛型相关的信息会被擦除

  1. ArrayList<String> list = new ArrayList<>();
  2. ArrayList<Integer> list2 = new ArrayList<>();
  3. //虽然传入数据类型不同,但本质上是同一种类型
  4. System.out.println(list.getClass() == list2.getClass());

无限制类型擦除

泛型参数没有限制,转换成了Object
image.png

有限制类型擦除

泛型参数有限制, 会转换成限制的参数类型
image.png

擦除方法中类型定义的参数

image.png

桥接方法

image.png