【Java学习】泛型
面向对象系列八
一、泛型类变量
二、泛型实现
1.编译检查
2.类型擦除
3.泛型效果
三、类型检查
1.向上转型相关:
2.数组相关:
四、extend
1.非泛型下:
2.泛型中:
一、泛型类变量
一个类变量对里面位置引用变量的类型通泛性,每创的一次似复刻变量就能对应实现那一种的引用类型的那一套,一个类变量能通泛性地创它里面位置引用变量所有类型的似复刻变量,对它里面位置引用变量的类型是泛性的所有类型的都能实现的,这种它里面对应位置引用变量全类型都能针对实现的类变量就是泛型类变量,一个模板它能对应去创所有引用类型套的但去实现时是一次只能实现一种套的那种不太泛的泛型
二、泛型实现
1.编译检查
创泛型类变量的似复刻变量,编译检查时,将这个创的似复刻变量去对应实现的具体那某引用类型套的似复刻变量引用去对应替换到里面泛型对的的位置引用变量T上来进行检查的,这样替换后的检查能实现对应具体类型在对应具体编译检查要求下去实现,对实现具体某一个引用类型套有了对应的编译检查保障,确保了外界使用能进来后的数据一定是此T类型下的数据
2.类型擦除
对进来后的数据进行编译检查通过后,将此泛型类变量里面的T引用变量全部擦除为Object类变量的似复刻变量引用,将外部代码里调用使用此泛型类变量里以T引用变量为返回值的方法的调用返回值处隐式加上对应实现的具体引用类型的强转,之后去运行,会发现在泛型类变量里面,
3.泛型效果
执行操作的一直都是Object类的似复刻变量,外界引用进来都是向上转型成Object类似复刻变量引用进来的,它通过编译类型检查指定确定了使用进入此泛型类变量里向上转型为Object类的似复刻变量的原下子类类型,对已知其下原子类类型的Object类似复刻变量在作为此泛型类变量里方法返回值处的对应去外部调用它处插入强转能对应向下转型回已知原子类类型的指定引用回来在外部,这样就实现了泛型类变量内部用所有类统一能用的Object父类来共用,外部不同类的使用处又能对应针对到各自不同的外部引用类,达到所有类都能使用且是全效果地使用它的泛型效果
三、类型检查
- 明确安全的转化正常直接转(向上转型)
- 可能安全的转化强转下编译可通过(运行时如果发现是危险的也报错)
- 一定危险的强转也编译报错
1.向上转型相关:
public T[] array = (T[])new Object[10]
编译检查时,array似复刻变量数组元素是以指定似复刻变量引用类型检查的
这里强转后不报错编译通过的原因是此Object类似复刻变量引用数组可能是通过T[]对应向上转型而来的(它们俩本身明确有继承关系),如果是这样,去向下转型是安全的,所以可能是安全的,强转后编译是允许通过的,具体看运行时,发现是(Object[])Object[],安全通过地运行,最后运行时也通过了
其实此语句最后一直执行的都是Object[] array = (Object[]) Object[10],换哪个指定引用类型去创建此泛型似复刻变量最后里面创建的都是它这样,那为什么不直接Object[] array = (Object[]) Object[10]创建呢?因为它和类变量下面的其它T一样,都是要去实现指定类型的检查的
Object object = new Object();
String string = new String();
string = (String) obejct;
编译时通过的,因为Object类与String类成继承关系,此object可能是string向上转型来的,编译器不知道,有可能安全的,所以编译时加上强转后是编译通过的,具体看运行时,发现object并不是此string向上转型来的,给它强转无法向下转型的,报错
2.数组相关:
基本数据类型的数组之间转化是一定危险报错的,因为空间都明确不一样
引用类型数组的转化就正常与它元素一样的看,因为每个引用变量空间都是固定统一的:
- 引用变量之间是继承下且是子类对父类的向上转型就可直接转编译与运行都通过
- 继承下父类往子类强转编译时通过运行时再具体看此父类是否是由子类先向上转型来的而决定运行时能否通过
四、extend
1.非泛型下:
- extend是继承,两边必须是相同性质的,类单继承类,接口多继承接口
- implements是实现,左边一定是类,右边一定是接口,类实现多接口
2.泛型中:
但在泛型中,统一用extend来声明边界,左边是指定的泛型类T,右边可以是类或接口:
- 是类时表明此泛型引用类将会去执行继承此类(如果它们俩实在是无法连接成继承关系的,编译器检查时就会报错)
- 是接口时表明此泛型引用类将会去执行连接此接口(到了具体指定的引用类那边就会有要求去实现接口里面的抽象方法)
可以同时定义多个边界<T extends A & B & C>:T必须可以去继承A的且有实现B和C接口方法的
编译擦除时将T擦除为边界类型(没有定义边界类型的默认边界为Object,擦除时就擦除为边界Object)
泛型方法在修饰符最后加上<T>来定义,调用时在方法名最前面加上<具体指定类型>