欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Kotlin语法总结(三)-泛型的使用

程序员文章站 2024-03-14 19:33:17
...

怎样声明一个函数来判断两个参数是否相等呢?如果参数是Int类型,则函数声明如下:

private fun isEqualsInt(a: Int, b: Int): Boolean {
         return (a == b)
}

这个函数参数列表是两个Int类型,它只能比较两个Int类型参数是否相等。如果想比较两个Double类型是否相等,可以修改上面声明的函数如下:

private fun isEqualsDouble(a: Double, b: Double): Boolean {
         return (a == b)
}

这个函数参数列表是两个Double类型,它只能比较两个Double类型参数是否相等。如果想比较两个String类型是否相等,可以修改上面声明的函数如下:

private fun isEqualsString(a: String, b: String): Boolean {
         return (a == b)
}

以上分别对3种类型的两个参数进行了比较,声明了类似的3个函数。

那么是否可以声明一个函数使之能够比较3种类型呢?

合并代码: 

private fun <T> isEquals(a: T, b: T): Boolean {
         return (a == b)
}

在函数名isEquals前面添加<T>这就是泛型函数了,<T>是声明类型参数,T是类型参数,函数中参数类型也被声明为T,在调用函数时T会用实际的类型替代。

泛型中类型参数,可以是任何大写或小写的英文字母,一般情况下人们习惯于使用字母TEKU等大写英文字母。

fun main(args: Array<String>) {
     println(isEquals(1, 5))
     println(isEquals(1.0, 5.0))
}

多类型参数

上面泛型函数示例中只是使用了一种类型参数,事实上可以同时声明使用多个类型参数,它们之间用逗号“,” 分隔,示例如下:
fun <T, U> addRectangle(a: T, b: U): Boolean {...}

类型参数不仅可以声明函数参数类型,还可以声明函数的返回类型,示例代码如下:

fun <T, U> rectangleEquals(a: T, b: U): U {...}

泛型约束

声明 fun <T> isEquals(a: T, b: T): Boolean 函数时,事实上还有一点问题,这是因为并不是所有的类型参数T 都具有 可比性 ,必须限定 T 的类型,如果只是数字类型比较可以限定为Number ,因为 Int Double 等数字类型都继承 Number ,是Number的子类型。
规则:
声明类型参数时在 T 后面添加冒号( : )和限定类型,这种表示方式称为“ 泛型约束 ,泛型约束主要应用于泛型函数和泛型类的声明。

private fun <T : Number> isEquals(a: T, b: T): Boolean { ①
        return (a == b)
}

fun main(args: Array<String>) {
        println(isEquals(1, 5)) //false ②
        println(isEquals(1.0, 1.0)) //true ③
}

上述代码是声明泛型函数,其中<T : Number>是带有约束的类型参数。

如果函数泛型限定声明为 <T : Number>,则函数只能比较Number类型的参数,不能比较String等其他数据类型,为此也可以将类型参数限定为Comparable<T>接口类型,所有可比较的对象都实现Comparable<T>接口,Comparable<T>本身也是泛型类型。

fun <T : Comparable<T>> isEquals(a: T, b: T): Boolean {

         return (a == b)
}

fun main(args: Array<String>) {
         println(isEquals(1, 5)) //false
         println(isEquals(1.0, 1.0)) //true
         println(isEquals("a", "a")) //true ①

         val d1 = Date()
         val d2 = Date()
         println(isEquals(d1, d2)) //true ②
}

可空类型参数和非空类型参数

在泛型函数声明中,类型参数没有泛型约束,函数可以接收任何类型的参数,包括可空和非空数据。例如fun <T> isEquals(a: T, b: T): Boolean 函数调用时可以传递可空或非空数据,代码如下:
println(isEquals(null, 5)) //false

所有没有泛型约束的类型参数,事实上也是有限定类型的,只不过是Any?Any?可以任何可空类型的根类,也兼容非空类型。

如果不想接收任何可空类型数据,可以采用 Any 作为约束类型, Any 是任何非空类型的父类,代码如下:
private fun <T : Any> isEquals(a: T, b: T): Boolean { ①
        return (a == b)
}

fun main(args: Array<String>) {
        println(isEquals(null, 5)) //编译错误 ②
        println(isEquals(1.0, null)) //编译错误 ③
}

泛型属性

Kotlin 中还可以声明泛型属性,但是这种属性一定是扩展属性,不是能是普通属性。普通属性不能声明泛型,只有扩展属性才能声明泛型。
示例代码如下:
  val <T> ArrayList<T>.first: T? //获得第一个元素 ①
        get() = if (this.size > 1) this[0] else null
  val <T> ArrayList<T>.second: T? //获得第二个元素 ②
        get() = if (this.size > 2) this[1] else null

  fun main(args: Array<String>) {
        val array1 = ArrayList<Int>()//等同于arrayListOf<Int>() ③
        println(array1.first) //null 
        println(array1.second) //null

        val array2 = arrayListOf ("A", "B", "C", "D") ④
        println(array2.first) //A
        println(array2.second) //B
  }

上述代码第①行和第②行是声明ArrayList集合的扩展属性first和second,其中使用了泛型。集合中的元素类型采用类型参数T表示,返回类型是T?表示可能有返回空值的情况。

代码第③行是实例化,Int类型的ArrayList集合,使用ArrayList构造函数创建一个空元素的集合对象。也可以使用arrayListOf<Int>()函数创建集合对象。代码是④行是创建String类型ArrayList集合对象,这里使用arrayListOf<String>("A", "B", "C", "D")函数创建并初始化该集合。

泛型类

在声明泛型类时也可以有多个类型参数,类似于泛型函数可以使用多个不同的字母声明不
同的类型参数。另外,在泛型类中也可以使用泛型约束,如下代码所示:
class Queue<T : Number> {...}
/**
* 自定义的泛型类
*/
class Queue<T> {

   // 声明保存队列元素集合items
   private val items: MutableList<T>
   // init代码块初始化是集合items
   init {
         this.items = ArrayList()
   }

   /**
    * 入队函数
    *
    * @param item  参数需要入队的元素
    */
    fun queue(item: T) {
         this.items.add(item)
    }

   /**
    * 出队函数
    * @return 返回出队元素
    */
    fun dequeue(): T? {
       return if (items.isEmpty()) {
                  null
              } else {
                  this.items.removeAt(0)
              }
    }

   override fun toString(): String {
              return items.toString()
    }
}

泛型接口:

 
/**
* 自定义的泛型队列集合
*/
interface IQueue<T> { ①
     /**
     * 入队函数
     *
     * @param item 参数需要入队的元素
     */
     fun queue(item: T) ②
   

    /**
     * 出队函数
     *
     * @return 返回出队元素
     */
     fun dequeue(): T? ③
}

实现接口IQueue<T>具体方式有很多,可以是List(列表结构)、Set(集结构)或Hash(散列结构)等多种不同方式,下面是一个基于List实现方式,代码如下:

/**
* 自定义的泛型队列集合
*/
class ListQueue<T> : IQueue<T> {

   // 声明保存队列元素集合items
   private val items: MutableList<T>
   // init代码块初始化是集合items
   init {
         this.items = ArrayList()
   }

   /**
    * 入队函数
    *
    * @param item
    * 参数需要入队的元素
    */
   override fun queue(item: T) {
         this.items.add(item)
   }

   /**
    * 出队函数
    *
    * @return 返回出队元素
    */
   override fun dequeue(): T? {
       return if (items.isEmpty()) {
                  null
              } else {
                  this.items.removeAt(0)
              }
    }

   override fun toString(): String {
              return items.toString()
    }
}
至此关于Kotlin的泛型内容到此完结!
相关标签: Kotlin