android学习笔记(2)

60 阅读9分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Kotlin

变量

Kotlin中声明变量只允许使用关键字valvar

  • val (value)用于声明不可变的变量,相当于Java中的final变量。
  • var (variable)用于声明可变的变量,相当于Java中的非final变量。

类型

Kotlin拥有类型推导机制,声明且赋值后,自动推导成对应类型,且不允许再赋值成其他类型。

但是对一个变量延迟赋值的话,Kotlin无法自动推导他的类型。这时候就需要显示声明变量类型。

val a: Int = 10

Kotnlin中,Int为首字母大写,Kotlin完全抛弃了Java的基础类型,全部使用对象数据类型。

Java基本数据类型Kotlin对象数据类型数据类型说明
intInt整型
longLong长整型
shortShort短整型
floatFloat单精度浮点型
doubleDouble双精度浮点型
booleanBoolean布尔型
charChar字符型
byteByte字节型

函数

fun largeNumber(param1 : Int, param2 : Int) : Int {
    return max(param1, param2)
}

当一个函数中只有一行代码时,Kotlin允许我们不必编写函数体,可以直接将唯一的一行代码写在函数定义的尾部,中间用等号连接即可。加上Kotlin的类型推导机制,以上代码可以简化为

fun largeNumber(param1 : Int, param2 : Int) = max(param1, param2)

逻辑控制

if 条件语句

Kotlin中的if语句相比于Java有一个额外的功能,它是可以有返回值的,返回值就是if语句每一个条件中最后一行代码的返回值

fun largerNumber(num1: Int, num2: Int): Int {
    val value = if (num1 > num2) {
        num1
    } else {
        num2
    }
    return value
}

语法糖优化精简

fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) {
    num1
} else {
    num2
}
//fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) num1 else num2

when 条件语句

精确匹配

fun getScore(name: String) = when (name) {
    "Tom" -> 86
    "Jim" -> 77
    "Jack" -> 95
    "Lily" -> 100
    else -> 0
}

类型匹配

fun checkNumber(num: Number) {
    when (num) {
        is Int -> println("number is Int")
        is Double -> println("number is Double")
        else -> println("number not support")
    }
}
//is关键字就是类型匹配的核心,它相当于Java中的instanceof关键字

when语句的结构体:

匹配值 -> { 执行逻辑 }

当执行逻辑只有一行代码是,可以省略{}

when可以不带参数

fun getScore(name: String) = when {
    name.startsWith("Tom") -> 86
    name == "Jim" -> 77
    name == "Jack" -> 95
    name == "Lily" -> 100
    else -> 0
}

循环语句

Kotlin中的区间概念

val range = 0..10

上述代码表示创建了一个0到10的区间,并且两端都是闭区间,用数学的方式表达出来就是[0, 10]

其中,..是创建两端闭区间的关键字,在..的两边指定区间的左右端点就可以创建一个区间了。

fun main() {
    for (i in 0..10) {
        println(i)
    }
}

Kotlin中可以使用until关键字来创建一个左闭右开的区间

val range = 0 until 10

上述代码表示创建了一个0到10的左闭右开区间,它的数学表达方式是[0, 10)

step关键字用于跳过其中的一些元素

fun main() {
    for (i in 0 until 10 step 2) {
        println(i)
    }
}

..until关键字都要求区间的左端必须小于等于区间的右端,也就是这两种关键字创建的都是一个升序的区间

降序的区间,可以使用downTo关键字

fun main() {
    for (i in 10 downTo 1) {
        println(i)
    }
}

Kotlin中任何一个非抽象类默认都是不可以被继承的,要让一个类可以被继承,需要加上open关键字

open class Person{
    
}

继承一个类在Kotlin中使用冒号

class Student : Person() {
    
}

构造函数

主构造函数

每个类默认都会有一个不带参数的主构造函数,也可以显式的指明参数。主构造函数的特点是没有函数体,直接定义在类名后面即可。

class Student(val sno: String, val grade: Int) : Person() {
    
}

如果主构造函数需要编写逻辑,Kotlin提供了init结构体,所有主构造函数的逻辑都可以写在里面

class Student(val sno: String, val grade: Int) : Person() {
    init {
        println("sno is " + sno)
        println("grade is " + grade)
    }
}

子类中的构造函数必须调用父类中的构造函数。

而子类具体调用父类中的哪个构造函数,在Kotlin中体现在继承时冒号后的括号。

class Student(val sno: String, val grade: Int) : Person() {
    
}
//在这里,Person类后面一对空括号表示Student类的主构造函数在初始化的时候会调用Person类的无参构造函数,即使无参数的情况下,括号也不能省略。

调用父类的有参构造函数则如下

open class Person(val name : String, val age: Int) {
    //...
}

class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
    //...
}
//在子类中增加父类拥有的字段时,不加关键字 var 或者 val,因为声明成 val 或 var 的参数,将自动成为该类的字段,与父类中同名的字段冲突。

次构造函数

任何一个类只能有一个主构造函数,但可以有多个次构造函数。次构造函数也可以用于实例化对象,这一点与主构造函数没有什么区别,但次构造函数时拥有函数体的。

Kotlin规定,当一个类既有主构造函数又有次构造函数时,所有次构造函数必须调用主构造函数(包括间接调用)

class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
    constructor(name: String, age: Int) : this("", 0, name, age) {
        //次构造函数1
    }

    constructor() : this("", 0) {
        //次构造函数2
    }
}

次构造函数通过constructor关键字来定义的。

次构造函数1通过this关键字调用主构造函数;次构造函数2通过this关键字调用次构造函数、间接调用主构造函数。

当一个类没有显式定义主构造函数,同时又定义了次构造函数,则继承类时,被继承类不需要加括号

class Student : Person {
    constructor(name: String, age: Int) : super(name, age) {
    }
}

接口

KotlinJava一样,是单继承结构,任何一个类只能继承一个父类,但可以实现多个接口。

修饰符

修饰符JavaKotlin
public所有类可见所有类可见(默认)
private当前类可见当前类可见
protected当前类、子类、同一包路径下的类可见当前类、子类可见
default同一包路径下的类可见(默认)
internal同一模块中的类可见

空指针处理

  • ?.操作符:当对象不为空时正常调用相应的方法,当对象为空时则什么都不做
  • ?:操作符:如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果

标准函数

let

调用let,对象本身作为参数

fun doStudy(study: Study?) {
    study?.let {
        it.readBooks()
        it.doHomework()
    }
}

with

第一个参数可以是一个任意类型的对象,第二个参数是一个Lambda表达式。with函数会在Lambda表达式中提供第一个参数对象的上下文,并使用Lambda表达式中的最后一行代码作为返回值返回

它可以在连续调用同一个对象的多个方法时让代码变得更加精简

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = with(StringBuilder()) {
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
    toString()
}
println(result)

run

区别于with:run函数通常不会直接调用,而是要在某个对象的基础上调用,run`函数只接收一个Lambda参数,并且会在Lambda表达式中提供调用对象的上下文

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().run {
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
    toString()
}
println(result)

apply

区别于runapply函数无法指定返回值,而是会自动返回调用对象本身

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().apply {
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
}
println(result.toString())

静态方法

object关键字

定义一个类为单例类、里面所有方法都为静态方法。

object Util {
    fun doAction() {
        println("do action")
    }
}

companion object

定义普通类中的方法为静态方法。

class Util {
    fun doAction1() {
        println("do action1")
    }
    companion object {

        fun doAction2() {
            println("do action2")
        }
    }
}

doAction2()方法其实也并不是静态方法,companion object这个关键字实际上会在Util类的内部创建一个伴生类,而doAction2()方法就是定义在这个伴生类里面的实例方法。只是Kotlin会保证Util类始终只会存在一个伴生类对象,因此调用Util.doAction2()方法实际上就是调用了Util类中伴生对象的doAction2()方法

以上两个关键字都不是真正的静态方法,仅仅是模拟静态方法

注解 @JvmStatic

而如果我们给单例类或companion object中的方法加上@JvmStatic注解,那么Kotlin编译器就会将这些方法编译成真正的静态方法。

@JvmStatic注解只能加在单例类或companion object中的方法上

class Util {
    fun doAction1() {
        println("do action1")
    }
    companion object {

        @JvmStatic
        fun doAction2() {
            println("do action2")
        }
    }
}

顶层方法

顶层方法指的是那些没有定义在任何类中的方法

kt文件中直接定义的方法,在kotlin任意位置,直接使用方法名调用。

java中调用顶层方法:xxxKt.methodName

延迟初始化

lateinit:声明变量时不初始化变量,后续初始化。

::variable.isInitialized:用于判断variable变量是否已经初始化

密封类

sealed class

当在when语句中传入一个密封类变量作为条件时,Kotlin编译器会自动检查该密封类有哪些子类,并强制要求你将每一个子类所对应的条件全部处理

密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的。

扩展函数

扩展函数表示即使在不修改某个类的源码的情况下,仍然可以打开这个类,向该类添加新的函数

运算符重载

operator关键字

语法糖表达式实际调用函数
a + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.rem(b)
a++a.inc()
a--a.dec()
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()
a == ba.equals(b)
a > ba.equals(b)
a < ba.equals(b)
a >= ba.equals(b)
a <= ba.compareTo(b)
a..ba.rangeTo(b)
a[b]a.get(b)
a[b] = ca.set(b, c)
a in bb.contains(a)