疯狂Kotlin讲义学习笔记10章:泛型

1、定义泛型接口、泛型类

泛型在定义类,接口,函数时使用泛型形参,这个泛型形参将在声明变量、创建对象,调用方法时动态地指定(传入实际的类型,也可称为类型实参)

可以为任何类、接口增加泛型声明

//定义App类时使用了泛型声明
open class Apple<T>{
    //使用泛型T定义属性
    open var info:T?
    constructor(){
        info=null
    }

    //使用泛型T来定义构造器
    constructor(info:T){
        this.info=info
    }
}


fun main(args:Array<String>){
    //由于传给泛型T的是String,所有构造器的参数只能是String
    var a1:Apple<String> = Apple<String>("苹果")
    //由于传给泛型T的是Int,所有构造器的参数只能是Int
    var a2:Apple<Int> = Apple(3)
    //由于传给泛型T的是Double,系统推断泛型形参为Double类型
    var a3=Apple(5.67)
    println(a1.info)
    println(a2.info)
    println(a3.info)

}

打印:
苹果
3
5.67

2、从泛型派生子类

当创建了带泛型声明的接口、父类之后,可以为该接口创建实现类,或者从该父类派生子类。
当使用这些接口,父类时不能再包含泛型形参。

父类形参为泛型形参,子类应当明确泛型形参的具体类型

//定义App类时使用了泛型声明
open class Apple<T>{
    //使用泛型T定义属性
    open var info:T?
    constructor(){
        info=null
    }

    //使用泛型T来定义构造器
    constructor(info:T){
        this.info=info
    }
}

class A1:Apple<String>(){
    //正确重写了父类的属性,属性类型与父类Apple<String>的属性类型完全相同
    override  var info:String?=null
        get() = "子类"+super.info
}

fun main(args:Array<String>){
    var a1:A1=A1()
    println(a1.info)

}

打印
子类null

3、泛型型变的需要(实际就是转型,便于添加一个类型的集合到另外一个类型的集合里)

型变实际就是转型,便于添加一个类型的集合到另外一个类型的集合里。
java是通过通配符?来完成的。但通配符的上限是Object类

泛型存在如下规律
通配符上限(泛型协变)意味着从中取出(out)对象是安全的,但传入对象(in)则不可靠
通配符下限(泛型逆变)意味着想起传入(in)对象是安全的。但取出对象(out)则不可靠

kotlin抛弃了泛型通配符语法,而是利用in,out让泛型支持型变

4、声明处型变

kotlin处理型变的规则

  • 如果泛型只需要出现在方法的返回值声明中(不出现在形参声明中),那么该方法就只是取出泛型对象,因此该方法就支持泛型协变(相当于通配符上限);如果一个类的所有方法都支持泛型协变,那么该类的泛型参数就可以使用out修饰
  • 如果泛型值需要出现在方法的形参声明中(不出现在返回值声明中),那么该方法就只是传入泛型对象,因此该方法就支持泛型逆变(相当于通配符下限);如果一个类的所有方法都支持泛型逆变,那么该类的泛型参数可以用in修饰

支持协变的案例

 class User<out T>{
    //此处不能用var,否则就有setter方法,setter方法会导致T出现在方法形参中
    val info:T
    constructor(info:T){
        this.info=info
    }
    fun test():T{
        println("执行test方法")
        return  info
    }

}
fun main(args:Array<String>){
    //此时T的类型是String
    var user=User<String>("疯狂教育体系")
    println(user.info)
    //对于u2而言,她的类型是User<Any>,此时T的类型是Any,由于程序声明了T支持协变,因此User<String>可当成User<Any>使用
    var u2:User<Any> = user//取出数据,所有将上限传入小类型是可行的
    println(u2.info)

}

打印:
疯狂教育体系
疯狂教育体系

支持逆变的案例

class Item<in T>{
    fun foo(t:T){
        println(t)
    }
}
fun main(args:Array<String>){
    //此时T的类型是Any
    var item=Item<Any>()
    item.foo(20)
    var im2:Item<String> =item

    //im2的实际类型是Item<Any>,因此她的foo的参数只要是Any即可
    //但我们声明了im2的类型为Item<String>,因此传入的参数值可能是String,所以程序肯定是安全
    im2.foo("疯狂kotlin讲义")
}

打印
20
疯狂kotlin讲义

kotilin处理规则

  • 如果泛型T只出现在该类的方法的返回值声明中,那么该泛型参数形参即可使用out修饰T
  • 如果泛型T只出现在该类的方法的形参声明中,那么该泛型参数即可使用in修饰T

泛型在参数声明的时候出现,这是声明处型变

5、使用处型变:类型投影

声明处型变导致此类所有方法都要用泛型声明返回值类型

使用处型变就是在使用泛型时对其使用out或in修饰

看不下去了,过吧

6、星号投影
7、泛型函数的使用
8、具体化类型参数
9、设定形参类型的上限
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值