一、泛型的简单使用
1、泛型怎么使用
在编写代码的过程中,有的时候,使用泛型类,但有时候忘了(偷懒)没有指定其泛型,很多时候其实并不会报错,但在运行调用指定方法的时候,就会出问题。泛型能够提高自身代码的清晰度,在后期维护代码,他人调用接口的时候,就能方便的识别出泛型类的参数。类型变量使用大写形式,且比较短, 这是很常见的。在 Java 库中, 使用变量 E 表示集合的元素类型, K 和 V 分别表示表的关键字与值的类型。T ( 需要时还可以用临近的字母 U 和 S ) 表示“ 任意类型”。
2、泛型的类型限制
不能确定泛型对象含有相应的方法,因此可以通过extends对其进行限定,规定其只能实现了Demo2方法,这里extends不是继承的extends,只是限定的意思,T可以是Demo2的子类,也可以是实现类,还有Demo2本身限定可以有多个,但只能有一个类(多个接口),但类必须放在第一位。
二、泛型知识进阶
1、泛型和虚拟机
在虚拟机中没有相应的泛型对象,虚拟机中只有普通的类,所有的类都会进行泛型类型擦除,转化成普通类。
2、泛型类型擦除
原始类型的名字就是删去类型参数后的泛型类型名。擦除( erased) 类型变量 , 并替换为限定类型 (无限定的变量用 Object) ,如图:
原始类型用第一个限定的类型变量来替换,如图
但是,有时候你会遇到这样的问题,如图
在本例中,在子类DateInterval有函数void setSecond(LocalDate second)方法,父类Pair中擦除了泛型后,有函数void setSecond(Object second)方法,这两个方法不是同一个方法,不会覆盖,因此,按照常理来说,在DateInterval也会继承参数为Object的方法,这样就会有一个问题,在多态的情况下如下代码
DateInterval interval= new DateInterval();
Pair<LocalDate> pair=interval;
pair.setSecond(aDate);
在Pair中不存在setSecond(LocalDate second)方法,因此只能调用Object参数的方法,但Object的方法没有被重写过,就只能调用Pair中的Object方法,这样泛型和多态就冲突了,为了解决这个冲突,编译器会在DateInterval类中生成桥方法public void setSecond(Object second){setSecond(setSecond((Date) second)}该方法覆盖了父类的方法,在调用的时候,会调用该方法调用了LocalDate方法,这样逻辑就走通了
泛型无法实例化类型变量
public Pair() { first = new T(); second = new T(); }//无法使用
应该要这样使用,如图,在Pair创建一个构造器表达式。
在这里使用了Supplier是函数式接口,有一个get函数,其返回泛型参数T。makePair方法中调用了Pair的有参构造器,实现了泛型的(实例化)。还有一点,在静态方法中,无法使用类的泛型参数,要使用需要自定义泛型参数。