Java 基础:泛型

886 阅读3分钟

本文介绍 Java 中的泛型,可与 Kotlin 基础:泛型 配合食用。

一、为什么要有泛型

  • 效率、成本
  • 减少样板代码的编写

二、泛型的分类

  • 泛型类
  • 泛型方法

三、泛型的关键字

3.1 T

T 代表任意一个类型,可以为任意字符串,一般为:T、U、S、E、K、V。

  • T、U、S:任意类型
  • E:集合的元素类型
  • K、V:Map 的 key 和 value 类型

3.2 ?

? 是泛型通配符,代表任意一批类型。

四、泛型类、方法的定义

4.1 泛型类的定义

class AClass<T> ...
class AClass<T extends BClass> ... //没有 T super BClass 这种写法

<T> 在类名后声明。在该类中,可以

  • 使用 T 作为对象的类型声明

    T a;

  • 使用 T 作为泛型类型对象的类型参数

    List<T> list;

  • 使用 T 作为方法返回类型前的声明(所以泛型类中的泛型方法可以省去返回类型前的 )

    见泛型方法的定义

4.2 泛型方法的定义

public <T> void ...

<T> 在方法返回类型前声明。在该方法中,可以

  • 使用 T 作为方法的返回类型

    public <T> T...

  • 使用 T 作为方法的参数类型

    public <T> void doSomething(T t) ...

  • 使用 T 作为方法的泛型参数的类型参数

    public <T> void doSomething(List<T> listT)...

五、泛型类、方法的使用

5.1 泛型实现类

指类型参数指定为一个确定的单一类,如 String 对应 AClass<String>,它表示:

一个泛型实现类,类型参数是 String(即 AClass<T>,使用时 T 已经被指定为 String)

5.2 通配类

5.2.1 AClass<?>

它代表一批泛型实现类,类型参数可以是任何类。

5.2.2 AClass<? extends BClass>

它代表一批泛型实现类,这批实现类的特点是:

  • 它们的类型参数只能是 BClass 的子类。
  • 它们自己,都是 AClass<? extends BClass> 的子类。

这种泛型实现类通配类的父子关系,和泛型实现类的类型参数通配类的类型参数的父子关系相同的关系,称为协变

当实现类转为 AClass<? extends BClass> 时:

  • 可以 get 到 BClass,因为所有实现类的类型参数的共同上界就是 BClass。
  • 不能 set 任何值,因为不确定实现类的类型参数是哪个 BClass 的子类。

5.2.3 AClass<? super BClass>

它代表一批泛型实现类,这批实现类的特点是:

  • 它们的类型参数只能是 BClass 的父类。
  • 它们自己,都是 AClass<? super BClass> 的子类。

这种泛型实现类通配类的父子关系,和泛型实现类的类型参数通配类的类型参数的父子关系相反的关系,称为逆变

当实现类转为 AClass<? super BClass> 时:

  • 不能 get 到 BClass,只能 get 到 Object,因为所有实现类的类型参数的共同上界只有 Object。
  • 可以 set BClass 及其子类,因为一定是覆盖真正的实现类的类型参数的。

六、代码示例

public class ChangeJava {
    class A {
    }

    class B extends A {
    }

    class C extends B {
    }

    class AClass<T> {
        private T mT;

        void set(T u) {
            mT = u;
        }

        T get() {
            return mT;
        }
    }

    private void doSomething() {
        AClass<String> aClass = new AClass<>();
        AClass<Object> aClass1 = new AClass<>();
        aClass1 = aClass; // 报错

        AClass<A> aClassA = new AClass<>();
        AClass<B> aClassB = new AClass<>();
        AClass<C> aClassC = new AClass<>();

        AClass<? extends B> aClassExtendB1 = aClassA; // 报错
        AClass<? extends B> aClassExtendB2 = aClassB;
        AClass<? extends B> aClassExtendB3 = aClassC;
        B b2 = aClassExtendB2.get(); // 可以 get 到 B
        aClassExtendB2.set(); // 报错,set 任何值都会报错

        AClass<? super B> aClassSuperB1 = aClassA;
        AClass<? super B> aClassSuperB2 = aClassB;
        AClass<? super B> aClassSuperB3 = aClassC; // 报错
        Object o = aClassSuperB1.get(); // 只能 get 到 Object
        aClassSuperB1.set(new A()); // 报错,set 除 B 及其子类以外的类型就会报错
        aClassSuperB2.set(new B());
        aClassSuperB2.set(new C());
    }
}