学习Kotlin之泛型和委托

泛型

 泛型的基本用法

 泛型主要有两种定义方式:一种是定义泛型类,另一种是定义泛型方法,使用的语法结构都是<T>。

 定义一个泛型类

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

 

 此时的MyClass就是一个泛型类,MyClass中的方法允许使用T类型的参数和返回值。

 调用的时候写法如下:

        val myClass = MyClass<Int>()
        val result = myClass.method(123)

 

 定义一个泛型方法:

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

 

 调用方式也需要进行相应的调整:

        val myClass = MyClass()
        val result = myClass.method<Int>(123)

 

 由于Kotlin的类型推导机制,我们传入的是Int类型的参数,它能自动推导出来,所有可以省略泛型的指定:

val result = myClass.method(123)

 

 

 泛型类型限制

 目前method()方法的泛型指定成任意类型,还可以通过指定上界的方式来对泛型的类型进行约束,比如这里将method()方法的泛型上界设置为Number类型,如下所示:

class MyClass {
    fun <T : Number> method(param: T): T {
        return param
    }
}

 表示method方法的泛型只能指定为Int,Float,Double等。

 另外,默认情况下,所有的泛型都可以指定为可空类型。因为在不指定上界的时候,泛型的上界默认是Any?。如果想要让泛型的类型不可为空,只需要将泛型的上界手动指定成Any就可以了。

 

 委托

 类委托和委托属性

 委托是一种设计模式,它的基本理念是:操作对象自己不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理。Java对于委托并没有语言层级的实现。

 类委托

 核心思想在于将一个类的具体实现委托给另一个类去完成

 Set是一个接口,如果要使用它,需要使用它具体的实现类,比如HashSet。而借助于委托模式,我们可以轻松实现一个自己的实现类。

 比如定义一个MySet,并让它实现Set接口,代码如下所示:

复制代码
class MySet<T>(val helperSet: HashSet<T>) : Set<T> {
    override val size: Int
        get() = helperSet.size

    override fun contains(element: T) = helperSet.contains(element)

    override fun containsAll(elements: Collection<T>) = helperSet.containsAll(elements)

    override fun isEmpty() = helperSet.isEmpty()

    override fun iterator() = helperSet.iterator()

}
复制代码

 

 MySet的构造函数中接收了一个HashSet参数,这就相当于一个辅助对象。然后在Set接口所有的方法实现中,我们都没有进行自己的实现,而是调用了辅助对象中相应的方法实现,这其实就是一种委托模式

  

 这样做的好处在于:如果我们只是让大部分的方法实现调用辅助对象中的方法,少部分的方法实现由自己来重写,甚至加入一些自己独有的方法,那么MySet就会成为一个全新的数据结构类,这就是委托模式的意义所在。

 但是有一个弊端:如果接口中待实现方法很多,那么每个都要去调用辅助对象中方法实现。但是Kotlin可以通过类委托的功能来解决。

 

 Kotlin中委托使用的关键字是by,我们只需要在接口声明的后面使用by关键字,再接上受委托的辅助对象,就可以免去之前所写的一大堆模板式的代码了,如下所示:

class MySet<T>(val helperSet: HashSet<T>) : Set<T> by helperSet{
    
}

 

 如果我们要对某个方法进行重新实现,只需要单独重写那一个方法就可以了,如下所示:

class MySet<T>(val helperSet: HashSet<T>) : Set<T> by helperSet{
    
    fun helloWorld() = println("Hello World")

    override fun isEmpty() = false
}

 现在MySet就是一个全新的数据结构类,不仅有新方法,还有HashSet中的功能。这就是Kotlin的类委托

 

 委托属性

 委托属性的核心思想是将一个属性(字段)的具体实现委托给另一个类去完成

 委托属性的语法结构,如下所示:

class MyClass {
    var p by Delegate()
}

 

 by关键字连接了左边的p属性和右边的Delegate实例。这种写法就代表着将p属性的具体实现委托给了Delegate类去完成。

 当调用p属性的时候会自动调用Delegate类的getValue()方法,当给p属性赋值的时候会自动调用Delegate类的setValue()方法。

 

 因此,我们还需要对Delegate类进行具体的实现才行,代码如下所示:

复制代码
class Delegate {
    var propValue: Any? = null
    operator fun getValue(myClass: MyClass, prop: KProperty<*>): Any? {
        return propValue
    }
    operator fun setValue(myClass: MyClass, prop: KProperty<*>, value: Any?){
        propValue = value
    }
}
复制代码

 

 这是一种标准模板,在Delegate类中我们必须实现getValue()和setValue()这两个方法,并且都要使用operator关键字进行声明。

 getValue()方法接收两个参数

  第一个: 用于声明该Delegate类的委托功能可以在什么类中使用,这里写成MyClass表示仅可在MyClass类中使用;

  第二个: KProperty<*>是Kotlin中的一个属性操作类,可用于获取各种属性相关的值,在当前场景下用不着,但是必须在方法参数上进行声明。

 <*>这种泛型的写法表示不知道或者不关心泛型的具体类型,只是为了通过语法编译而已。

 setValue()方法也是相似的,只不过它要接收3个参数:

  前两个参数和getValue()方法是相同的;

  最后一个参数表示具体要赋值给委托属性的值,这个参数的类型必须和getValue()方法返回值的类型保持一致。

 

 整个委托属性的工作流程就是这样实现的,现在当我们给MyClass的p属性赋值时,就会调用Delegate类的setValue()方法,当获取MyClass中p属性的值时,就会调用Delegate类的getValue()方法。

 

 委托功能本身不难理解,真正的难点在于如何灵活地进行应用。

 

posted @   PeacefulGemini  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
回顶部
点击右上角即可分享
微信分享提示