数据类型

首字母大写
String Char Boolean Int Double list Set Map

“a” to 5,“b” to 6

String

${} 字符串模板
substring(0 until -1)
split返回 origin,dest,proxy,三个字符串,。也可以返回List,返回挨个赋值而已,有可能赋值没完?
replate(){when
forEach

==字符是否匹配

===是否同一对象。新生成的就不是一个字符串了

数字

没有转换成功就返回null而不是抛异常
字符串toInt就抛异常,toIntOrNull就不抛异常
Double转int不抛异常

const

编译时常量只能在函数之外,因为编译时厂里必须在编译时赋值,二函数都是在运行时才调用,函数内的便利也是运行时赋值,编译时常量要在这些变量赋值前就已存在。

const value MAX=5

函数

具名参数
匿名参数
没有返回值的函数叫Unit函数,返回类型是Unit。
Unit解决void无法解决泛型的解释问题
TODO永远别指望运行常规,返回Nothing类型,抛出异常x可以使用\来表示特殊的函数名

匿名函数

没有名字的函数,匿名函数通常整体传递给其他函数
匿名函数会隐式或自动返回函数体最后一行语句的结果

// 变量的类型是匿名函数 // 无参,返回值类型为string
val func:()->String    = {
    val a="a"
    "b"
}
// 需要带参数时,
val func:(String)->String    = { name->
    val a="a"
    "b"
}
// it关键字
// 只有一个参数的匿名函数时,可以不写,用it代替
val func:(String)->String    = { 
    val a="a"
    "${it}  $it b"
}

// 可以省略成 // 注意是a={}就行
val func   = { 
    val a="a"
    "${it}  $it b"
}
// 多个参数时可以不在=左面写,但可以在右面name:String写

// 作为参数时,fun:()->String // 就是指定了参数和返回值
// 如果一个函数的lambda参数排在最后,或者是唯一的参数,name参数的一堆圆括号可以省略
// 传递参数的引用,可以用::fun  // 可以使用lambda的地方都可以使用函数引用
// 函数作为返回值

// 匿名内部类,创建对象。
// 注意一下,第二个参数是匿名内部类时,可以把它提取到(){
    
}

函数内联
在JVM中,定义的lambda以对象实例的形式存在,产生了内存开销。而kotlin相当于DEFINE;但是使用lambda的递归函数无法内联,否则会无线赋值循环,变异会发出警告
show kotlin

闭包
匿名函数能修改自己作用域之外的便利,引用自己作用于里的就是闭包

lambda

演算

apply

标准库函数
是一个配置函数,传入接受者,然后调研一系列
调研一个个函数累配置接收者是,变量名就省略了,因为在lambda里apply能让每隔配置函数都作用于接受者,这种行为又是又叫做相关作用于,因为lambda表达式里的所有函数调研都是针对于接受者的,或者说是针对于接受者的隐式调用

let

ley会吧接受者传给lambda,二apply什么都不传,就是使用it然后返回

编译好的java文件名就是文件名,而且还是final的

嵌套类:如果一个类只对另外一个类有用

kotlin只提供引用类型这一数据类型,出于更性能的需要,kotlin编译器会在java字节码中改用基本数据类型

数据类:专门用来存储数据的类,toString方法

data class A(var x:Int,vat y:Int){}
此时打印的时候人家就已经写过toString方法了
hashCode和equals等方法 ==
Any超类的默认实现就是使用的=== ,二data类使用的是==

还提供了copy
var b = a.copy("name") // copy对应到了构造方法上

// 数据类还可以解构,解构的是主构造的属性
其实就是帮我们重写了
operator fun component1() = exprience

类似的,如果a+b想要支持,可以重载
operatiror fun puls(other:A)=A(x+other.x,y+other.y)

属性

针对你定义的每一个属性,kotlin都会产生一个field、一个getter以及一个setter。field同来存储属性,你不能直接定义field,kotlin会封装field,保护里面的数据,只暴露给getter、setter使用。
也可以自定义getter、setter

class P{
    var name ="a"
    get()=field.captitalize()
    set(value){field=value.trim()}
    
    var age =10
    get()=field.absoluteValue
    set(value){field=value.absoluteValue}
}
// 使用的时候p.name="a"就可以,编译会调用setter
getter setter要紧跟在属性后面写

计算属性可以不写field

构造

临时变量通常用_a表示。
可以在主构造函数里定义属性,不写_就是属性了

class P(
    var _name:String
){
    var name=_name
}

class P(
    name:String
){

}
// 指定默认值
class P(
    var name:String="A"
){
}

次构造函数

construct(name:String):this(name,age=10)

construct(name:String):this(name,age=10){
    
}

init

初始化块,可以检测某构造函数的值是否有效,
初始化块代码在构造累实例时执行
初始化顺序

  • 主构造函数里什么的属性 // 就是参数
  • 类级别的属性赋值 // {里面写的
  • init里的属性赋值和函数调用 // init{里的
  • 但是上面2个不是绝对的,顺序写反也报错
  • 次构造函数里的赋值和函数调用 // 次构造函数首先调用了主构造函数,而前面3个都在主构造函数里

编译没问题不代表一定没问题,可能还会有未初始化就使用的潜在危险

延迟初始化lateinit

如果不想再构造时候初始化,name就可以使用延迟初始化

在用它之前负责初始化

class P{
    lateinit var a:String
    fun ready(){
        a="a"
    }
    fun b(){
        println(a)
    }
    // 只有调用了ready()才能调用b()
    
    // 也可以在b中用if(::a.isInitialized)判断下再使用
}

惰性初始化by lazy

延迟初始化和惰性初始化不同
暂时不初始化某个变量,使用时再初始化

val a by lazy{func1()}
private func1():String{
    return "a"
}

继承

累默认都是封闭的,要让某个类开放继承,必须使用open关键字修饰它

open class A:B("b"){}

类型转换

可以通过is检测是否是哪个类型的对象

  • 通过as可以转换类型 a as B
  • 只要使用过一次as,后面使用a时就智能转换了,不用再写as
  • 所有类的超类是Any

object

使用object可以定义一个只能产生一个实例的类:单例
使用object的三种方式

  • 对象声明:声明后直接用类名调研方法。可以定义在类内部,但不可以有构造器
  • 对象表达式:匿名内部类,与java的区别在于可以调用非接口的方法
  • 伴生对象:包级别函数
object A{
    init{
        
    }
    fun func(){}
}
// 既是类名,又是实例对象名字
A.func()

半生对象
如果你想将某个对象的初始化和一个类实例捆绑到一起,可以考虑使用半生对象,使用companion修饰,一个类只能有一个伴生对象
本质上局部静态类
无论实例化多少次,伴生对象已有一个

open class A{
    companion object{
        private const val PATH="A"
        fun func1()=FILE(PATH).readBytes()
    }
}
A.func1()
A.PATH

枚举Enum

enum class A{
    EAST,
}
A.EAST
也可以带参数

range

用in检查是否在范围之内
!in

when(a){
    "a"->""
    else{
        
    }
}

null

除非另有指定,否则不能为null值
?
安全调用操作符  a?.cappitalize()

上面是调用一次时的用法,如果要对这个对象进行多个操作呢?
a?.let{用it代替该变量}

!!又称感叹号操作符,非空断言操作符
a!!.capitalize() // 当变量为空时会执行函数,但也会抛出NPE
也可以使用if a == null
?:代表如果左面的值为null,就使用右面的值 。空合并操作符

异常

try catch
自定义异常,继承

先决条件函数

kotlin提供了一些库函数,叫内置函数,可以抛出带自定义信息的异常,这些便利函数又叫做先决条件函数,你可以用它定义先决条件,条件满足 目标代码才能执行

checkNotNull
require 如果参数为false,抛异常
requireNotNull null抛异常
error null抛异常并输出错误消息
assert  如果false抛异常
checkNotNull(a,"异常信息")

list

mutableList
+=
listOf
removeIf

// 遍历
for (a in list)
list.forEach
forEachIndexed遍历时要获取索引

解构
val (a,b,c)=list

set

setOf
set.elementAt
mutableSetOf
+=
listof().toSet().toList()
listOf().distinct()

数组

IntArray

// 创建
intArrayOf
// 对象数组
ArrayOf

Map

to看上去像关键字,但是是省略了点号和参数的特殊函数,to函数

键 to  值
Pair
mapof("a" to 1)
mapOf(pair("a",10))
getValue

getOrElse(){}//执行
getorDefault(,)//默认值


// 
map.forEach{$it.key  $it.value}
map.forEach
// mutableMapOf
+="A" to 10
put
getOrPut不存在就添加,否则返回已有键的值