泛型

只标记重要的部分


什么是泛型?

泛型即参数化类型,参数化类型就是说将类型由原来具体给定的某一个类型参数化,也就是说现在的类型是一个参数,由这个参数决定到底是什么类型。
JavaSE7及以后,构造函数中可以省略泛型类型:

ArrayList list=new ArrayList<>();

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

class ArrayAlg
{
    public static  T getMiddle(T...a)
    {
        return a[a.length/2];
    }
}

类型变量的限定

public static  T min(T[] a)

表示T是Comparable类型的子类型,一个类型变量或通配符可以有多个限定
限定类型用&分隔,逗号用来分隔类型变量
可以有多个接口超类型,但是限定中至多有一个类。
如果用一个类作为限定,它必须是限定列表中的第一个。


泛型代码和虚拟机

虚拟机没有泛型类型对象---所有对象都属于普通类
在虚拟机中,无论何时定义一个泛型类型,都自动提供了一个相应的原始类型,原始类型的名字就是删去类型参数后的泛型类类名。
Pair的原始类型为Pair

Java泛型转换的事实:

  • 虚拟机中没有泛型,只有普通的类和方法。
  • 所有的类型参数都用他们的限定类型替换
  • 桥方法被合成来保持多态
  • 为保持类型安全性,必要时插入强制类型转换

使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存上只有一个,即还是原来最基本的类型,举个栗子也就是Pair的原始类型为Pair,原因在于java泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦除,也就是说成功编译过后的class文件是不包含任何泛型信息的,泛型信息不会进入到运行阶段,不会进入虚拟机运行阶段。

  • 对此总结成一句话,泛型类型在逻辑上可以看成是多个不同的类型,实际上都是相同的基本类型。

约束与局限性

  • 不能用基本类型实例化类型参数,因此没有Pair,只有Pair
  • 虚拟机中的对象总有一个特定的非泛型类型。因此所有的类型查询只产生原始类型。
  • 试图查询一个对象是否属于某个泛型类型时,倘若使用instanceof会得到一个编译器错误,如果使用强制类型转换会得到一个警告。
  • 不能创建参数化类型的数组
  • 泛型类的静态上下文中类型变量无效
public class Singleton
{
  private static T singleInstance();
}

上述是无效的

  • 既不能抛出也不能捕获泛型类对象,甚至泛型类扩展Throwable都是不合法的
public class Problem extends Exception
  • 一个类或者类型变量不能同时成为两个接口类型的子类,而这两个接口是同一接口的不同参数化。如下
class Employee implements Comparable{}
class Manager extends Employee implements Comparable{}

Manager会实现Comparable和Comparable,这是同一接口的不同参数化。

  • 带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。
  • 通配符不是类型变量,因此不能在代码中使用“?”作为一种类型
  • 此处’?’是类型实参,而不是类型形参 !再直白点的意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。

在逻辑上Box不能视为Box的父类。因为在编译阶段以后会进行类型擦除,都成了Box类

  • 只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

    • 这才是一个真正的泛型方法。
    • 首先在public与返回值之间的必不可少,这表明这是一个泛型方法,并且声明了一个泛型T
    • 这个T可以出现在这个泛型方法的任意位置.
    • 泛型的数量也可以为任意多个
    • 如:public K showKeyName(Generic container){}
  • 类中的泛型方法
    //在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。
    //由于泛型方法在声明的时候会声明泛型,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。
    public void show_3(E t){
    System.out.println(t.toString());
    }
    在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。
    public void show_2(T t){
    System.out.println(t.toString());
    }

  • //在泛型方法中添加上下边界限制的时候,必须在权限声明与返回值之间的上添加上下边界,即在泛型声明的时候添加
    //public T showKeyName(Generic container),编译器会报错:"Unexpected bound"

  • 下面的声明则不会报错
    public T showKeyName(Generic container){

你可能感兴趣的:(泛型)