Kotlin学习之泛型与类委托和委托属性
泛型的基本用法泛型主要有两种定义方式,一种是定义泛型类,另一种是定义泛型方法,使用的语法结构都是。当然括号内的T并不是固定要求的,事实上你使用任何英文字母或单词都可以,但是通常情况下,T是一种约定俗成的泛型写法。如果要定义一个泛型类,就可以这么写:class MyClass<T> {fun method(param: T): T {return param}}在调用MyClass类和m
泛型的基本用法
泛型,即 “参数化类型”,将类型参数化,可以用在类,接口,方法上。与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
泛型主要有两种定义方式,一种是定义泛型类,另一种是定义泛型方法,使用的语法结构都是。当然括号内的T并不是固定要求的,事实上你使用任何英文字母或单词都可以,但是通常情况下,T是一种约定俗成的泛型写法。
如果要定义一个泛型类,就可以这么写:
class MyClass<T> {
fun method(param: T): T {
return param
}
}
在调用MyClass类和method()方法的时候,可以将泛型指定成具体的类型,如下所示:
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)
可以看到,现在是在调用method()方法的时候指定泛型类型了。另外,Kotlin还拥有非常出色的类型推导机制,例如传入了一个Int类型的参数,它能够自动推导出泛型的类型就是Int型,因此这里也可以直接省略泛型的指定:
val myClass = MyClass()
val result = myClass.method(123)
泛型约束
我们可以使用泛型约束来设定一个给定参数允许使用的类型。
Kotlin 中使用 : 对泛型的类型上限进行约束。
最常见的约束是上界(upper bound):
fun <T : Comparable<T>> sort(list: List<T>) {
// ……
}
Comparable 的子类型可以替代 T。 例如:
sort(listOf(1, 2, 3)) // OK。Int 是 Comparable<Int> 的子类型
sort(listOf(HashMap<Int, String>())) // 错误:HashMap<Int, String> 不是 Comparable<HashMap<Int, String>> 的子类型
默认的上界是 Any?。
对于多个上界约束条件,可以用 where 子句:
fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
where T : CharSequence,
T : Comparable<T> {
return list.filter { it > threshold }.map { it.toString() }
}
类委托
委托模式的基本理念是操作对象不会自己去处理某段逻辑,而是会把工作委托给另一个辅助对象去处理。
我们举个例子,Set是一个接口,它所存储的数据是无序且不可重复的,如果要使用Set,就需要使用它的实现类HashSet,而借助委托模式,我们可以轻松实现一个自己的实现类。
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()
}
可以看到,就是接受了一个HashSet参数,相当于一个辅助对象,直接使用辅助对象的方法,这就是委托模式,但是委托也有一定的弊端,如果接口中的待实现方法比较少还好,要是有几十甚至上百个方法的话,每个都去这样调用辅助对象中的相应方法实现,写起了就非常复杂了。这个问题在Kotlin中可以通过类委托的功能来解决。
类委托使用关键字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
}
委托属性
委托属性的核心思想是将一个属性(字段)的具体实现委托给另一个类去完成。
我们看一下委托属性的语法结构,如下所示:
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
}
}
整个委托属性的工作流程就是这样实现的,现在当我们给MyClass的p属性赋值时,就会调用Delegate类的setValue()方法,当获取MyClass中p属性的值时,就会调用Delegate类的getValue()方法。
其中getValue的参数中,第一个是声明委托属性可以在什么类中使用,第二个参数KProperty<>是Kotlin中的一个属性操作集,可以用于获取各种属性相关的值,"<>"表示不知道或者不关心泛型的具体类型
对于
val p by lazy{ ... }
其实就是委托属性,lazy是一个高阶函数,再lazy中会创建并返回一个Delegate对象,当我们调用p属性时,其实调用的时Delegate对象的getValue()方法,然后getValue()方法又会调用传入lazy中的Lambda表达式,并且调用p属性得到的值就是Lambda表达式中最后一行代码的返回值。
更多推荐

所有评论(0)