泛型

泛型就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的
回值及参数类型

泛型的作用:一种安全机制,它可以帮助我们建立类型安全的集合
其通过<>声明给编译器,只能往内部存储某种数据的元素。
<>用于接收具体引用数据类型的参数范围

泛型 - 图1

  • 泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。




    泛型的擦除:
    类型擦除指的是在Java泛型程序运行过程中出现的类型被转换为Object或者其限定类型的现象。

例如:

  1. Class<?> c1 = new ArrayList<String>().getClass();
  2. Class<?> c2 = new ArrayList<Integer>().getClass();
  3. System.out.println(c1 == c2); // true

虽然泛型类的参数不同,但是结果却是TRUE。
这是因为在泛型代码内部,无法获得任何有关泛型参数类型的信息。

所有的泛型类型在运行过程中都会被擦除。这意味着当你在使用泛型时,你唯一知道的是你在使用一个对象。因此List和List在运行时事实上都被擦除成原生的List类型。




泛型的补偿:
在运行时,需要通过获取元素的类型进行转换工作,我们无需使用者再强制转换。
因为泛型会通过getClass取到集合内部数据类型,然后帮我们进行强转
泛型 - 图2



泛型的约定规范
泛型 - 图3

  • 当一个泛型类声明了定义泛型参数时,我们就需要往里面传所需要的类型参数
  • 如果指定,默认是object类型




    泛型类

    在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态 属性的类型、参数类型、返回值类型。
    但在静态方法 中不能使用类的泛型。

根据工具类写实现类时,就可以往泛型参数里面传入想要实例化的类。还可以省略强转

泛型 - 图4



泛型方法

泛型方法一般用于泛指,就是说 设置了一个通用的返回值类型

  • 泛型方法跟指定Object类型的区别:引用了Object数据类型,就只能使用Object定义的方法
  • 而泛型,可以实现多参数传入(实现多个类型的方法)。

注:泛型类和泛型方法直接没有关系 ,泛型方法仅仅是指在方法中出现了泛型的结构,泛型参数与类的泛型参数没任何关系。

  1. //泛型方法,可以声明为静态的。
  2. public static <E> List<E> copyFromArrayToList(E[] arr){
  3. ArrayList<E> list = new ArrayList<>();
  4. for(E e : arr){
  5. list.add(e);
  6. }
  7. return list;
  8. }
  9. }


泛型的通配符“?”

当不明确想要声明的引用数据类型时,就可以使用通配符 ?
使得所有的引用数据类型都能匹配 (或者说,引用的数据类型都是object)

泛型限定:

泛型限定是用于泛型扩展使用的。其中包含了多态的思想。

限定继承

使用 <? extends E > 来限定通配符的范围,表示只接收E类型或者E的子类型对象。

举例:
泛型 - 图5

由于定义了T泛型的变量,但由于我们需要进行比较,所以,需要该变量类型实现Comparable接口,但是,我们却无法对类型做出任何继承操作。
所以,此时我们应该进行泛型限定。


限定父类

使用 <? super E > 来限定通配符的范围,表示只接收E类型或者E的父类类型对象
可以同时进行多种限定

例如: T extend Comparable & Serializable