Java 与 Kotlin 泛型

Java

Java 泛型(generics)是 JDK 5 中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型。

下面这个类为例子

public class FatherClass {
    void fatherMethod() {
        System.out.println("父类方法");
    }
}
public class ExtendsClass {
    T t;

    void set(T t) {
        this.t = t;
    }

    T get() {
        return t;
    }
}

在main方法中调用

 public static void main(String[] args) {
        ExtendsClass sonClassExtendsClassNo = new ExtendsClass();
        sonClassExtendsClassNo.set(new SonClass());
        SonClass sonClassNo = (SonClass) sonClassExtendsClassNo.get();

        ExtendsClass sonClassExtendsClass = new ExtendsClass<>();
        sonClassExtendsClass.set(new SonClass());
        SonClass sonClass = sonClassExtendsClass.get();
}

第一种:当我们不指定泛型类型时,使用时需要强制转换,这个存在强制转换隐患错误;
第二种:创建时指定类型,获取值的时候就不需要转换了,可以在编译时候检查类型安全,可以用在类,方法,接口上。

第二种就体现了泛型的好处
上界通配符 < ? extends T>

用 extends 关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。

  • 必须传入T或者T的子类
  • 可以使用T里面的方法
public void upFun(ArrayList fatherList) {

}
下界通配符 < ? super T>

用 super 进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object。

  • 必须传入T或者T的父类
public void downFun(ArrayList fatherList) {

}
无界通配符?

参数可为任何类型,类似于

ArrayList fatherList
?和 T 的区别
T t;//可以
void set(T t)
public class ExtendsClass

? v;//不可以
public void upFun(ArrayList fatherList)
public void downFun(ArrayList fatherList)
public class ExtendsClass //不可以

T 是一个确定的类型,通常用于泛型变量、泛型方法和泛型类的定义;
?是一个不确定的类型,通常用于泛型方法形参范围控制,不能用于定义类和泛型方法。

泛型多重限定

首先定义两个接口

interface InterfaceA {
}

interface InterfaceB {
}

继承这两个接口

public class SonClass extends FatherClass implements InterfaceA, InterfaceB {
    void sonMethod() {
        System.out.println("子类方法");
    }
}

泛型类实现

public class InterfaceClass {
    T t;

    void set(T t) {
        this.t = t;
    }

    T get() {
        return t;
    }
}
//不可以
InterfaceClass interfaceClassNo =  new InterfaceClass();

//可以
InterfaceClass interfaceClass =  new InterfaceClass();

总结:当采用双重泛型限定,泛型类必须实现指定需要实现的接口,缺一不可;

协变与逆变

逆变与协变用来描述类型转换(type transformation)后的继承关系,其定义:如果A、B表示类型,f(⋅)表示类型转换,≤表示继承关系(比如,A≤B表示A是由B派生出来的子类)
f(⋅)是逆变(contravariant)的,当A≤B时有f(B)≤f(A)成立;
f(⋅)是协变(covariant)的,当A≤B时有f(A)≤f(B)成立;
f(⋅)是不变(invariant)的,当A≤B时上述两个式子均不成立,即f(A)与f(B)相互之间没有继承关系。
--引自网络

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class Bird extends Animal {}
协变
ArrayList animalExtends = new ArrayList();
//编译不通过
animalExtends.add(new Dog());
animalExtends.add(new Cat());
animalExtends.add(new Bird());

ArrayList dogList = new ArrayList();
dogList.add(new Dog());
dogList.add(new Dog());
dogList.add(new Dog());

animalExtends = dogList;
//获取到父类
Animal animal = animalExtends.get(0);
逆变
ArrayList animalSuper = new ArrayList();
animalSuper.add(new Dog());
//编译不通过
animalSuper.add(new Cat());
animalSuper.add(new Bird());

ArrayList dogList = new ArrayList();
dogList.add(new Dog());
dogList.add(new Dog());
dogList.add(new Dog());

animalSuper = dogList;
//获取集合中的值
Object object = animalSuper.get(0);
  • 协变:extends/向上转换/不能add/只能get(T及父类)
  • 逆变:super/向下转换/不能get/只能add(T及子类)

Kotlin

学习了一下Java的泛型,Kotlin就简单多了

变量、方法和类的泛型
public class ExtendsClass  ->

public class ExtendsClass {
    var t: T? = null
    fun set(t: T) {
        this.t = t
    }

    fun get(): T? {
        return t
    }
}
Kotlin 上界通配符
//Java
ArrayList 

//Kotlin
ArrayList
Kotlin 下界通配符
//Java
ArrayList 

//Kotlin
ArrayList
泛型多重限定
//Java
public class InterfaceClass 

//Kotlin
class InterfaceClass where T : InterfaceA?, T : InterfaceB?

这里where是个新的关键字

无界通配符*

参数可为任何类型,类似于

 ArrayList<*>
问题衍生

kotlin中inline内联函数,为了使调用函数可以内联函数的泛型的类型,可以reified关键字修饰

泛型类型方法

inline fun  method(param: T): T {
   return param
}

reified关键字修饰,此时泛型T被实化可以获取泛型实际类型,T::class.java实际类型

inline fun  method(param: T): T {
    return param
}

//可以获取
inline fun  getGenericType() = T::class.java
val genericType = getGenericType()
println(genericType)

class java.lang.String
协变与逆变

总体跟Java相同,只是变了一下符合
协变

//Java
ArrayList 

//Kotlin
ArrayList

逆变

//Java
ArrayList 

//Kotlin
ArrayList

完结

你可能感兴趣的:(Java 与 Kotlin 泛型)