泛型擦除:

    1. public class ErasedType {
    2. public static void main(String[] args) {
    3. Class c1 = new ArrayList<String>().getClass();
    4. Class c2 = new ArrayList<Integer>().getClass();
    5. System.out.println(c1 == c2);
    6. }
    7. }
    8. Arraylsit源码:
    9. public class ArrayList<E> extends AbstractList<E>implements List<E>,
    10. ~Output:
    11. true

    我们把一个Integer对象放入到String类型的集合中肯定会出错,因为两个集合的类型不同,但他们的class对象比较却是相同。这便是泛型擦除在捣乱。在运行的时候,不管是String类型还是Integer类型都被擦啦。
    泛型理解:
    在泛型代码内部我们无法获得任何有关泛型参数的信息
    当我们在使用泛型时,任何具体的类型信息都被擦除了,我们唯一知道的就是在使用一个对象
    无法知道创建摸个对象的特定实例

    1. package com.package15;
    2. import java.util.*;
    3. class Frob{}
    4. class Fnorkle{}
    5. class Qurak<Q>{}
    6. class Particle<POSITION,MOMENTUM>{}
    7. public class LostInformation {
    8. public static void main(String[] args) {
    9. List<Frob> frobList = new ArrayList<>();
    10. Map<Frob,Fnorkle> hashMap = new HashMap<>();
    11. Qurak<Frob> Qurak = new Qurak<>();
    12. Particle<Frob, Fnorkle> particle = new Particle<>();
    13. System.out.println("froblist "+ Arrays.toString(frobList.getClass().getTypeParameters()));
    14. System.out.println("hashMap "+Arrays.toString(hashMap.getClass().getTypeParameters()));
    15. System.out.println("Qurak " +Arrays.toString(Qurak.getClass().getTypeParameters()));
    16. System.out.println("particle "+Arrays.toString(particle.getClass().getTypeParameters()));
    17. }
    18. }
    19. //~Output:
    20. froblist [E]
    21. hashMap [K, V]
    22. Qurak [Q]
    23. particle [POSITION, MOMENTUM]
    1. getTypeParameters()用于获取此实体的类型参数。该实体可以是类,数组,接口等。该方法返回表示类型变量的TypeVariable对象的数组。

    擦除的核心动机:
    非泛化的类库可以去使用泛化的客户端。也就是说,当摸个类库变成泛型时,不会破坏依赖于它的代码和应用程序
    擦除的代价:
    泛型不能用于显示地引用运行时类型的操做之中,比如:转型、instanceod操做、new 表达式。因为所以关于参数的类型信息都丢失了,无论何时,当我们在编写泛型代码时,必须时刻提醒自己,你只是好像拥有有关参数的类型信息而已。
    边界的运用:
    1通过泛型使用某一类型的方法?
    泛型的擦除机制使我们无法去使用显示的使用运行时类型的操作了。如果我们想要在泛型中使用一个一个类型的方法,那么程序就会报错。↓

    1. 问题:
    2. public class HasF {
    3. public void f(){
    4. System.out.println("HasF.f() ");
    5. }
    6. }
    7. class Manipulator<T>{
    8. private T o;
    9. public Manipulator(T o){
    10. this.o = o;
    11. }
    12. public void manipulate(){
    13. o.f();//无法使用类型方法
    14. }
    15. }
    16. public class Manipulation {
    17. public static void main(String[] args) {
    18. }
    19. }

    解决方案:使用边界 通过extends来限定边界(!此时要注意对T的初始化),虽然使用边界符可以调用类型方法,但泛型擦除依然存在。

    1. package com.package15;
    2. import java.util.Arrays;
    3. class HaseF{
    4. public void f(){
    5. System.out.println("Hase.F()");
    6. }
    7. }
    8. class Manipulator<T extends HaseF>{
    9. private T t;
    10. Manipulator(T t){this.t=t;}
    11. public void info(){
    12. t.f();//无法使用泛型类型中的方法的
    13. }
    14. }
    15. public class Manipulation {
    16. public static void main(String[] args) {
    17. Manipulator<HaseF> haseFManipulator = new Manipulator<>(new HaseF());
    18. haseFManipulator.info();
    19. //虽然使用边界符可以调用类型方法,但泛型擦除依然存在
    20. System.out.println(Arrays.toString(haseFManipulator.getClass().getTypeParameters()));
    21. }
    22. }

    2.通过使用边界,可以返回Woo及其子类,但不需要显示的类型转换。但泛型擦除依然存在。

    1. package com.package15;
    2. class Woo{}
    3. class Hoo extends Woo{
    4. }
    5. public class GenericBoundaryApp<T extends Woo> {
    6. private T t;
    7. GenericBoundaryApp(T t){
    8. this.t=t;
    9. }
    10. public T getTClass(){
    11. return t;
    12. }
    13. public static void main(String[] args) {
    14. GenericBoundaryApp<Woo> genericBoundaryApp = new GenericBoundaryApp<>(new Woo());
    15. Woo tClass = genericBoundaryApp.getTClass();
    16. System.out.println("返回了Woo"+tClass);
    17. GenericBoundaryApp<Hoo> genericHoo = new GenericBoundaryApp<>(new Hoo());
    18. Hoo tClass1 = genericHoo.getTClass();
    19. System.out.println("返回了Woo的子类"+tClass1);
    20. }
    21. }