zoukankan      html  css  js  c++  java
  • Java基础语法<十二> 泛型程序设计

    1 意义

    泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用

    常见应用 : ArrayList

    2 K T V E ? object等的含义

    类型变量使用大写形式

    E – Element (在集合中使用,因为集合中存放的是元素)

    T – Type(Java 类)(需要时还可以用临近的字母U和S)表示任意类型  S、U、V – 2nd、3rd、4th types

    K – Key(键)

    V – Value(值)

    N – Number(数值类型)

    ? – 表示不确定的java类型(无限制通配符类型)

    Object – 是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。

    3 泛型方法

    public static <T> T getXXX(){

    }

    类型变量放在修饰符的后面,返回类型的前面

    变量类型的限定

    <T extends Comparable> T

    一个类型变量或通配符可以有多个限定

    T extends Comparable & Serializable

    限定类型用&分隔,逗号用来分隔类型变量

    在Java的继承中,可以根据需要拥有的多个接口超类型,但限定中至多有一个类,如果用一个类作为限定,它必须是限定列表中的第一个。

    4 泛型代码和虚拟机

    Java中的泛型基本上都是在编译器这个层次来实现的。

    生成的Java字节代码中是不包含泛型中的类型信息的。

    使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。 其实编译器通过Code sharing方式为每个泛型类型创建唯一的字节码表示,并且将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类形实例映射到唯一的字节码表示是通过类型擦除(type erasue)实现的。

    无论何时定义一个泛型类型,都自动提供一个相应的原始类型(raw type)。原始类型的名字就是删除类型参数后的泛型类型名。擦除(erased)类型变量,并替换为限定类型(无限定的变量用Object)

    4.1 类型擦除

    类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。 类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。

    类型擦除的主要过程如下:

    1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。

    2.移除所有的类型参数。

    PS:

    1.虚拟机中没有泛型,只有普通类和普通方法,所有泛型类的类型参数在编译时都会被擦除,泛型类并没有自己独有的Class类对象。比如并不存在List<String>.class或是List<Integer>.class,而只有List.class。

    2.创建泛型对象时请指明类型,让编译器尽早的做参数检查(Effective Java,第23条:请不要在新代码中使用原生态类型

    3.不要忽略编译器的警告信息,那意味着潜在的ClassCastException等着你。

    4.静态变量是被泛型类的所有实例所共享的。对于声明为MyClass<T>的类,访问其中的静态变量的方法仍然是 MyClass.myStaticVar。不管是通过new MyClass<String>还是new MyClass<Integer>创建的对象,都是共享一个静态变量。

    5.泛型的类型参数不能用在Java异常处理的catch语句中。因为异常处理是由JVM在运行时刻来进行的。由于类型信息被擦除,JVM是无法区分两个异常类型MyException<String>和MyException<Integer>的。对于JVM来说,它们都是 MyException类型的。也就无法执行与异常对应的catch语句。

    5 泛型转换

    Java虚拟机中没有泛型,只有普通的类和方法

    所有的类型参数都用它们的限定类型替换

    桥方法被合成来保持多态

    为保持类型安全性,必要时插入强制类型转换

    6 约束与局限性

    • 不能用基本类型实例化类型参数
    • 运行时类型查询只适用于原始类型
    • 不能创建参数化类型的数组
    • Varargs警告
    • 不能实例化类型变量
    • 泛型类的静态上下文中类型变量无效
    • 不能抛出或捕获泛型类的实例
    • 注意擦除后的冲突

    7 通配符类型

    7.1 extends <? extends T> 

    表示类型的上界,表示参数化类型的可能是T 或是 T的子类

    7.2 超类型限定 super <? super T >

    表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Object

    带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。

    7.3 无限定通配符 <?>

    ps:

    如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)

    如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)

    如果既要存又要取,那么就不要使用任何通配符。

    8 tag问题

    8.1 什么是泛型、为什么要使用以及泛型擦除

    泛型,即“参数化类型”。
    创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。
    Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。泛型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。
    类型擦除的主要过程如下:
    1).将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
    2).移除所有的类型参数。

     

  • 相关阅读:
    python二进制转换
    git的使用
    c++primer plus笔记
    c++primer 学习笔记
    二分查找
    字符串全排列
    斐波那契数列
    JavaScript 相关
    HTTP记录
    前端笔记
  • 原文地址:https://www.cnblogs.com/loveincode/p/7207594.html
Copyright © 2011-2022 走看看