1.除非一个变量需要被修改,否则就是使用 val 声明
2.函数声明
fun methodNmae(param : String, ...): String {
return ""
}
3.当函数只用一行代码时,可用 = 连接, = 表示 返回值的意思
如:fun largerNumber(num1 : Int , num2 : Int) = max(num1,num2)
4.if 、when 语句 都有返回值
val str = ""
val v2 = when (str) {
"" -> 1
"1" -> 2
else -> 3
}
fun getNum(str : String)= when {
str.startsWith("") -> 1
str == "123" -> 2
str is String -> 4
else -> 3
}
5.
is 相当于 instanceof
as 相当于 强转
6.for in
for( i in 0..10){
}
0..10 0.rangeTo(10) 包含 0 和 10 相当于 [0,10]
0 until 10 包含 0 不含 10 相当于 [0,10)
downTo 表示 降序
step 表示 步
7.File 通常是用于编写Kotlin 顶层函数 和 扩展函数的
8.Kotlin中的 非抽象类 默认是不可被继承的 open
open class Person(){
}
class Student() : Person(){
}
没有参数时,Student() 的 () 可以省略
Person() 的 () 不可以省略,表示使用父类的 无参构造函数
主构造函数,次构造函数
每个类都会默认有一个无参的主构造函数
子类中的构造函数必须父类中的构造函数
当一个类既有主构造函数,又有次构造函数的时候,次构造函数必须直接和间接调用主构造函数
父类主构造函数总声明为 val/var 的参数将自动生成为该类的字段,子类中不能再声明为 val/var
主构造函数:没有函数体,直接定义在类名的后面()
次构造函数:通过 constructor 关键字定义
constructor(name : String) : this.() { }
init{ } 结构体 用来 编写主构造函数的逻辑
9.接口 interface Inter{} 没有构造函数
支持函数默认实现
10.kotlin 默认修饰符 public
修饰符 java kotlin
public 所有类可见
private 当前类可见
protected 当前类、子类
同一个包路径下
default 同一个包路径下
internal 同一个模块
11.数据类 data class className(val name : String,...)
单例类 object className{}
12.Lambda 就是一小段可以作为参数传递的代码
{param : paramType,... -> 函数体}//和oc的block比较像
最后一行代码会自动作为lambda表达式的返回值
当lambda作为函数参数的最后一个时,可以将Lambda表达式移到函数表达式外面
如果是函数唯一参数的话,可以省略函数的()
val value = 函数{Lambda}
当Lambda 只有一个参数时 可以直接用 it 代替 参数使用
13.
map 函数 对集合中的元素进行映射
filter 过滤数据
any 判断集合中是否至少有一个元素满足指定条件
all 所以元素
14.kotlin调用java 使用函数式api
该方法只接受一个参数:java单抽象方法接口(接口中只有一个待实现方法)参数
15.匿名函数使用 object 关键字声明
16.空指针检测
? 可空类型 必须用? 标明
操作符
?. 对象为空时,什么都不做,不为空时再执行 ?. 后的代码
?: val v = a ?: b a不为空 返回 a 为空则返回 b
!! 非空断言,不对对象进行指针检测
17.
let{ it -> } 函数 {}中 参数(it) 为 调用者 对象,let函数返回值 block 的值
在let中多条语句使用全局变量时是安全的,不担心其他线程修改
可以和 ?. 一起用 进行辅助判空处理 obj?.let{ it -> }
with(obj,{}) 函数 {}中提供 obj 对象的 上下文,Lambda 最后一句作为返回值
连续调用同一个对象的多个方法时可用
run{} 函数 obj.run{} {}中提供 obj 对象的 上下文,Lambda 最后一句作为返回值
apply{} 函数 obj.apply{} {}中提供 obj 对象的 上下文,apply函数返回 调用者对象 obj
18.字符串内嵌表达式 ${}
19.companion object (名字为Companion?默认没有,可指定){ } 伴生对象,每个类只能有一个伴生类
真正的静态方法 需要在方法上 @JvmStatic ,只能加在单例类 或者 companion object的方法上
顶层方法 被kotlin编译器编译成静态方法
20.密封类 sealed class 可被继承,本身及所有子类都只能定义在同一个文件的顶层位置,不能嵌套在其他类中
sealed class Result
class Success(val msg : String) : Result()
class Failure(val error : Exception) : Result()
可结合 when/if 条件语句使用
21.高阶函数 一个函数作为另一个函数的参数 或者 返回值类型
(param , ...)-> Unit
::method 函数引用
className.() -> String 表示 将 () -> String 函数定义在 className 这个类中
22.内联函数 inline ,在编译时,会将inline函数替换到调用的地方
Lambda表达式 在底层都会转换成匿名类(Function接口,kotlin内置接口,包含一个待实现的invoke函数)的方式实现,
每次调用都会产生一个匿名类对象,造成性能和内存的开销
函数加上 inline 编译时会将 函数的所有函数类型参数进行内联, 使用 noinline 声明不需要内联的 函数型参数
inline 的函数型参数(因为在编译时会替换到使用位置,它没有参数属性)只能传给 另外一个 inline函数,
非内联函数参数(是真正的参数)可以自由传递
inline 函数可以使用return 进行函数返回(返回最外层函数,相当于在调用函数的地方 return),
非内联函数只能进行局部返回(返回Lambda 函数外面) return@当前函数名称 且不再执行Lambda中后面的语句
如果在inline高阶函数中,创建了另外的Lambda或者匿名类的实现,并在这些实现中调用函数型参数,会报错
(非inline函数没问题,应为inline函数允许 return)
使用 crossline关键字修饰 函数型参数,表示在inline函数的Lambda表达式中不适用return,可以局部返回
23.可变参数 vararg ( var array )
24.泛型 上界限 Any?
25.类委托,属性委托 by
委托,设计模式,操作对象不想自己处理某个逻辑,而是把工作委托给另外一个对象去处理
类委托:将一个类的具体实现委托给另外一个类去完成
class MySet<T> (val helperSet : HashSet<T>) : Set<T> by helperSet{
对某个方法重写
新的方法
}
属性委托:将一个属性/字段 委托给另一个类去完成
var p by Delegate()
将p 的具体实现委托给 Delegate() 类实现,获取p时,调用 Delegate 的 getValue() 方法,赋值时调用 setValue()
class MyLazy<T>(val bolck: () -> T) {
var value: Any? = null
operator fun getValue(any: Any?, prop: KProperty<*>): T {
if (value == null) {
value = bolck()
}
return value as T
}
}
委托类中的 getVale/setValue 方法必须使用 operator 声明
方法中第一个参数:表示委托可以在哪个类中使用
第二个参数:kotlin中的属性操作类,可以获取各种属性相关的值
<*>星投影 泛型 表示不关心泛型的具体类型,类似java <?>
by lazy 懒加载 lazy 是一个顶层高阶函数
lateinit 延迟初始化
26.infix 中缀表达式 to 不是关键字
A to B 实为 A.to(B)
使用 infix 声明函数,不能定义顶层函数,只能是某个类的成员函数,并且函数有且只有1个参数
27.运算符重载 operator
28.
Class<T> A : B
协变 out 生产者(我从生产者这里拿东西) 只能读取数据 <? extend T>
Class<A> 相当于 Class<B> 的子类型 Class 在泛型T上是协变 如 List<T>
class Data<out T>(val data : T?) 此时的构造函数上的 T 因为使用 val 修饰 可以 出现在 in 位置
或者 private var data : T? 保证这个泛型 T 对应于外部是不可修改的 就可以
逆变 in 消费者(我给消费者添加东西) 只能接受数据 <? super T>
Class<B> 相当于 Class<A> 的子类型 Class 在泛型T上是逆变 如 Comparable<T>
PECS PEO-CSI
可以 声明处 型变
使用 @UnsafeVariance 注解
29.泛型的实化
java的泛型是通过类型擦除机制来实现,泛型只在编译时起作用,JVM识别不出来泛型类型
由于inline函数 会直接替换到使用它的位置,这样就不存在泛型擦除的问题了
inline fun <reified T> getGenericType() = T::class.java
30.协成 在单线程下模拟多线程的效果,通过挂起、恢复来调度
Global.launch{} 可以创建一个协成作用域,创建的是顶层协成,该协成当应用程序结束时也会一起结束
deley(1000) 函数可以让当前协成延迟指定时间后再运行,非阻塞式挂起函数,只会挂起当前协成,不影响其他协成
只能在协成作用域或挂起函数中调用
runBlocking{} 可以创建一个协成作用域,当该协成内的代码,或子协成没有执行完之前,会阻塞当前线程(不建议正式环境使用)
launch{} 必须在协成作用域中调用,会创建一个子协成
子协成特点:当外部作用域的协成结束了,该作用域下的多有子协成也会一同结束
suspend 关键字 修饰的函数 会被声明成 挂起函数 但是 不提供 协成作用域,挂起函数之间可以相互调用
coroutineScope{} 函数是一个 挂起函数 ,会继承外部的协成作用域,并创建一个子作用域,
保证作用域中的代码和子协成在全部执行完之前,阻塞当前 协成
取消协成
Global.launch{},luanch{} 函数会返回 一个 Job 对象 调用 job.cancel() 取消协成
常用用法:先创建Job对象,把job对象传入 CoroutineScope() 函数中 获取CoroutineScope对象 调用对象的launch创建协成
这样创建的协成都会关联到job对象的作用域下 调用一次 cancel() 取消该作用域中全部协成
val job = Job()
val scope = CoroutineScope(job)
scope.launch{}
job.cancel()
async{} 函数可以创建一个协成并返回 Deferred 对象,调用Deferred对象await()获取它的执行结果
须在协成作用域中调用
val v = async{}.await() 这样调用 async中代码会立即执行,
但是如果代码块中代码未执行完毕,await()会阻塞当前协成,直到获取到结果
可修改为 val deferred = async{}
...
在协成最后调用 deferred.await() 多个协成可同时执行
withContext(指定线程参数) 函数 相当于 async{}.await()
Dispathcers.Defult 默认低并发线程
IO 高并发线程
Main Android中主线程
suspendCoroutine{ continuation -> } 在协成作用域或挂起函数中调用
作用:将当前协成挂起,在一个普通线程中执行Lambda中代码,Lambda 参数 为对象 continuation,
通过调用 continuation.resume() 或 continuation.resumeWithException() 恢复协成
liveData(){} 函数是 lifecycle-livedata-ktx 库提供的,可以自动构建并返回一个LiveData对象,
并在它的代码块中提供一个挂起函数的上下文
可以通过 kotlin 内置 Result.success()/.failure()包装数据
通过emit(result)将包装的数据返回
Kotlin 中 双冒号操作符 表示把一个方法当做一个参数,传递到另一个方法中进行使用,通俗的来讲就是引用一个方法
//const 必须修饰val
//const 只允许在top-level级别和object中声明
//const val 可见性为public final static,可以直接访问。
//val 可见性为private final static,并且val 会生成方法getNormalObject(),通过方法调用访问。