泛型(泛型擦除、泛型可以反射、泛型的限制和问题)

1. 泛型擦除

泛型的擦除是是用一种称为类型消除( type erasure)的方法来实现的。
当泛型存在于编译时,一旦被确认安全使用时,
就会将其转换为原生类型也就是擦除成原生类型。

泛型擦除是指泛型代码在编译后,都会被擦除为原生类型。例如
Zoo<Fish>和Zoo<Bird>,实际上在运行时都是同一种类型,即
原生类型Zoo。这就意味着运行时,Java并不存在类型参数这一概念,
因此将无法任何相关的参数类型信息。

例如下面的代码证实了泛型擦除:
package Generic.wildcardsAndBoundaries;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Zoo<Fish> fishZoo = new Zoo<>(new Fish());
        Zoo<Bird> birdZoo = new Zoo<>(new Bird());
        System.out.println("两者的类型相同吗? " + fishZoo.getClass().equals(birdZoo.getClass()));
    }
}

运行结果:
在这里插入图片描述


1.1 为什么要擦除泛型

擦除是java泛型方法实现的一种折中办法。
因为擦除的核心动机是使得泛化的代码可以使用非泛化的类库,
反之亦然,为了让非泛型的代码和泛型的代码共存,实现擦除非常可靠!

1.2 如何擦除

其实擦除的实质就是将原有的类型参数替换成即非泛化的上界。如:
public class Computer<E> {
    
    
    private E e;
    public Cmputer(E e){
    
    
        this.e=e;
    }
    public E apply(){
    
    
        return this.e;
    }
}
上方代码经过编译后,将被编译成以下代码形式:
public class Computer {
    
    
    private Object e;

    public Computer(Object e) {
    
    
        this.e = e;
    }

    public Object apply() {
    
    
        return e;
    }
}
通过比较你会发现原有类型参数消失了,取而代之为参数类型Object,
这是因为Computer<E>没有指明上界,编译器将其自动擦除成顶类Object类型

若指明了上界如<E extends electrical>,则会有如下翻译:

在这里插入图片描述


1.3 多边界擦除

在这里插入图片描述


2 泛型可以反射

在这里插入图片描述


3 泛型的限制和问题

因为擦除机制使得运行时丢失了泛型信息,
因此一些理所当然的功能在java泛型系统中得不到支持。
  • 限制一:
    为了保证类型安全,不能使用泛型类型参数创建实例
    // 不合法 T object=new T() ;
  • 限制二:
    不能声明泛型实例数组,这会导致运行错误
    // 不合法 T[] numbers= new T[capcity];
    但可以通过创建一个Object类型数组然后将它的类型转换E[]来规避这个限制。
    T[] number= (E[])new Object[capcity]:
  • 限制三:
    在静态的环境下不允许参数类型是泛型类型的。(由于泛型类的所有实例都有相同的运行时类,所以泛型类的静态变量和方法是被它的所有实例所共享的。既然是共享的你就没有必要再重新定义一样的泛型类型,那如果你不定义一样的泛型类型,又达不到共享(或者说是一致性),更没有必要让这种情况通过。所以,在静态环境了类的参数被设置成泛型是非法的。)
  • 限制四:
    泛型类对象无法被抛出或捕获,因为泛型类不能继承或实现Throwable接口及其子类。

猜你喜欢

转载自blog.csdn.net/I_r_o_n_M_a_n/article/details/115203473