【Android基础】第一行代码-Kotlin泛型与委托
泛型与委托
泛型
泛型主要有两种定义方式:一种是定义泛型类,另一种是定义泛型方法,使用的语法结构都是 <T>。
定义一个泛型类,就可以这么写:

此时的MyClass就是一个泛型类,MyClass中的方法允许使用T类型的参数和返回值。
我们在调用MyClass类和method()方法的时候,就可以将泛型指定成具体的类型,如下所示:
![]()
这里我们将MyClass类的泛型指定成Int类型,于是method()方法就可以接收一个Int类型的参数,并且它的返回值也变成了Int类型。
定义泛型方法:

此时的调用方式也需要进行相应的调整:
![]()
Kotlin还拥有非常出色 的类型推导机制,例如我们传入了一个Int类型的参数,它能够自动推导出泛型的类型就是Int 型,因此这里也可以直接省略泛型的指定:
![]()
Kotlin还允许我们对泛型的类型进行限制,比如这里将method()方法的泛型上界设置为Number类型。这种写法就表明,我们只能将method()方法的泛型指定成数字类型,比如Int、Float、 Double等。但是如果你指定成字符串类型,就肯定会报错,因为它不是一个数字。

在默认情况下,所有的泛型都是可以指定成可空类型的,这是因为在不手动指定上界的 时候,泛型的上界默认是Any?。而如果想要让泛型的类型不可为空,只需要将泛型的上界手动指定成Any就可以了。
class MyClass{
fun<T:Any>method(param:T):T{
return param
}
}
委托
委托是一种设计模式,它的基本理念是:操作对象自己不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理。
Kotlin中也是支持委托功能的,并且将委托功能分为了两种:类委托和委托属性。
类委托
首先来看类委托,它的核心思想在于将一个类的具体实现委托给另一个类去完成

MySet的构造函数中接收了一个HashSet参数,这就相当于一个辅助对象。然后在Set接口所有的方法实现中,我们都没有进行自己的实现,而是调用了辅助对象中相应的方法实现,这其实就是一种委托模式。
既然都是调用辅助对象的方法实现,那还不如直接使用辅助对象得了。这么说确实没错,但如果我们只是让大部分的方法实现调用辅助对象中的方法,少部分的方法实现由自己来重写,甚至加入一些自己独有的方法,那么MySet就会成为一个全新的数据结构类,这就是委托模式的意义所在。但如果接口中的待实现方法比较少还好,要是有几十甚至上百个方法的话,每个都去这样调用辅助对象中的相应方法实现,效率很低。Kotlin中委托使用的关键字是by,我们只需要在接口声明的后面使用by关键字,再接上受委托 的辅助对象,就可以免去之前所写的一大堆模板式的代码了

这两段代码实现的效果是一模一样的,但是借助了类委托的功能之后,代码明显简化了太多。 另外,如果我们要对某个方法进行重新实现,只需要单独重写那一个方法就可以了:

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

这里使用by关键字连接了左边的p属性和右边的Delegate实例。这种写法就代表着将p属性的具体实现委托给了Delegate类去完成。当调用p属性的时候会自动调用Delegate类的getValue()方法,当给p属性赋值的时候会自动调用Delegate类的 setValue()方法。

getValue()方法要接收两个参数:第一个参数用于声明该Delegate类的委托功能可以在什么 类中使用,这里写成MyClass表示仅可在MyClass类中使用;第二个参数KProperty<*>是 Kotlin中的一个属性操作类,可用于获取各种属性相关的值,在当前场景下用不着,但是必须在 方法参数上进行声明。另外,<*>这种泛型的写法表示你不知道或者不关心泛型的具体类型,只 是为了通过语法编译而已,有点类似于Java中的写法
存在一种情况可以不用在Delegate类中实现setValue()方法,那就是 MyClass中的p属性是使用val关键字声明的。这一点也很好理解,如果p属性是使用val关键 字声明的,那么就意味着p属性是无法在初始化之后被重新赋值的,因此也就没有必要实现 setValue()方法,只需要实现getValue()方法就可以了。
结合委托属性实现lazy
![]()
by lazy并不是连在一起的关键字,只有by才是Kotlin中的关键字,lazy在这里只是一个高阶函数而已。

这里将getValue()方法的第一个参数指定成了Any?类型,表示我们希望Later的委托功能在 所有类中都可以使用。然后使用了一个value变量对值进行缓存,如果value为空就调用构造 函数中传入的函数类型参数去获取值,否则就直接返回。
![]()
我们将这个顶层函数也定义成了泛型函数,并且它也接收一个函数类型参数。这个顶层函数的 作用很简单:创建Later类的实例,并将接收的函数类型参数传给Later类的构造函数。

将这段代码放到任何一个Activity 中,并在按钮的点击事件里调用p属性。 你会发现,当Activity启动的时候,later函数中的那行日志是不会打印的。只有当你首次点击 按钮的时候,日志才会打印出来,说明代码块中的代码成功执行了。而当你再次点击按钮的时 候,日志也不会再打印出来,因为代码块中的代码只会执行一次。
更多推荐


所有评论(0)