美文网首页Android开发
Java 与 Kotlin 泛型

Java 与 Kotlin 泛型

作者: 戎码虫 | 来源:发表于2022-02-12 15:10 被阅读0次

    Java

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

    下面这个类为例子

    public class FatherClass {
        void fatherMethod() {
            System.out.println("父类方法");
        }
    }
    
    public class ExtendsClass<T extends FatherClass> {
        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<SonClass> sonClassExtendsClass = new ExtendsClass<>();
            sonClassExtendsClass.set(new SonClass());
            SonClass sonClass = sonClassExtendsClass.get();
    }
    

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

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

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

    • 必须传入T或者T的子类
    • 可以使用T里面的方法
    public void upFun(ArrayList<? extends FatherClass> fatherList) {
    
    }
    
    下界通配符 < ? super T>

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

    • 必须传入T或者T的父类
    public void downFun(ArrayList<? super SonClass> fatherList) {
    
    }
    
    无界通配符?

    参数可为任何类型,类似于<? extends Object>

    ArrayList<?> fatherList
    
    ?和 T 的区别
    T t;//可以
    void set(T t)
    public class ExtendsClass<T extends FatherClass>
    
    ? v;//不可以
    public void upFun(ArrayList<? extends FatherClass> fatherList)
    public void downFun(ArrayList<? super SonClass> fatherList)
    public class ExtendsClass<? extends FatherClass> //不可以
    

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

    泛型多重限定

    首先定义两个接口

    interface InterfaceA {
    }
    
    interface InterfaceB {
    }
    

    继承这两个接口

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

    泛型类实现

    public class InterfaceClass<T extends InterfaceA & InterfaceB> {
        T t;
    
        void set(T t) {
            this.t = t;
        }
    
        T get() {
            return t;
        }
    }
    
    //不可以
    InterfaceClass interfaceClassNo =  new InterfaceClass<FatherClass>();
    
    //可以
    InterfaceClass interfaceClass =  new InterfaceClass<SonClass>();
    

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

    协变与逆变

    逆变与协变用来描述类型转换(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<? extends Animal> animalExtends = new ArrayList<Dog>();
    //编译不通过
    animalExtends.add(new Dog());
    animalExtends.add(new Cat());
    animalExtends.add(new Bird());
    
    ArrayList<Dog> dogList = new ArrayList<Dog>();
    dogList.add(new Dog());
    dogList.add(new Dog());
    dogList.add(new Dog());
    
    animalExtends = dogList;
    //获取到父类
    Animal animal = animalExtends.get(0);
    
    逆变
    ArrayList<? super Dog> animalSuper = new ArrayList<Animal>();
    animalSuper.add(new Dog());
    //编译不通过
    animalSuper.add(new Cat());
    animalSuper.add(new Bird());
    
    ArrayList<Dog> dogList = new ArrayList<Dog>();
    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<T extends FatherClass>  ->
    
    public class ExtendsClass<T : FatherClass?> {
        var t: T? = null
        fun set(t: T) {
            this.t = t
        }
    
        fun get(): T? {
            return t
        }
    }
    
    Kotlin 上界通配符
    //Java
    ArrayList<? extends FatherClass> 
    
    //Kotlin
    ArrayList<out FatherClass>
    
    Kotlin 下界通配符
    //Java
    ArrayList<? super SonClass> 
    
    //Kotlin
    ArrayList<in SonClass>
    
    泛型多重限定
    //Java
    public class InterfaceClass<T extends InterfaceA & InterfaceB> 
    
    //Kotlin
    class InterfaceClass<T> where T : InterfaceA?, T : InterfaceB?
    

    这里where是个新的关键字

    无界通配符*

    参数可为任何类型,类似于<out Any>

     ArrayList<*>
    
    问题衍生

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

    泛型类型方法

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

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

    inline fun <reified T> method(param: T): T {
        return param
    }
    
    //可以获取
    inline fun <reified T> getGenericType() = T::class.java
    
    val genericType = getGenericType<String>()
    println(genericType)
    
    class java.lang.String
    
    协变与逆变

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

    //Java
    ArrayList<? extends FatherClass> 
    
    //Kotlin
    ArrayList<out FatherClass>
    

    逆变

    //Java
    ArrayList<? super SonClass> 
    
    //Kotlin
    ArrayList<in SonClass>
    

    完结

    相关文章

      网友评论

        本文标题:Java 与 Kotlin 泛型

        本文链接:https://www.haomeiwen.com/subject/koczkrtx.html