Kotlin速成

kotlin中没有分号

kotlin中在后边进行类型的声明

函数

/**
 * main函数,同java一样,程序的入口
 * Unit表示返回值为空
 */
fun main():Unit{
    println("Hello Kotlin!")
}
// 带参数的函数
fun test(x:Int):Int{
    return x*2
}
// 函数参数默认值
@JvmOverloads // 表示重载,在java代码中可以使用
fun msg(name: String, age: Int = 19) { // 这里的age默认为19
    println("name = $name , age = $age")
}

变量

  • var声明为可变的
  • val声明为只读的(相当于Java中加上final的变量)
// 可写成 var age = 18,系统会自动识别
var age: Int = 18
val NAME = "JulyPost"
// 创建对象直接如此,不需要new关键字了
var person = Person()

可空类型和不可空类型

在kotlin里,所有的变量都默认是不允许为空

var a: String = "abc" // 非空类型
var b: String? = "cba" // 可空类型
a = null // 赋空报错
b = null // 可赋为空
lateinit var username:TextView // 延迟初始化

调用符

var b: String? = "cba" // 可空类型
println(b?.length) // 安全调用,如果不是空的话就调用length方法,如果是空的话就不做任何事
println(b!!.length) // 强制调用

安全调用符号?.会检查是否非空,非空则返回b.length,而强制调用!!.则会强制调用b.length

构造器

// 空构造
constructor()
// 带参数的构造
constructor(context:Context)
// 调用其他构造器
constructor(context:Context):this(context,null)
// 调用父类构造器
constructor(context:Context):super(context,1)

AnyUnit

Any可以对应java中的Object

Unit可以对应java中的void

各种集合

var dataList = arrayOf("xx", "aa") // 定义一个数组

静态函数和属性

  • 顶层函数(直接在kt文件里定义函数)
  • object声明一个单例对象,可直接使用
  • companion object 也是生成一个单例对象
  • @JvmStatic:通过这个注解,让object和companion object 的内部函数和属性,真正的生成为静态

另外,匿名内部类是用的object关键字进行创建的

object : OnClickListener {
    // ....
}

字符串

val name = "任我行"
val text = "我是${name}" // 拼接字符串,还可以是函数的返回值
val text = """
        我的第一行
        我是第二行
        我是第三行
    """.trimIndent() // 多行字符串

when

switch的高级版,分支条件支持表达式,在kotlin里,if和when都是有返回值的

var num = 21
when (num) {
    in 1..10 -> println("小于10")
    in 11..20 -> println("小于20")
    in 21..30 -> println("小于30")
    else -> println("未知")
}
// 还可以这样使用
fun getScore(name: String) = when {
    name == "Tom" -> 86
    name == "Jim" -> 77
    else -> 0
}

for,遍历

// 左闭右闭
for (i in 0..10){
    println(i)
}
// 左闭右开
for (i in 0 until 10) {
    println(i)
}
// 步长为2
for (i in 0 .. 10 step 2) {
    println(i)
}
// 降序
for (i in 10 downTo 1) {
    println(i)
}

// 对象
for (item in persons) {
    println(item.toString())
}

for (i in persons.indices) {
    println("persons[$i] = ${persons[i]}")
}

各种声明

// 抽象类
abstract class className{...}
// 接口
interface className{...}
// 注解
annotation class className{...}
// 枚举
enmu class className{...}
// 数据类
data class className{...}

标准函数

// let会将变量传入表达式中,主要作用就是配合?.来进行判空处理
fun doStudy(name:String?){
    name?.let {
        println("$it is studying")
    }
}
// with会在lambda表达式中提供第一个参数对象的上下文,并使用lambda表达式中的最后一行作为返回值返回
val list = listOf("Apple", "Banana", "Orange")
var builder = StringBuilder()
val result = with(builder) {
    append("Start")
    for (fruit in list) append("$fruit \n")
    append("finish")
    toString()
}
println(result)
// run其实和with很相似
val list = listOf("Apple", "Banana", "Orange")
var builder = StringBuilder()
val result = builder.run {
    append("Start")
    for (fruit in list) append("$fruit \n")
    append("finish")
    toString()
}
println(result)
// apply和run很相似,但是无法指定返回值
val list = listOf("Apple", "Banana", "Orange")
var builder = StringBuilder()
val result = builder.apply {
    append("Start")
    for (fruit in list) append("$fruit \n")
    append("finish")
}
println(result.toString())

编译期常量

在静态变量上加上const关键字

companion object {
    const val GOOGLE_URL = "https://www.google.com/";
}

内部类

class outer{
    // 默认静态内部类
    class inner1{
        
    }
    // 嵌套内部类
    inner class inner2{
        
    }
}

internal

当前模块可见

openfinal

在kotiln中,类和函数默认是被final修饰的(除了abstractoverride外)

而使用open来修饰,就表示可以继承

主构造器和init

class Activity constructor(name: String?) {
    private var name: String? = null

    init { // init是初始化代码块
        this.name = name
    }
}

更简洁的写法:

class Activity constructor(var name: String?) {
    // 在构造的时候就定义变量
}

=====

  • ==调用equals()进行比较
  • ===比较引用地址

?:

在kotiln中,这是一个用于简化if null的操作符

name?:"令狐冲" // 如果name是null的话,则赋值为"令狐冲"

扩展函数

可以如此使用:

fun main() {
    var text = "乌拉"
    println(text.msg())
}

fun String.msg(): String {
    return "====> $this"
}

委托

val name: String by lazy {"萧峰"} // 延迟,语句只在第一次访问时执行

协程

是一套由Kotlin官方提供的线程API,优势在于可以把不同线程的代码写在同一代码块

密封类

// kotlin会自动检查该密封类有哪些子类
sealed class Result
class Success(val msg:String):Result()

class Failure(val error:Exception):Result()

// 当使用when传入一个密封类时,kotlin编译器会自动检测此密封类有哪些子类,并强制要求你每一个情况都有做处理,好处是不用编写else语句了
fun getResultMsg(result: Result) = when(result) {
    is Success -> result.msg
    is Failure -> "error is ${result.error.message}"
}

内联函数

kotlin编译器会将内联函数中的代码在编译的时候自动替换到调用它的地方,它可以将使用Lambda表达式带来的运行时开销完全消除

inline 表示这是一个内联函数,里面的所以Lambda表达式都会被内联,但是在参数前加上noinline表示不内联

这是因为内联的函数类型参数在编译的时候会被进行代码替换,因此它没有真正的参数属性。非内联的函数类型参数可以自由地传递给其他任何函数,因为它就是一个真实的参数,而内联的函数类型参数只允许传递给另外一个内联函数,这也是它最大的局限性。

而加上crossinline表示内联函数Lambda表达式中一定不会有return关键字(但是可以有局部返回例如return@printString)

inline fun inlineTest(block1: () -> Unit, noinline block2: () -> Unit, crossinline block3: () -> Unit) {
}

运算符重载

kotlin允许我们将所有的运算符甚至其他关键字进行重载

class Money(val value: Int) {

    operator fun plus(money: Money): Money {
        val sum = value + money.value
        return Money(sum)
    }

    operator fun plus(num: Int): Money {
        val sum = value + num
        return Money(sum)
    }
}
// 使用
fun main() {
    val m1 = Money(29)
    val m2 = Money(10)
    val m3 = m1 + m2
    val m4 = m1 + 1

    println("m3.value  = ${m3.value}") // 39
    println("m4.value  = ${m4.value}") // 30
}