4.2.2 常量和只读变量
常量和只读变量一旦初始化就不能再被修改。在kotlin中,声明常量是在标识符的前面加上val或const val 关键字。
1. val 声明的是运行时变量,在运行时进行初始化
2.const val 声明的是编译时常量,在编译时初始化
val 相当于 final
const val 相当于 public static final
5.4.1 可空类型概念
例子:
var n:Int = 10 n=null 编译错误
var n:Int?=10 n=null 可以
Kotlin 安全运算符
1.安全调用运算符?.
2.安全转换运算符 as?.
3.Elvis 运算符?:
也叫 空值合并运算符 例子:
var a=divide(100,0)
int x=a?:0
结果x=0
意思就是 假如a是空值,则让x=0 相当于给他一个默认值,空的就赋值0,避免了null 报错
4.非空断言 !!
6.2.5字符串比较
val s1="Hello"
val s2="HELLO"
s1.equals(s2,ignoreCase = true)//忽略大小写比较内容是否相等 结果为true
除了equals 之外,还有compareTo ,这个比较的是顺序,返回的是数字,
如果俩个字符串相等结果为0,前面的小就返回负数,大就返回正数
7.5其他运算符
冒号: 用于变量或者常量类型声明,以及声明继承父类和实现接口
小括号():起到改变表达式运算顺序的作用,他的优先级更高
中括号【】:索引访问运算符号
等号:赋值
可空符?标识一个可空类型
安全调用运算符?. 调用非空类型的函数或者属性
Elvis ?: 空值合并运算符
非空断言 !! 就是一定不会是空值
双冒号:: 引用类,属性或函数
区间.. :表示一个范围区间
箭头-> 用来声明lambda 表达式
展开运算符*将数组传递给可变参数时使用
8.1分支结构
if else
when(){
x->{
}
}
do{
}while()
8.2.3 for语句
for( a int 0..9){
}
for(a int 0..list.size){}
for(item in list){}
//获取数组索引
for(i in list.indices){}
8.4 使用区间
for(x in 0..5) //定义区间包含0和5
for(x int 0 until 5) //定义半开区间包含0,不包含5
8.4.2 使用in 和!in 关键字
例子
var testScore=80 //设置一个测试分数
var grade=when(testScore){
in 90..100->"优秀"
in 80 until 90->"良"
in 60 until 80->"中"
in 0 until 60->"差"
else->"无"
}
if(testScore !in 60..100){
println("不及格")
}
val strList= arrayOf("刘备","关羽","关羽")
var name="赵云"
if(name !in strList){
println(name+"没结义")
}
函数
fun 函数名(参数列表) : 返回值类型{
函数体
return 返回值
}
9.3.1使用命名参数调用函数
xxx(100,100)//没有采用
xxx(width=100,height=100)//采用命名函数
xxx(100,height=100)//采用
这个操作,之前的java使用参数提示的,命名函数可能有其他操作吧
9.3.2参数默认值
9.3.3可变参数
这里可以和扩展运算符*结合
9.5 局部函数
9.6匿名函数
fun nimingTEST(a:Int,b:Int):String{
val xxx=if(a==b)
fun (x1 : Int, x2:Int):String{return (x1+x2).toString() }
else
fun (x1 : Int, x2:Int):String{return (x1-x2).toString() }
return xxx(a,b)
}
感觉这个不如一条一条列出来清晰
10.4.1 Bean
10.4.3延迟初始化属性
lateinit 字面意思延迟初始化,用的时候才会实例化,实例化是占内存,这个可以避免内存消耗吧
lateinit 关键字放在var之前,不能是可空类型
10.4.6可观察属性
这里做了一个点击查看的操作,是可以监听到的,
10.5.1扩展函数
//基本数据类型扩展
fun Double.interestBy(interestRate: Double): Double {
return this * interestRate
}
//自定义账户类
class Account {
var amount: Double = 0.0 //账户金额
var owner: String = "" //账户名
}
//账户类函数扩展
fun Account.interestBy(interestRate: Double): Double {
return this.amount * interestRate
}
Double 类型可以引用
看起来很方便
这个看起来只能在当前类中使用
肯定可以写全局的
写一个文件,注意是文件不是类
这样直接在其他地方可以用了,需要注意是在同一个包里
10.6构造函数
默认是自带无参数构造
10.8.1声明数据类
创建一个类,区分了是数据类还是工具类还是其他类
数据类关键词data
添加一个data关键字后变成了数据类,底层数据类
底层的三个方法
hash() toString equals 另外增加了一个copy的方法
data 修饰的类 参数有要求,必须要有var/val修饰
打印出来是2,也就是 修改了其中一个值其他都是之前的
10.10嵌套类
无法访问外部类成员变量
加一个内部类关键字就可以了
10.11.1对象表达式
Object关键字
接口回调
10.11.3 伴生对象
Kotlin 没有 java中的Static 所以
伴生类不能访问外部类的成员属性啥的,这个交互起来,还是以外部类为主
11.继承与多态
关键字open,Kotlin 默认是 final修饰的类和属性只有加上open才能被继承
都一样,哪个代码少用哪个
11.4.1 is as
is 相当于 instanceof as 相当于强类型转换
13.2.4 函数作为参数调用
费劲巴拉的你直接宽*高不就得了。
13.3Lambda 表达式
使用案例2
简便了为啥我感觉花里胡哨的没有java通俗易懂
简化之后Int直接省略了
省略写法
没啥意思啊~
13.3.4 return
return@foreach可以跳出本次循环,return 和 break 会跳出整个循环
这种写法就可以用continue
13.4.闭包与捕获变量
这个有点绕
13.5内联函数
关键字inline
13.5.2Let函数
let的特点 1 最后一行是赋值
let特点2非空检查
在koltin中防止引用null对象,所有的对象都可以调用let方法,为空时不执行,不为空时执行
a是自己取的名字,可以使用默认的it
let特点3 直接读取调用链结果
例子
这里拿到的是他们的长度,但是我想要字符串本身
直接拿到数据
map是转换的意思
run
with
和run类似,但是他没有返回值
apply
also
泛型
假设要做一个比较的方法
这里只能比较int 参数
在方法名之前加上<T>就行了,一般都是TEKU
如果是多类型的<T,U>,中间用逗号隔开
14.1.3泛型约束
假如只想比较数字方向的类型,可以大概给个Number,他的子类有Int Double
也可以写成
Comparable<T>包括了很多可以比较的类型,前后的参数一定要一个类型的
14.1.4可空类型参数
假如参数是空的,我们需要防止
可空
不可空
3大基础函数
filter
过滤
map
转换
reduce
聚合
聚合函数
阶乘
// n个元素
val intArray = IntArray(2) {
it + 1
}
val reduce = intArray.reduce { acc, i ->
acc * i
}
println(reduce)
从1开始到n的阶乘
结果是从0到999
19协程
在执行阻塞任务时.会将这种任务放到子线程中,执行完成再回调(callback)主线程,更新UI等操作,这就是异步编程。协程底层库也是异步处理阻塞任务,但是这些复杂的操作被底层库封装起来。协程代码的程序流是顺序的,不再需要一堆的回调函数,就像同步代码一样,也便于理解,调试和开发
线程是抢占式的,线程调度是操作系统级的,而协程是协作式的,协程调度是用户级的,协程是用户空间线程,与操作系统无关,所以需要用户自己去做调度
19.2创建协程
launch 函数的返回值是一个Job对象,Job是协程要执行的任务,可以将Job对象看做协程本身,所有对协程的操作都是通过Job对象完成的,协程的状态和生命周期都是通过Job反应出来的
Job对象的常用属性和函数
isActive 判断Job是否处于活动状态
isCompleted判断Job是否处于完成状态
isCanceled判断Job是否处于取消状态
start 开始Job
cancel取消Job
join 当前协程处于等待状态,知道Job完成,join是一个挂起函数,只能在协程体中或其他的挂起函数中调用
launch 和 runBlock 是相反的,runBlock 会阻塞线程
从这里可以看出通过.launch开启一个协程会被先挂起,同级别的代码会先运行,
suspend是一个协程的关键字,被他修饰的函数就会挂起,例如这个delay(),他只能在协程方法体内运行,当遇到了suspend函数的时候,当前的协程就会主动逃离当前的线程去别的地方执行任务,当函数比如delay 500 执行完了,他就会回来线程继续执行
suspend就是让协程该走就走,执行完在回来,给主线程或者说同级别的代码块更好的运行
这里的运行顺序换成runBlock
和上面相反程序会等runblock 执行完再执行下面
由于这种操作有可能阻塞主线程,所以很少有
简单实用的场景
butStart.setOnClickListener(View.OnClickListener {
val coroutineScope = CoroutineScope(Dispatchers.Main)
coroutineScope.launch {
withContext(Dispatchers.IO) {
Thread.sleep(5000)
a = 20
}
text.text = ""+a
}
})
可以通过withContext 把它切换到子线程,
以后用它替换java的AsycnTask吧,至于其他方法太烦了