【Kotlin】泛型 ① ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 )

2023-03-30 18:54:41 浏览数 (1)

文章目录

  • 一、泛型类
  • 二、泛型参数
  • 三、泛型函数
  • 四、多泛型参数
  • 五、泛型类型约束

一、泛型类


定义一个 泛型类 ,

将 泛型参数 T 放在 尖括号 <T> 中 , 该泛型参数放在 类名后 , 主构造函数之前 , 该泛型参数 T 是 类型占位符 ,

在 该泛型类类中 可以使用 类型占位符 T 作为一个类 使用 ,

  • 可以 定义 T 类型成员属性
  • 主构造函数中可以接收 T 类型的实例对象作为参数 ,
  • T 类型可以 作为函数的返回值 ;

通常情况下 , 泛型参数 都使用 T 表示 , 使用其它字母 或者 字符串 都可以表示 泛型参数 , 但是 约定俗成 都使用 T 来表示泛型 ;

代码示例 : 下面的代码中 , 声明了 Student 泛型类 , 该泛型类 接收 T 类型的泛型参数 , 在主构造函数中接收 T 类型的参数 , 在该泛型类中声明了 T 类型的成员属性 ;

代码语言:javascript复制
class Student<T>(_item: T) {
    var item: T = _item
    fun log(){
        println("item : $item")
    }
}

fun main() {
    var student: Student<String> = Student("Tom")
    student.log()

    var student2: Student<Int> = Student(18)
    student2.log()
}

执行结果 :

代码语言:javascript复制
item : Tom
item : 18

二、泛型参数


通常情况下 , 泛型参数 都使用 T 表示 , 使用其它字母 或者 字符串 都可以表示 泛型参数 , 但是 约定俗成 都使用 T 来表示泛型 ;

在下面的代码中 , 使用 M 作为 泛型参数 ;

代码示例 :

代码语言:javascript复制
class Student<M>(_item: M) {
    var item: M = _item
    fun log(){
        println("item : $item")
    }
}

fun main() {
    var student: Student<String> = Student("Tom")
    student.log()

    var student2: Student<Int> = Student(18)
    student2.log()
}

执行结果 :

代码语言:javascript复制
item : Tom
item : 18

三、泛型函数


函数 的 参数 或 返回值 类型为 泛型类型 , 则该函数称为 泛型函数 ;

代码示例 : 该代码中 , 泛型函数 logT 的 参数 和 返回值 都是 T 泛型参数 类型 ;

代码语言:javascript复制
class Student<T>(_item: T) {
    var item: T = _item

    // 泛型函数 参数 和 返回值 都是 T 类型
    fun logT(t: T): T{
        println("item : $item")
        return item
    }
}

fun main() {
    var student: Student<String> = Student("Tom")
    println(student.logT(student.item))

    var student2: Student<Int> = Student(18)
    println(student2.logT(student2.item))
}

执行结果 :

代码语言:javascript复制
item : Tom
Tom
item : 18
18

四、多泛型参数


泛型函数 中 如果涉及到 匿名函数 参数 , 匿名函数 的 参数返回值 都是泛型 的话 , 在该泛型函数 中可能需要使用多个泛型 , 使用不同的字母表示不同的泛型 ;

如果函数中 引入了新的泛型类型 , 需要在 fun 关键字 和 函数名 之间 , 使用 尖括号 <T> 注明 ;

代码示例 : 在本代码中 , logT 函数涉及到了两个泛型参数 , 传入的 匿名函数 参数类型为 (T) -> R , 需要两个泛型参数来表示其类型 ; T 类型在泛型类中注明 , 可以在该泛型类 Student 中随意使用 , 但是 泛型参数 R 是首次在该函数中使用 , 因此需要在该函数的 fun 关键字 和 函数名 之间 , 使用 尖括号 <R> 注明 新的泛型参数 ;

代码语言:javascript复制
class Student<T>(_item: T) {
    var item: T = _item

    fun <R> logT(action: (T) -> R): R{
        return action(item)
    }
}

fun main() {
    var student: Student<String> = Student("Tom")
    println(student.logT {3.14})

    var student2: Student<Int> = Student(18)
    println(student2.logT {true})
}

执行结果 :

  • student 实例对象中 , 泛型 T 的实际类型是 String 类型 , 在 logT 中 泛型 R 的类型是 Double 类型 ;
  • student2 实例对象中 , 泛型 T 的实际类型是 Int 类型 , 在 logT 中 泛型 R 的类型是 Boolean 类型 ;
代码语言:javascript复制
3.14
true

五、泛型类型约束


在 泛型类 , 泛型函数 中 , 使用泛型前 , 需要声明 泛型参数 :

  • 泛型类 泛型参数 声明 : 如果类中 引入了新的泛型类型 , 需要在 class 关键字 和 主构造函数 之前 , 使用 尖括号 <T> 注明 ;
代码语言:javascript复制
class Student<T>(_item: T) {
}
  • 泛型函数 泛型参数 声明 : 如果函数中 引入了新的泛型类型 , 需要在 fun 关键字 和 函数名 之前 , 使用 尖括号 <T> 注明 ;
代码语言:javascript复制
    fun <R> logT(action: (T) -> R): R{
        return action(item)
    }

在 尖括号 <> 中声明 泛型参数 时 , 可以指定 泛型类型 的 约束 , 如 泛型类型 必须是某个类型的子类 ;

在下面的代码中 , Soldier 类的泛型 进行了约束 , 必须是 Weapon 类的子类类型 ;

代码语言:javascript复制
class Soldier<T : Weapon>(_item: T) {}

Weapon 类是父类 , 其有一个 子类 AK47 类 ;

在创建 Soldier 实例对象时 , 传入 子类 AK47 类的实例对象 , 调用其重写父类的 fire 函数 ;

代码示例 :

代码语言:javascript复制
class Soldier<T : Weapon>(_item: T) {
    var item: T = _item

    fun fight(){
        item.fire()
    }
}

open class Weapon(var name: String){
    open fun fire(){
        println("weapon fire!")
    }
}
class AK47: Weapon("AK47"){
    override fun fire(){
        super.fire()
        println("fire in the hole !")
    }
}

fun main() {
    var soldier: Soldier<AK47> = Soldier(AK47())
    soldier.fight()
}

执行结果 :

代码语言:javascript复制
weapon fire!
fire in the hole !

0 人点赞