kotlin学习资料
kotlin学习要点
函数式API(Lambda表达式)
语法结构
完整结构:
{参数1:参数类型,参数2:参数类型 ,..->函数体}
参数类型大多数可省略:
{参数1,参数2 -> 函数体}
Lambda只有一个参数,可用it代替参数,只保留函数体:
{it}
- 当lambda表达式为函数的最后一个参数时,可将表达式移到括号外面;当仅有一个lambda表达式参数时,可将()省略。
fun(lambda) <=> fun()lambda <=> fun lambda
空检测
加!!像Java一样抛出空异常,加?可不做处理返回值为 null或配合?:做空判断处理
- obj?.do() 非空时执行 <=> if(obj!=null) obj.do()
- a = obj?:b <=> a = if(obj!=null) obj else b
- obj!!.do() 非空时执行,空时断言报错 <=> if(obj!=null) obj.do() else throws Exception
默认参数
/**
* 默认参数 可选
*/
fun getUserInfo(name:String,age:Int ,sex:String="male",address:String)="姓名:$name 年龄:$age 性别:$sex 地址:$address"
//调用 有默认参数的可不传,没有默认值则必传 若默认参数不在最后,则必传
val res = getUserInfo("guchao",30,"male","焦作沁阳市")
//若不想传默认参数,但其后仍有参数,可通过键值对方式传参
val res = getUserInfo("guchao",30,address = "焦作沁阳市")
标准函数
- with 场景:连续调用通一个对象的多个方法
val result = with(obj){
....
"value" //最后一行是返回值
}
- run 场景:同with,只是使用方式不一样,
val result = obj.run{
//obj的上下文
"value" //最后一行是返回值
}
- apply 场景:使用方式同run,但无法指定返回值,自动返回对象本身
val result = obj.apply{
//obj的上下文
}
//result == obj
- let 场景:使用方式同run,但不持有obj的上下文
val result = obj.let{
//将obj对象传入 以it 可调用
"value" //最后一行是返回值
}
- repeat 常见:将一件事重复n遍执行
repeat(n){
//需重复执行的代码
}
定义静态方法
- object 对象里的方法相当于静态方法
//Util.function() 即可调用
object Util{
@JvmStatic
fun function(){}
}
- 通过半生对象定义静态方法(实质是Util类中伴生对象的实例方法)
//Util.function() 即可调用
class Util{
companion object {
@JvmStatic //该注释会将方法编译成真正的静态方法
fun function(){}
}
}
- 通过@JvmStatic注解定义(只能加在对象类 或伴生对象类中的方法上)
- 顶层方法(类之外的方法)
关键字
- 延时初始化 lateinit
class Demo{
private lateinit var param:String //延迟初始化
fun somemethod(){
if(!::param.isInitialized){ //::param.isInitialized 来判断是否初始化过
param = "HelloWorld"
}
}
}
- 定义常量 const (const 只能在单例类、伴生对象或顶层方法中才能使用)
- 密封类 sealed 好处:kotlin会自动检测密封类有哪些子类,并强制要求你将每个子类所对应的条件全部处理
//实现
sealed class Base()
class A :Base(){
}
class B :Base(){
}
//使用 不可能出现其他情况,必须实现Base所有子类所对应的条件
when(base:Base){
A->...
B->...
}
- 运算符重载 operator 重新定义运算符的含义,实现对象的运算
//定义重载运算符的对象类
class Money(val value:Int){
operator fun plus(money:Money):Money{
val sum = value + money.value
return Money(sum)
}
}
- a+b 调用 a.plus(b)
- a-b 调用 a.minus(b)
- a*b 调用 a.times(b)
- a/b 调用 a.div(b)
- a%b 调用 a.rem(b)
- a++ 调用 a.inc()
- a-- 调用 a.dec()
- +av 调用 a.unaryPlus()
- -a 调用 a.unaryMinus()
- !a 调用 a.not()
- a==b | a>b | a<b 调用 a.equals(b)
- a>=b | a<=b 调用 a.compareTo(b)
- a…b 调用 a.rangeTo(b)
- a[b] 调用 a.get(b)
- a[b]=c 调用 a.set(b,c)
- a in b 调用 b.contains(a)
扩展函数
- 扩展函数语法
fun ClassName.methodName(param1:Int, param2:Int):Int{
...
return 0
}
高阶函数
如果一个函数接收另一个函数作为参数,或返回值是另一个函数,那么该函数就是高阶函数。
- 高阶函数
//定义高阶函数
fun operation(p1: Int, p2: Int, lambda: (Int, Int) -> Int?): Int? {
return lambda(p1, p2)
}
//定义函数 加法
val plus: (Int, Int) -> Int = { a: Int, b: Int -> a + b } //Lambda表达式
//定义函数减法
fun minus(a:Int,b: Int):Int{
return a-b
}
//使用
val res = operation(5, 6, plus) //函数变量
val res1 = operation(5,1,::minus) //::minus 表示函数引用
val res2 = operation(5, 6) { p1, p2 -> p1 * p2 } //直接传入lambda表达式
- 内联函数(定义高阶函数时加上inline关键字声明即可)
//完全消除Lambda表达式带来的运行时开销
inline fun operation(p1: Int, p2: Int, lambda: (Int, Int) -> Int?): Int? {
return lambda(p1, p2)
}
- nionline与crossinline
//nionline 作用:内联高阶函数接收多个函数类型参数时,进行内联排除
inline fun inlineTest(block1:()->Unit,noinline block2:()->Unit){
}
//crossinline 作用:相当于契约,保证高阶函数的匿名类实现中不允许使用return关键字进行函数返回
inline fun runRunnable(crossinline block:()->Unit){//不使用crossinline,则会编译报错
val runnable = Runnable{
block()
}
runnable.run()
}
泛型
- 定义泛型类
//类名后使用<>声明泛型
class MyClass<T>{
fun method(param:T):T{
return param
}
}
//调用
val myClass = MyClass<Int>()
val result = myClass.method(110)
- 定义泛型方法
//方法名前使用<> 声明泛型方法
fun <T> method(param:T):T{
return param
}
//调用
val result = method<Int>(110)
- 对泛型类型进行约束
fun <T:Number> method(param:T){
return param
}
委托
- 类委托
精髓:将一个类的具体实现委托给另一个类去完成
//创建接口
interface Base{
fun print()
}
//创建被委托的类
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
// 通过关键字 by 建立委托类
class Derived(b: Base) : Base by b
fun main(args:Array<String>){
val b = BaseImpl(110)
Derived(b).print() // 输出 110
}
- 属性委托
/**
* Created by guc on 2020/5/7.
* 描述:属性委托
*/
class Delegate {
var propValue:Any? = "default"
/**
* [any] 指定任何类都可以使用该代理
* [prop] 属性操作类,可获取各种属性相关的值
*/
operator fun getValue(any: Any?,prop:KProperty<*>):Any?{
return propValue
}
/**
* [any] 指定任何类都可以使用该代理
* [prop] 属性操作类,可获取各种属性相关的值
* [value] 赋给委托属性的值
*/
operator fun setValue(any: Any?,prop:KProperty<*>,value:Any?){
propValue = value
}
}
infix函数
A to B <=> A.to(B)
//A.method(B) 等价于 A method B
infix fun String.beginWith(prefix: String) = startsWith(prefix)
string.beginWith(prefix) == string beginWith prefix
泛型的实化与泛型的协变
- 泛型的实化允许获取泛型的实际类型(使用inline 和 reified 关键字)
inline fun <reified T> startActivity(context: Context,block: Intent.() -> Unit) {
val intent = Intent(context, T::class.java)
intent.block()
context.startActivity(intent)
}
- 泛型的协变
interface MyClass<T>{
//in位置:参数位 out位值:返回位
fun method(param:T):T
}
- out T :T只能出现在out位置,相当于禁用了set方法
- in T :T只能出现在in位置
协变:假如定义一个MyClass<T>的泛型类,其中A是B的子类,同时MyClass<A>又是MyClass<B>的子类型,那么我们就成MyClass在T这个泛型上的协变。
实现:MyClass<out T> 指定T只可出现在out位置(即泛型类在其泛型类型的数据上只读)
class SimpleData<out T>(val data:T?) {
fun get(): T? = data
}
- 泛型的逆变
逆变:假如定义一个MyClass<T>的泛型类,其中A是B的子类,同时MyClass<B>又是MyClass<A>的子类型,那么我们就成MyClass在T这个泛型上的协变。
实现:MyClass<in T> 指定T只能出现在in位置(即泛型类在其泛型类型的数据上只可写,不可读)
/*
* 描述:泛型类逆变
*/
interface Transformer<in T> {
fun transform(t:T):String
}
协程
- 添加依赖
//协程使用
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
- 基本用法
- GlobalScope.launch {}//创建一个顶层协程,应用程序运行结束时也会跟着结束
- runBlocking{} //保证在协程作用域内的所有代码和子协程全部执行完。阻塞当前线程
- runBlocking{ launch{}…} //创建多个协程
注:suspend 可将函数声明为挂起函数,就可以调用其他挂起函数 delay()
suspend fun printDot(){
println(".")
delay(100)
}