Java泛型的定义和原理

119 阅读2分钟

1.为什么要有泛型

适用于多种类型执行相同代码;在编译期能够检查类型安全,减少运行时的类型转换异常。

2. 泛型类和泛型接口的定义

泛型类的定义:

public class NormalGeneric<T> {

    private T data;

    public NormalGeneric() {
    }

    public NormalGeneric(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static void main(String[] args){
        NormalGeneric<String> normalGeneric = new NormalGeneric<>();
        normalGeneric.setData("Food");
        System.out.println(normalGeneric.getData());
    }
}

泛型接口的定义:

public interface Generot<T> {
    public T next();
}

泛型方法的定义:

public class GenericMethod {
    //修饰符   返回符
    public <T> T genericMethod(T...a){
        return a[a.length/2];
    }

    public static void main(String[] args){
        GenericMethod genericMethod = new GenericMethod();
        System.out.println(genericMethod.genericMethod("apple", "pear", "banana"));
    }
}

3. 泛型中的标记符含义

标记符含义
EElement (在集合中使用,因为集合中存放的是元素)
TType(Java 类)
KKey(键)
VValue(值)
NNumber(数值类型)
不确定的java类型

4. 泛型中的约束和局限性

  1. 不能实例化泛型
public class GenericTest<T> {
    public GenericTest() {
        T t = new T();
    }
}

上述代码在编译时就会报错,因为无论是Java还是kotlin在编译期间都无法确定泛型参数的类型,所以为了防止类型问题,编译器不支持直接对泛型实例化。

  1. 无法获取泛型Class类型且不能用instanceOf关键字去判定泛型参数的类型
public class Restrict<T> {

    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static void main(String[] args){
        Restrict restrict = new Restrict();
        Restrict<String> r1 = new Restrict<>();
        Restrict<Integer> r2 = new Restrict<>();
        System.out.println(r1.getClass() == r2.getClass());
    }
}

上述代码返回的结果一定是true,因为泛型被擦除后,无论是Restrict<String>还是Restrict<Integer>获取的都是同一个Restrict class而不是Restrict<T> class

image.png

编译器是不支持用instanceOf去判断泛型类型的。

5. 限定类型变量

当我们进行代码逻辑编写时,需要调用某个类的方法,我们就可以对类型变量进行多重限定(类要写在最前面)

image.png

image.png

image.png

6. 通配符

通配符(Java/Kotlin)含义局限性
? / *无界通配符,表示未知的数据类型不可对类型变量进行多重限定, 而T可以用&进行多重限定
extends/out上界通配符,包括它的子类和本身生产者,向外提供数据(无法添加元素,只能获取元素)
super/in下界通配符,包括它的本身和超类消费者,可以添加元素,但不能按照泛型类型读取元素