欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Java基础扫盲]--反射与泛型--(5)泛型

程序员文章站 2022-07-15 16:25:45
...
Author:赵志乾
Date:2019-05-04
Declaration:All Right Reserved!!!

1、什么是泛型

所谓的泛型就是编写模板代码来适应任意类型,从而避免一些繁琐的类型转化,且能够让编译器在编译阶段进行类型检查。在使用泛型时,其继承关系中要保持泛型参数不变。例如:ArrayList<Integer>和List<Integer>有继承关系,而ArrayList<Integer>和List<Number>没有继承关系。

在使用泛型时,需要将泛型参数T替换为需要的引用类型;当不指定泛型参数类型时,编译器会给出警告,且只能将泛型参数视为Object类型。

2、编写泛型

按照某种类型去编写类;

标记其中所有的特定类型;

将特定类型替换为T,并在声明处使用<T>;

注意:泛型类型<T>不能用于静态方法,否则会出现编译错误,因为编译器无法在静态字段或静态方法中使用泛型类型<T>。静态方法可以单独改写为泛型方法,其使用的泛型参数和类的泛型参数不是同一个,例如使用另一个类型<K>

public class Pair<T>{
    private T first;
    private T second;

    public Pair(T first, T second){
        this.first = first;
        this.second = second;
    }
    
    public T getFirst(){
        return first;
    }

    public T getSecond(){
        return second;
    }

    public static <K> Pair<K> create(K first,K second){
        return new Pair<K>(first,second);
    }

}

注意:定义泛型时,也可以使用多个泛型参数,如<T,K,U>

3、泛型擦除

编译器会将类型<T>视为Object,只不过在编译的过程中会依据泛型参数<T>实现安全的强制类型转换。故泛型这一该概念在虚拟机中是不存在的。由于编译器会将泛型参数视为Object,所以泛型参数不能是基本类型。

由于编译后,编译器会将泛型擦除,所以在运行时,无法取得带泛型的Class实例。因为他们对应的都是泛型参数为Object类型时的Class实例。

由于泛型参数会被擦除为Object,所以T类型不可以直接实例化。其在源码中进行实例化时必须借助于Class<T>。如:

public class Pair<T>{

    private T first;
    private T second;

    public Pair(Class<T> clazz){
        first = clazz.newInstance();
        second = clazz.newInstance();
    }
}

4、extends通配符

由于泛型参数在继承体系中不可变,即相同的泛型参数才具有继承关系。为了解决这一问题,引入了extends通配符,其使得泛型参数由单一类型扩展至该单一类型及其子类型。方法参数使用通配符下:

public class Pair<T>{
    .....
}

public class PairHelper{
    public static double add(Pair<? extends Number> p){
        //可以调用get方法,但不可以调用set方法;因为我们无法确定传入的类型具体是什么类型
        Number first = p.getFirst();
        Number second = p.getSecond();
        return first.doubleValue() + second.doubleValue();
    } 
}

类型定义使用extends通配符如下,其限定了定义Pair<T>时只能时使用Number或Number的子类替换泛型参数:

public class Pair<T extends Number>{
    private T first;
    private T second;

    public Pair(T first, T second){
        this.first = first;
        this.second = second;
    }
    
    public T getFirst(){
        return first;
    }

    public T getSecond(){
        return second;
    }
}

5、super通配符

super通配符是extends通配符的互补,其在方法参数中使用时,表明泛型参数由单一类型扩展至单一类型及其超类。

public class Pair<T>{
    .....
}

public class PairHelper{
    public static void set(Pair<? super Integer> p, Integer first,Integer second){
        //可以调用set方法,但不可以调用get方法;因为无法确定传入的泛型类型
        p.setFirst(first);
        p.setSecond(second);
    } 
}

同理,super通配符用于类型定义时,其限定了泛型参数只能使用指定单一类型及其超类。

注意:<? extends T> 允许调用方法获取T的引用,而<? super T>允许调用方法传入T的引用。

6、无限定通配符

<?>称为无限定通配符,包含了super通配符和extends通配符的限制,所以无限定通配符很少使用。