上一章地址
文章目录
前言
这章接着上一章语法总结继续讲解,主要讲kotlin和java不一样的地方
(40)嵌套类
(41)数据类 data class 提供toString,equals,hashCode个性化实现,==
符号比较值,为每个属性生成operator修饰的componentN()方法,支持解构,生成copy方法,方便对象复制
class playerScore(val experience:Int,val level:Int) {
operator fun component1() = experience
operator fun component2() = level
}
fun main() {
//解构
val(x,y) = playerScore(1,2)
println(x)
println(y)
}
- 数据类必须有至少一个参数数的主构造函数
- 数据类的主构造函数参数必须是val或var
- 数据类不能使用abstract、open、sealed和inner修饰
data class dataTest(var x:Int, var y:Int){
val isInB = x>0 && y>0
}
(42)枚举类 enum class
(43)运算符重载
(44)密封类·sealed class(一种特殊的抽象类)
- 密封类的直接子类必须和密封类在同一个文件中
- 密封类的间接子类可以在不同文件中
(45)接口 interface,所有的属性和函数实现都需要override关键字
interface Moveable{
var maxSpeed : Int
get() = (0..4).shuffled().last()
set(value) {}
var wheel : Int
fun move(moveable: Moveable):String
}
class Car(
_name:String,
override var wheel : Int = 4
):Moveable{
override var maxSpeed: Int
get() = super.maxSpeed
set(value) {}
override fun move(moveable: Moveable): String {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
(46)抽象类 abstract
abstract class Gun(val range:Int){
abstract fun pullA():String
}
class AK47(val pr:Int):Gun(400),Moveable{
override fun move(mo: Moveable): String {
TODO("not implemented")
}
override val max: Int
get() = super.max
override var wheel: Int
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
set(value) {}
override fun pullA(): String {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
(47)泛型
class fanXing5<T:Human>(vararg item:T){
var ab = false
private var sub : Array<out T> = item
fun tech(index: Int):T?{
return sub[index].takeIf { ab }
}
//return -> R
//业务:取元素时把元素进行修改T->R
fun <R>tech(index: Int,suba:(T) -> R):R?{
return suba(sub[index]).takeIf { ab }
}
//a[i] --> a.get(i)
operator fun get(index: Int):T? = sub[index]?.takeIf { ab }
}
- operator:运算符重载
- 父类泛型对象可赋值给子类泛型对象:
- 子类泛型对象可赋值给父类泛型对象:
(48)扩展函数:不直接修改类定义的情况增加类的功能,封装频率使用较高的代码,字节码中被编译成静态方法
fun Any.easyPrint01() = println(this)
fun Any.easyPrint02():Any{
println(this)
return this
}
fun <T> T.easyPrint03():T{
println(this)
return this
}
(49)扩展属性
val String.numVowels
get() = count { "aeiou".contains(it) }
(50)infix中缀函数
- map中
1 to "one"
就是中缀表达式 - 使用infix的条件(1)只有一个参数(2)方法前加infix(3)成员方法或者扩展方法
(51)DSL领域特定语言,android中可代替xml动态实现布局(非必要),kotlin中实现DSL需要两样东西
-
扩展函数
-
带接收者的Lambda表达式
build:StringBuilder.()->Unit
(调用者类型.(参数类型)->返回值类型)
(52)函数式编程:变换、过滤、合并
- 变换:map和flatMap
fun main() {
val animals = listOf("a","b","c")
//不可变副本在链上函数间的传递
val babys = animals
.map { animal -> "A baby $animal" }
.map { baby -> "aaa $baby" }
println(animals)
println(babys)
val animalLength = animals.map { it.length }
println(animalLength)
val flat = listOf(listOf("111","123","123"), listOf("111","45","435")).flatMap { it.filter { it.contains("1") } }
println(flat)
val aa = listOf("123","211","3234").filter { it.contains("1") }
println(aa)
}
- 过滤 filter
val num = listOf(3,4,5,6,7,8,9,11,13)
val pri = num.filter { number ->
(2 until number).map { number%it }.none { it==0 }
}
println(pri)
- 合并 zip fold reduce
val aa = listOf("123","211","3234")
val bb = listOf(1,2,3)
val cc = aa.zip(bb).toMap()
println(cc)
//fold函数
val ee = listOf(1,2,3,4).fold(2){acc,num ->
println(acc)
acc + (num*3)
}
println(ee)
优点:
- 累加变量隐式定义
- 函数运算结果会自动赋值给累加变量,降低出错率
- 执行新任务函数很容易添加到调用链上,都兼容Iterable类型
(53)惰性集合:序列(Sequence)
Sequences 序列接口强大在于其操作的实现方式。序列中的元素求值都是惰性的,所以可以更加高效使用序列来对数据集中的元素进行链式操作 (映射、过滤、变换等), 而不需要像普通集合那样,每进行一次数据操作,都必须要开辟新的内存来存储中间结果。
-
中间操作:如果返回的是一个 Sequence 那么这就是一个中间操作,操作被延迟,在末端操作被调用时,才会输出提示
-
末端操作:执行原来中间操作的所有延迟计算
-
创建序列:(1)
list.asSequence()
(2)val num = generateSequence(0){it+1}
(3)val numOnce = num.constrainOnce()
一次性序列 -
数据量越大,性能越好
-
优化原理:不会开辟空间保存中间值,只算出结果
-
实例化对应的 Sequence 子类对象,每个子类对象重写了 Sequence 接口中的 iterator () 抽象方法,内部实现根据传入的迭代器对象中的数据元素,加以变换、过滤、合并等操作,返回一个新的迭代器对象。这就能解释为什么序列中工作原理是逐个元素执行不同的操作,而不是像普通集合所有元素先执行 A 操作,再所有元素执行 B 操作。
(54)协程:轻量级线程
- 为什么不用线程? 回调地狱:callBack里嵌套callback,代码可读性差
- 协程以后将会单独开一章讲解