一文掌握Kotlin:Kotlin基础语法
Kotlin并非另一门“昙花一现”的编程语言。其诞生于JetBrains——这家以打造顶尖开发工具闻名世界的公司,经过十余年的精心打磨,最终在Java生态的坚实基础上,开辟出了一条更现代、更安全、更富有表现力的道路。它既能够与现有的Java代码无缝互操作,又通过简洁的语法设计、空安全和函数式编程特性,显著提升了开发效率和代码质量。
Kotlin并非另一门“昙花一现”的编程语言。其诞生于JetBrains——这家以打造顶尖开发工具闻名世界的公司,经过十余年的精心打磨,最终在Java生态的坚实基础上,开辟出了一条更现代、更安全、更富有表现力的道路。Kotlin既能够与现有的Java代码无缝互操作,又通过简洁的语法设计、空安全和函数式编程特性,显著提升了开发效率和代码质量。
无论你是从Java等传统面向对象语言转型而来的开发者,还是刚刚踏入移动端或后端开发领域的新人,掌握Kotlin都已成为一项极具价值的技能。不仅能帮助你编写更少、更安全的代码,更能以一种全新的思维方式来解决实际问题。
一、基本数据类型
分一下几种进行介绍。
- 数值类型
- 字符类型
- Boolean
1.1 数值类型
Kotlin 的基本数值类型包括 Byte、Short、Int、Float、Long、Double
| 数据类型 | 位长 |
|---|---|
| Byte | 8 |
| Short | 16 |
| Int | 32 |
| Float | 32 |
| Long | 64 |
| Double | 64 |
分一下几种情况分别进行说明:
- 数值类型使用;
- 数值类型 二、八、十六进制转换;
- 数值比较;
- 数值类型转换;
- 数值类型位操作;
1.1.1 数值类型使用
基本数值类型( Byte、Short、Int、Float、Long、Double)使用。
数值写法:
// Int:数值类型变量定义
// var <标识符> : <类型> = <初始化值>
val aa: Int = 123
val aa = 123
// Float: 使用 f 或者 F 后缀
val aa = 123.5f
val bb = 123.5F
// Long: 以大写的 L 结尾
val aa = 1234_5678_9012_3456L
// Double 默认写法
val aa = 123.5
1.1.2 二、八、十六进制
基本数值类型,二、八、十六进制支持情况。
// 十进制:123
val aa = 123
// 二进制:0b 开头
val aa = 0b00001011
// 八进制:暂不支持
// 十六进制:0x 开头
val aa = 0x0F
1.1.3 数值比较
Kotlin 中没有基础数据类型,只有封装的数字类型。
我们每定义的一个变量,其实 Kotlin 帮你封装了一个对象,这样可以保证不会出现空指针,所以在比较两个数字的时候,就有比较数据大小和比较两个对象是否相同的区别了。
在 Kotlin 中:
- 三个等号
===表示比较对象地址; - 两个
==表示比较两个值大小。
// 地址空间比较(同一对象)
val a: Int = 10000
println(a === a) // true
// 地址空间比较(不同对象)
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA === anotherBoxedA) // false 对象地址不一样
// 大小比较
println(boxedA == anotherBoxedA) // true,值相等
1.1.4 类型转换
由于不同的表示方式,较小类型并不是较大类型的子类型。
因此,较小的类型不能隐式转换为较大的类型,因此若 Byte 转换为 Int 需进行显示转换。
val b: Byte = 1
// 显示转换
val i: Int = b.toInt()
每种数据类型都有下面的这些方法,可以转化为其它的类型:
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
1.1.5 位操作
// 左移位
shl(bits)
// 右移位
shr(bits)
// 无符号右移位
ushr(bits)
// 与
and(bits)
// 或
or(bits)
// 异或
xor(bits)
// 反向
inv()
1.2 字符类型
Char 必需是单引号 ’ 包含起来的。比如普通字符 ‘0’,‘a’。
// 地址空间比较(同一对象)
val a: Char = '9'
// 显示转换
val i: Int = a.toInt()
1.3 字符串
字符串变量声明:
// 单行字符串
val str = "123"
// 多行字符串
val text = """
多行字符串
多行字符串
"""
字符串使用方式:
// 取字符串中的字符
val str = "123"
println(str[2])
// 取字符串中的字符
for (c in str) {
println(c)
}
// 显示字符转换
val i: Int = str.toInt{)
// 去处空格
val text = """
多行字符串
多行字符串
""".trimMargin()
字符串模板:
// $ 表示一个变量名或者变量值
// $varName 表示变量值
// ${varName.fun()} 表示变量的方法返回值
fun main(args: Array<String>) {
var a = 1
// 模板中的简单名称:
val s1 = "a is $a"
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, now is $a"
print(s2)
}
1.3 布尔
布尔用 Boolean 类型表示,它有两个值:true 和 false。
val b: Boolean = true
二、变量
- 变量定义
- 变量NULL检查
- 变量类型检测
is - 变量区间表示
- 可变长参数
vararg
2.1 变量定义
- var 可变变量;
- val 只读变量,相当于java中的final变量,val 变量创建的时候必须初始化。
var <变量标识符> : <变量类型> = <变量初始化值>
// 可变变量初始化:
var a: Int = 1
// 只读变量初始化:
val b: Int = 2
2.2 变量NULL检查
- 类型后面加? 表示可为空
var aa: String? = "23" - 标识符后加!! 表示若为null 正常抛出异常;
val aa = age!!.toInt() - 标识符后加? 表示若为空 则返回空
val aa = age?.toInt() - ?:使用:age为空返回-1
val ages2 = age?.toInt() ?: -1
2.3 变量类型检测
// 类型检测
if (obj is String) {
// 做过类型判断以后,obj会被系统自动转换为String类型
return obj.length
}
2.4 变量区间
- 使用 … 代表
rangeTo(从小到大)for (i in 1..4) print(i) // 输出“1234” - 使用
downTo(从大到小)for (i in 4 downTo 1 step 2) print(i) // 输出“42” - 使用
step指定步长for (i in 1..4 step 2) print(i) // 输出“13” - 使用
until排除结束元素
// i in [1, 10) 排除了 10
for (i in 1 until 10) {
println(i)
}
2.5 可变长参数
可边长参数 vararg
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
// 测试
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 输出12345
}
三、方法
- 方法定义
- lambda匿名方法
3.1 方法定义
方法定义使用关键字:fun,
参数格式为:参数 : 类型
// 有返回值方法定义
fun sum(a: Int, b: Int): Int {
// Int 参数,返回值 Int
return a + b
}
// 无返回值方法定义
fun printSum(a: Int, b: Int) {
print(a + b)
}
3.2 lambda匿名方法
// 测试
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 输出 3
}
lambda简化的几种情况
a、无参数的情况 :
val/var 变量名 = { 操作的代码 }
// 举例:未简化写法
fun test(){ println("无参数") }
// 举例:lambda写法
val test = { println("无参数") }
b、有参数的情况
val/var 变量名 : (参数类型,参数类型) -> 返回值类型 = {参数1,参数2 -> 操作参数的代码 }
// 举例:未简化写法
fun test(a : Int , b : Int) : Int{
return a + b
}
// 举例:lambda写法
val test : (Int , Int) -> Int = {a , b -> a + b}
c、lambda表达式作为函数中的参数的情况
fun test(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, … ) -> 表达式返回类型){
…
}
// 举例:未简化写法
fun test(a : Int , b : Int) : Int{
return a + b
}
fun sum(num1 : Int , num2 : Int) : Int{
return num1 + num2
}
//
// 举例:lambda写法
fun test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
return a + b.invoke(3,5)
}
// 调用简化后的 test 方法
test(10,{ num1: Int, num2: Int -> num1 + num2 })
四、条件控制
- if表达式
- when表达式
4.1 if表达式
一个 if 语句包含一个布尔表达式和一条或多条语句。
// 使用if else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// 使用 if 表达式
var max = a
if (a < b) max = b
// 作为表达式使用:表达式结果赋值给变量
val max = if (a > b) a else b
// 作为表达式使用:表达式结果赋值给变量
val max = if (a > b) {
a
} else {
b
}
4.2 when表达式
when 将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。when 类似其他语言的 switch 操作符。when 表达式 else 同 switch 的 default,如果其他分支都不满足条件将会求值 else 分支。
//
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意这个块
print("x 不是 1 ,也不是 2")
}
}
//
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
when 表达式,用in检测一个值在或者不在区间或者集合中:
//
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
when 表达式,用用is检测一个值是或者不是一个特定类型的值:
//
when(x) {
is String -> x.startsWith("prefix")
else -> false
}
五、循环控制
- for 循环
- while 与 do while
- return、break与continue
5.1 for 循环
for 循环可以对任何提供迭代器(iterator)的对象进行遍历。
//
for (item in collection) print(item)
// 循环体也可以是一个语句
val items = listOf("apple", "banana", "kiwi")
for (item in items) println(item)
// 循环体也可以是一个代码块
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
// 通过索引遍历一个数组或者一个 list
for (i in array.indices) {
print(array[i])
}
// 使用 withIndex 库方法
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
5.2 while 与 do while
while 和 do while 功能相似;不同的是 do while 至少会执行一次。
fun main(args: Array<String>) {
// while 循环
var x = 5
while (x > 0) {
println( x--)
}
// do…while 循环
var y = -1
do {
println(y--)
} while(y>0)
}
// 执行结果
// while 循环
5
4
3
2
1
// do…while 循环
-1
5.3 return、break与continue
- return 从最直接包围它的方法或者匿名方法返回;
- break 终止最直接包围它的循环;
- continue 继续下一次最直接包围它的循环;
使用方式举例如下:
fun main(args: Array<String>) {
for (i in 1..10) {
if (i==3) continue // i 为 3 时跳过当前循环,继续下一次循环
println(i)
if (i>5) break // i 为 6 时 跳出循环
}
}
Kotlin中的标签
在 Kotlin 中任何表达式都可以用标签来标记。标签的格式为 标识符后跟 @ 符号,例如:abc@、fooBar@都是有效的标签。
// 用标签限制 break
loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop
}
}
六、类
- 类定义
- 抽象类
- 嵌套类
- 内部类
- 匿名内部类
6.1 类定义
- 类关键词
类使用关键字class声明,后面紧跟类名:class Person{} - 主构造方法
类可以有一个主构造器、多个次构造器。
主构造器是类头部的一部分,位于类名称之后。主构造器中不能包含任何代码,初始化代码可以放在初始化代码段init中。 - 次构造方法
如果类有主构造方法,每个次构造方法都要 直接或间接通过另一个次构造方法 代理主构造方法;在同一个类中代理另一个构造方法使用 this 关键字; - 类属性声明
类中非空属性必须在定义的时候初始化,但也可通过lateinit关键词延迟初始化。
另外,Kotlin提供了后端变量field机制,但field关键词只能应用于属性的访问器。
Kotlin 类构造代码举例如下:
// 类关键词:类使用关键字 class 声明,后面紧跟类名;
// 构造方法:带构造方法的类 (constructor关键词 可省略);
class Person constructor (name: String){
// 类属性:非空属性必须在定义的时候初始化;
// 类属性:Kotlin提供了 后端变量field 机制,但 field关键词 只能应用于属性的访问器;
var mName: String = "xia"
get() = field.toUpperCase() // 将变量赋值后转换为大写
var mAge: Int = 16
set(value) {
if (value < 20) { // 如果传入的值小于 20 返回该值
field = value
} else {
field = 18 // 否则返回18
}
}
// 构造方法:主构造器中不能包含任何代码,初始化代码可放在 init 代码段中;
init {
this.mName = name
println("init name $mName")
println("init age $mAge")
}
// 次构造方法:如果类有主构造方法,每个次构造方法都要 直接或间接通过另一个次构造方法 代理主构造方法;
// 次构造方法:在同一个类中代理另一个构造方法使用 this 关键字;
constructor (name: String, age:Int) : this(name) {
// 次构造方法...
this.mName = name
this.mAge = age
println("constructor init name $mName")
println("constructor init age $mAge")
}
}
// main 程序入口
fun main(args: Array<String>) {
// 创建对象
var person: Person = Person("xiaxl")
// 姓名
person.mName = "xiaxueliang"
println("changeName:${person.mName}")
// 年龄
person.mAge = 21
println("changeAge:${person.mAge}")
}
6.2 抽象类
抽象类 类本身、类中的部分成员,都可以声明为abstract类型。
// 抽象类 类本身、类中的部分成员,都可以声明为abstract类型
abstract class Person {
abstract fun changeName()
}
6.3 嵌套类
可以把类嵌套在其他类中。
// 嵌套类:可以把类嵌套在其他类中
// 外部类
class Outer {
private val outerProperty: Int = 1
// 嵌套类
class Person {
fun changeAge() = 18
}
}
fun main(args: Array<String>) {
// 嵌套类调用:外部类.嵌套类.嵌套类方法/属性
val age = Outer.Person().changeAge()
println(age) // 输出 18
}
6.4 内部类
内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以可以访问外部类成员属性和成员方法。可以使用 this@label 标签,访问来自外部作用域的 this。
// 内部类:内部类使用 inner 关键字来表示。
// 内部类:内部类会带有一个对外部类的对象的引用,所以可以访问外部类成员属性和成员方法。
class Outer {
private val iProperty: Int = 18
var sProperty = "outerName"
// 内部类
inner class Person {
// 访问外部类成员
fun test01() = iProperty
// 获取外部类对象,访问外部类成员
fun test02() {
// 内部类:使用 `this@label` 标签,访问来自外部作用域的 `this`
var outerObj = this@Outer
// 访问外部类成员
println("inner sProperty:" + outerObj.sProperty)
}
}
}
fun main(args: Array<String>) {
val iProperty = Outer().Person().test01()
println("main Person test01: " + iProperty)
//
val sProperty = Outer().Person().test02()
println("main Person test02: " + sProperty)
}
6.5 匿名内部类
// 定义接口
interface PersionInterFace {
fun changeName()
}
// 定义类
class Persion {
var v = "成员属性"
// 定义方法
fun setInterFace(testObj: PersionInterFace) {
testObj.changeName()
}
}
// 程序入口
fun main(args: Array<String>) {
// 获取类的对象
var persion = Persion()
// 采用对象表达式来创建接口对象,即匿名内部类的实例。
persion.setInterFace(object : PersionInterFace {
override fun changeName() {
println("实现匿名内部类的 changeName 方法")
}
})
}
七、继承
Kotlin 中所有类都继承该 Any 类,它是所有类的超类。
另外,Any 类默认提供了三个方法,分别为:equals()、hashCode()、toString()。
- 构造方法
- 重写方法
- 重写属性
7.1 构造方法
- 如果子类有主构造方法:
则必须在子类主构造方法中初始化基类。
// 如果子类有主构造方法:则必须在子类主构造方法中初始化基类。
// 基类
// 如果一个类要被继承,可以使用 open 关键字进行修饰
// Any 类为所有类的超类
open class Person(var name:String, var age:Int){
}
// 子类 Student
class Student(name:String, age:Int, ,number:String) : Person(name, age) {
}
// 测试
fun main(args: Array<String>) {
var s = Student("xia", 18, "n987456123")
println("姓名: ${name}")
println("年龄: ${age}")
println("学号: ${number}")
}
- 如果子类没有主构造方法:
则必须在子类每一个次级构造方法中用super关键字初始化基类。
// 如果子类没有有主构造方法:则必须在子类每一个次级构造方法中用 super 关键字初始化基类。
// 基类
open class Person(name:String){
// 基类 次构造方法
constructor(name:String,age:Int):this(name){
println("--- 基类 次构造方法 ---")
println("姓名: ${name}")
println("年龄: ${age}")
}
}
// 子类 Student
class Student:Person{
// 子类 次构造方法
constructor(name:String,age:Int,number:String):super(name,age){
println("--- 子类 次级构造方法 ---")
println("姓名: ${name}")
println("年龄: ${age}")
println("学号: ${number}")
}
}
fun main(args: Array<String>) {
var s = Student("xia", 18, "number987456123")
}
7.2 重写方法
在基类中,声明函数方法时,此方法默认为 final ,不能被子类重写。
如果允许子类重写该方法,需要手动添加 open 修饰, 子类重写方法需使用 override 关键词。
// 基类
// 方法重写:在基类中,使用fun声明函数方法时,此函数方法默认为 final ,不能被子类重写。
// 方法重写:如果允许子类重写该方法,需要手动添加 open 修饰, 子类重写方法需使用 override 关键词。
open class Person{
// 允许子类重写
open fun study(){
println("学习使我快乐")
}
}
// 子类
class Student : Person() {
// 重写
override fun study(){
println("我是一名学生")
}
}
// 程序入口
fun main(args: Array<String>) {
val s = Student()
s.study();
}
7.3 重写属性
使用 override 关键字,也可以在主构造函数中使用 override 关键字作为属性声明的一部分。
interface Persion {
val age: Int
}
// 重写属性:使用 override 关键字
class Student1 : Persion {
override var age: Int = 9
}
// 重写属性:在主构造函数中使用 override 关键字作为属性声明的一部分
class Student2(override val age: Int) : Persion{
}
// 程序入口
fun main(args: Array<String>) {
var s1 = Student1()
println("Student1: "+s1.age);
var s2 = Student2(18)
println("Student2: "+s2.age);
}
八、接口
Kotlin 使用 interface 关键字定义接口。
- 接口中的方法允许有默认实现;
- 接口中的属性只能是抽象的,不允许初始化;
- 一个类可以实现一个或多个接口,实现多个接口时,可能会遇到同一方法继承多个实现的问题。
// 接口类A
interface AInterface {
// 接口:属性只能是抽象的,不允许初始化
var name:String
// 接口:方法允许有默认实现
// 未实现的方法
fun changeName()
// 已实现的方法
fun changeAge() {
println("AInterface changeAge")
}
}
// 接口类B
interface BInterface {
// 接口:方法允许有默认实现
// 未实现的方法
fun changeName() {
println("BInterface changeName")
}
// 已实现的方法
fun changeAge() {
println("BInterface changeAge")
}
}
class C : AInterface {
// 重写属性
override var name: String = "xiaxl"
// 重写方法
override fun changeName() {
println("Class C changeName")
}
}
class D : AInterface, BInterface {
// 重写属性
override var name: String = "xiaxl"
// 重写方法
override fun changeName() {
// super<AInterface>.changeName()
super<BInterface>.changeName()
println("Class D changeName")
}
// 重写方法
override fun changeAge() {
super<BInterface>.changeAge()
println("Class D changeAge")
}
}
fun main(args: Array<String>) {
val d = D()
println(" ")
d.changeName();
println(" ")
d.changeAge();
}
九、枚举
Kotlin中的enum class是一种强大的类型安全枚举实现,它不仅仅是简单的常量集合,更是功能完整的类。与Java枚举相比,Kotlin枚举更加简洁且功能丰富,能够有效管理一组相关的常量,并提供类型安全性保证。
enum class Color(val rgbValue: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
fun main(args: Array<String>) {
//
var color:Color=Color.GREEN
// 打印枚举名称
println(color.name)
// 打印枚举顺序
println(color.ordinal)
// 打印枚举 Value
println(color.rgbValue)
}
十、数据类型
先说为什么要使用数据类:
Kotlin使用数据类替换普通类的好处是Kotlin会帮我们产生大量代码,省去大量的重复性工作。
- Kotlin中使用数据类只需要在
class关键字前添加data关键字,编译器会自动从主构造函数中根据声明的属性推导出相关函数equals()、toString()、copy()、componentN()、hashCode(); - Kotlin中数据类 自动声明与构造函数入参同名的属性字段,自动实现每个属性字段的存取器方法
set/get;
声明数据类:
// 声明数据类型
data class <类名> <主构造函数参数> <:继承类和实现接口> { /*类体*/ }
数据类型举例:
// 创建数据类
data class Person(var name :String, var age :Int){
// 类体内生命属性
var job: String = "student"
}
// 程序入口
fun main(args: Array<String>) {
var p = Person("xiaxl",18)
// 调用数据类的 getter
println(p.name)
println(p.age)
println(p.job)
// 调用数据类的 setter
p.name = "xiaxueliang"
// 自动调用toString()方法
println(p)
//调用hashCode()方法,输出内存地址
println(p.hashCode())
// 解析构造函数 componentN
val (name, age) = p
println("name = $name, age=$age")
}
十一、泛型
Kotlin的泛型系统在Java的基础上进行了改进,提供了更安全的类型参数约束。
// 泛型举例
class Persion<T>(t : T) {
var value = t
}
// 泛型举例
fun <T> doPrintln(t: T) {
when (t) {
is Int -> println("整型数字: $t")
is String -> println("字符串大写: ${t.toUpperCase()}")
else -> println(" 不是整型,也不是字符串")
}
}
// 程序入口
fun main(args: Array<String>) {
var pInt = Persion<Int>(18)
var pString = Persion<String>("xiaxl")
// 输出
doPrintln(pInt.value)
doPrintln(pString.value)
}
十二、伴生对象
- 伴生对象
- 对象声明
12.1 伴生对象
伴生对象,就是随着类的存在而存在。
在Kotlin中,类是没有static方法的,在大多数情况下 Kotlin 推荐的做法是使用包级别的函数作为静态方法,Kotlin 会将包级别的函数当做静态方法来看待。
// 伴生对象
class MyConstant {
companion object {
var num: Int = 100
fun doPrint() {
println("method test")
}
}
}
// 程序入口
fun main(args: Array<String>) {
// 变量
var num = MyConstant.num
println("num: $num")
// 方法
MyConstant.doPrint()
}
12.2 对象声明
Kotlin 可以通过对象声明来获得一个单例,Kotlin 使用 object 关键字来声明一个对象。
// 对象声明
object Singleton{
// 属性
val name = "xia"
// 方法
fun doPrint(age: Int){
println("$name ---- $age")
}
}
// 程序入口
fun main(args: Array<String>) {
// 单例
Singleton.doPrint(18)
}
十三、回调函数
Lambda 表达式(lambda expression)是一个匿名函数。
编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。
- 回调函数的Java写法
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
// TODO
}
});
- 回调函数的kotlin写法
mEditText?.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable) {
// TODO
}
})
- 在Kotlin中,对于
接口只有一个回调的方法,符合使用lambda简化
mEditText.addTextChangedListener({
editable: Editable ->
// TODO
})
// 如果以上代码中没有回调参数的话,可以直接把editable去掉
mEditText.addTextChangedListener({
// TODO
})
// addTextChangedListener 函数最后一个参数是一个函数,可以直接把括号的实现提到圆括号外面
mEditText.addTextChangedListener(){
// TODO
}
// addTextChangedListener函数只有一个参数,可以直接省略圆括号
mEditText.addTextChangedListener{
// TODO
}
十四、let also run with apply
apply用于对象初始化;let、also用于替代判空;run 、with用于绑定数据;
13.1 apply 对象初始化
apply函数 一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值;
或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到;
// 一个对象实例初始化的时候,需要对对象中的属性进行赋值
mEditText = findViewById<EditText>(R.id.search_et).apply {
// 点击事件
setOnClickListener{
// TODO
}
}
13.2 let和also替代判空
let 替代判空
表示object不为null的条件下,才会去执行let函数体,返回最后一行代码的值。
// 表示object不为null的条件下,才会去执行let函数体,返回最后一行代码的值
mEditText = findViewById<EditText>(R.id.search_et);
mEditText?.let {
// it.todo()
it.setSelection(0)
}
also 替代判空
表示object不为null的条件下,才会去执行also函数体,返回的是传入对象本身。
// 表示object不为null的条件下,才会去执行also函数体,返回的是传入对象本身
mEditText = findViewById<EditText>(R.id.search_et).also {
// it.todo()
it.setSelection(0)
}
13.3 run和with绑定数据
- with 适用于调用同一个类的多个方法时,
可以省去类名重复直接调用类的方法; - run 适用于调用同一个类的多个方法时,
可以省去类名重复直接调用类的方法,同时可以像let函数一样做判空处理;
// java 写法
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ItemBean item = getItem(position);
if (item == null) {
return;
}
holder.mTitleTv.setText(item.title);
holder.mSubTitleTv.setText(item.subTitle);
holder.mDescTv.setText(item.desc);
}
// with适用于调用同一个类的多个方法时,可以省去类名重复直接调用类的方法
override fun onBindViewHolder(holder: ViewHolder, position: Int){
val item = getItem(position)?: return
//
with(item){
holder.mTitleTv.text = title
holder.mSubTitleTv.text = subTitle
holder.mDescTv.text = desc
}
}
// run适用于调用同一个类的多个方法时,可以省去类名重复直接调用类的方法,同时可以像let函数一样做判空处理
override fun onBindViewHolder(holder: ViewHolder, position: Int){
val item = getItem(position)?: return
item?.run{
holder.mTitleTv.text = title
holder.mSubTitleTv.text = subTitle
holder.mDescTv.text = desc
}
}
更多推荐



所有评论(0)