Kotlin——基础语法

https://rainmonth.github.io/posts/A180116.html

Kotlin——基础语法

定义函数

带有两个Int参数、返回Int的函数:

1
2
3
fun sum(a: Int, b: Int): Int {
return a + b
}

表达式作为函数体、返回值类型自动推断的函数:

1
fun sum(a: Int, b: Int) = a + b

返回无意义的值:

1
2
3
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a+b}")
}

省略Unit返回类型:

1
2
3
fun printSum(a: Int, b: Int) {
println("sum of $a and $b is ${a+b}")
}

定义变量

只读变量

只读变量用val修饰:

1
2
3
4
val a: Int = 1        //立即赋值
val b = 2 //自动推断b的类型为Int
val c: Int //没有赋值的情况下,不能省略类型Int
c = 2 //立即赋值

可变变量

可变变量用var修饰:

1
2
var x = 5            //自动推断出Int类型
x += 1

Android Studio Java 和 Kotlin混合编译配置

Java和Kotlin的混编,按场景分一下两种:

  1. Java 调用 Kotlin(如Java编写的Activity里面按钮点击,开启一个Kotlin编写的Activity
  2. Kotlin 调用 Java(如Kotlin编写的Activity里面按钮点击,开启一个java编写的Activity

具体配置

下面讲一下怎么配置才能满足混合编译的配置

  1. 根项目下的build.gradle文件配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    buildscript {
    ext.kotlin_version = '1.6.10'

    repositories {
    ...
    }
    dependencies {
    // gradle 插件版本
    classpath 'com.android.tools.build:gradle:3.6.1'
    // kotlin gradle 插件版本,这个版本要与Android Studio的插件版本序号一致
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    // 扩展插件可以节省findviewbyid(),实现与Data-Binding,Dagger框架的效果,不需要添加任何额外代码,也不影响任何运行时体验。
    classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files

    }
    }
    allprojects {
    repositories {
    ...
    }
    }
  2. module项目下的build.gradle文件配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
       apply plugin: 'com.android.application'

    // 下面两种写法都可以
    //apply plugin: 'org.jetbrains.kotlin.android'
    apply plugin: 'kotlin-android'
    android({
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    buildToolsVersion rootProject.ext.android.buildToolsVersion

    compileOptions {
    sourceCompatibility javaVersion
    targetCompatibility javaVersion
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }

    dependencies {
    dependencies {
    // 这个可以不用,作用Android KTX 是包含在 Android Jetpack 及其他 Android 库中的一组 Kotlin 扩展程序。KTX 扩展程序可以为 Jetpack、Android 平台及其他 API 提供简洁的惯用 Kotlin 代码。
    implementation "androidx.core:core-ktx:1.6.0"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    }
    }

关于android KTX,请参考Android KTX

这样就可以配置就完成了

问题

Java调用Kotlin没什么问题,主要是在Kotlin的Activity中调用Java方法(或开启Java的Activity)时,如果Java 类文件不在main/java下,就会出现找不到引用的问题,这个目前没有搜到相应的解决办法,后面知道了会跟新记录

NULL检查机制

注意点1

都知道Kotlin有空安全机制,这样可以避免Java中crash最常见的罪魁祸首NPE出现,但还是要知道Kotlin空安全的具体使用的。具体来说,Kotlin对于声明为可为空的参数,在使用时要进行判空处理具体有以下两种方式:

  1. 可为空字段后面加上!!,表示当字段为空时,会像Java一样抛出空指针异常;
  2. 可为空字段后面加上?,表示不做处理返回值为null或者配合?:做判空处理;

具体看下面的例子:

1
2
3
4
5
6
7
8
//类型后面加?表示可为空
var age: String? = "23"
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1

注意点2

当引用一个可能为null的值时,对应的类型声明必须明确的标记为可为null

具体例子:

1
2
3
4
// 当 str 中的字符串内容不是一个整数时, 返回 null,函数返回值类型必须为 Int?
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}

类型检测及自动类型转换

Kotlin中类型检测采用 is关键字来表示,类似于 Java中的 instanceOf关键字,但Kotlin中会有一个更便捷的地方,就是采用 is检测后,就自动转换成对应的类型了,不用像Java中那样在现实的强转一下,具体看一下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
fun getStringLength(obj : Any) : Int? {
if (obj is String) {
// 在这里 obj 就自动变成了 String类型了,如果是Java中,则需要强转一下
return obj.length
}
// if (obj !is String) {
// return null
// }
// return obj.length
}
// 在这里obj仍然是 Any类型
return null
}

扩展

Kotlin可以对一个类的属性和方法进行扩展,且不许要使用继承或者Decorator模式;

扩展函数可以在已有类

object关键字

kotlin增加了一个 object关键字,该关键字用于以下场景中:

  1. 对象表达式,相当于Java中的匿名内部类;
  2. 对象声明,kotlin中提供的一个简洁的单例声明方式;
  3. 伴生对象,kotlin中替代Java 中static功能的方式;

对象表达式

对象表达式,类似于Java中的匿名内部类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface OnClickListener {
fun onClick(v: View?)
}

private fun setOnClickListener(listener: OnClickListener?) {

}

fun test() {
setOnClickListener(listener = object : OnClickListener {
override fun onClick(v: View?) {
}
})
}

注意:listener = 可以省略

关于对象表达式,还有以下要知道的:

  1. 对象表达式 object 冒号后面可以有多个超类,
  2. 对象表达式 的超类如果包含带参数的构造函数,则在声明的时候需要传递相应的参数;
  3. 匿名对象智能在 本地私有声明 中作为类型使用,如果对象表达式采用了 public 关键字修饰,则匿名对象的实际类型是 匿名对象的超类型(没有超类型则 类型为Any),public 修饰的匿名对象 里成员将不可访问。
  4. 对象表达式可以访问外部类的成员,并且外部类没必要声明为final,这一点同Java不一样。

对象声明

对象声明是Kotlin (在Scala之后)实现单例的一种快捷方式,即kotlin中可以像声明变量那样采用关键字来声明单例,而不用像Java那样需要自己 去实现单例。这个关键字就是 object,该关键字后面直接接类名时,那么这个类就只有一个对象,例如:

1
2
3
4
5
6
7
8
9
10
11
object DialogManager : BaseDialogManager() {
fun showDialog() {

}

fun dismissDialog() {

}
}

open class BaseDialogManager

由上面的示例可见,对象声明 时 类可以有超类。对象声明虽然方便,但也有几个局限的地方:

  1. 对象声明 时 没有 右值的,所以不能作为表达式那样复制个其他变量,这一点Java的单例是可以的;
  2. 对象声明 不能 是本地的,即不能放在函数作用域中,可以在类作用域(类里面声明)使用;
  3. 对象声明 可以继承超类,即单例可以有超类。

伴生对象

伴生对象(companion object)的出现是为了解决 Java 静态方法(static)的反面向对象(Anti-OOP)的问题。即Java 中 static 方法是无法声明为接口、无法被重写的,也就是说 static方法没有面向对象的 消息传递延迟绑定 特性。而Kotlin中一切皆对象,多以采用伴生对象来替代static方法。

companion object 是一个对象,在类初始化时被实例化。注意 伴生对象不是类的 static 方法,而是类的实例化对象,其内部可以声明接口,方法也可以被重写,具备面向对象的特点。

伴生对象声明方式

1
2
3
companion object ObjectName : [0~N个父类型] {
// 伴生对象类体
}

伴生对象的特点:

  1. 伴生对象相当于类的对象,可以直接通过类名访问伴生对象的成员;
  2. 每个类最多定义一个伴生对象;
  3. kotlin中没有 static关键字,伴生对象是为了弥补kotlin中没有 static 修饰的静态成员的不足;
  4. @JvmStatic 注解只能用在伴生对象内,修饰伴生对象内的属性和函数;

协程

操作符

  1. 安全调用操作符 ?.

    • 功能:安全调用操作符 ?. 用于在调用方法或访问属性时,确保如果左侧表达式为 null,则整个表达式的值为 null,而不会抛出异常。

    • 使用场景:当你不确定某个对象是否为 null,并且希望在对象为 null 时不执行后续操作时,可以使用 ?.。

  2. 非空断言操作符 !!.

    • 功能:非空断言操作符 !!. 用于强制将一个可空类型的值转换为非空类型。如果该值为 null,则会抛出 NullPointerException。

    • 使用场景:当你确定某个对象不会为 null,并且希望在对象为 null 时立即抛出异常而不是继续执行代码时,可以使用 !!.。