kotlin 实战之核心基础特性总结(1)

对于 kotlin 来说,如果你不用 IDE(其本质也是走的命令行行为),则其编译与反编译原理基本与 java 如出一辙,kotlin 的 kotlinc 命令对应 java 的 javac,用法也相同;kotlin 的 kotlin 命令对应 java 的 java 命令,都是执行程序;由于 kotlin 编译后也是 class 字节码,所以其反编译依然使用 java 的 javap 等工具,这点和 groovy 类似。

需要特别注意的是 kotlin 中非 class 声明的 kotlin 文件(譬如一个FileName.kt文件中顶级定义了变量或者方法)默认会生成一个以 Kt 追加文件名的 class 文件(譬如生成FileNameKt.class 文件,而 kotlin 中编写的类编译后与 java 类似,不存在这个特性。这个特性可以通过指定的注解打破,具体看后面总结。

var 与 val 及变量类型


与 java 不同的是,kotlin 的变量类型可以是类似下面这样的:

fun main() {

//val 定义的变量值不能被修改,类似 java 的 final

val a: Int = 1

//kotlin 自动类型推断 b 为 Int 类型,kotlin 中的 Int 在 jvm 中表示为 java 的 int 类型,可以看注释得知

val b = 2

//var 定义变量,后面可以对变量值做修改

var c: Int

c = 34

var d: Long = 10

var e = 20

//d = e 编译错误,无法自动类型转换,小类型赋值给大类型是不被允许的,java 可以

d = e.toLong() //合法

}

//Any 为 koltin 中的基类,类似 java 的 Object 类,但是又不一样

fun convert(arg: Any): String? {

//is 类似 java 的 instanceof

return if (arg is String) {

arg.toUpperCase()

} else {

null

}

}

!!.?.?:asas?的区别


在 kotlin 中!!.?.都是用来判断空参数异常的。?.的含义是这个参数可以为空且程序继续运行下去;!!.的含义是这个参数如果为空则抛出异常。

?.在 kotlin 中的使用案例如下:

val testClass: TestClass? = null

testClass?.func() //如果有返回值则当testClass为空返回 null,反之返回正常返回值

println “done” //当testClass为空则继续执行这里

上面代码对应的 java 实现逻辑如下:

TestClass testClass = null;

if (testClass != null) {

testClass.func();

}

System.out.println(“done”)

!!.在 kotlin 中的使用案例如下:

val testClass: TestClass? = null

testClass!!.func()

println “done” //当testClass为空则抛出异常,这里没机会执行

上面代码对应的 java 实现逻辑如下:

TestClass testClass = null;

if (testClass != null) {

testClass.func();

} else {

throw new NullPointerException();

}

System.out.println(“done”)

Elvis 表达式?:很像 java 的三目运算符,但又不一样,其使用案例如下:

//当 name 不为 null 则返回 null 给 str,当 name 为 null 则返回 default 给 str

val str = name ?: “default”

as 被用做类型转换或者重取别名,当用作取别名时案例如下:

//包及导入特性小节演示过了

//指定导入别名

import cn.yan.test2.funcTest as selfFuncTest

当用作类型转换时,as用于执行引用类型的显式类型转换,如果要转换的类型与指定的类型兼容则成功执行,如果类型不兼容则会抛出转换异常;当使用as?运算符进行类型转换,如果要转换的类型与指定的类型兼容则成功执行,如果类型不兼容则返回 null。在 kotlin 中,父类型是禁止转换为子类型的,请务必注意。

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

open class Fruit

open class Apple(name: String) : Fruit()

val fruit = Fruit()

//抛出 java.lang.ClassCastException 异常

println(fruit as Apple)

//打印为 null,安全的类型转换

println(fruit as? Apple)

kotlin 类型UnitNothingNothing?AnyAny?区分


kotlin 中 Unit 类型与 java 中 void 的功能基本相似。如下是 kotlin 源码中 Unit 的源码:

//Unit 类型是一个 object 对象类型

public object Unit {

//toString 函数返回值

override fun toString() = “kotlin.Unit”

}

在 kotlin 中,当一个函数没有返回值时,我们用 Unit 来表示,而不是 null;大多数时候我们不需要显示地返回 Unit,或者声明一个函数的返回值是 Unit,编译器会自动推断它。跟 kotlin 的其他类型一样,Unit 的基类型是 Any。如果是一个可空的Unit?则父类型是Any?Any?是 Any 的超集,Any?是 kotlin 类型层次的最顶端。

fun main() {

val unit = testUnit()

println(unit is Unit) //true

println(unit is Any) //true

println(unit is Unit?) //true

println(unit is Any?) //true

val unitNullable = testUnitNullable()

println(unitNullable is Unit) //false

println(unitNullable is Any) //false

println(unitNullable is Unit?) //true

println(unitNullable is Any?) //true

}

fun testUnit(): Unit {}

fun testUnitNullable(): Unit? { return null }

我们知道,在 java 中 void 不能是变量的类型,也不能作为值打印输出,java 提供了一个包装类 Void(void 的自动装箱类型),如果我们想让一个方法的返回类型永远是 null,则可以把返回类型定义为这个大写的 Void 类型。

java 中的这个 Void 类型对应 kotlin 的类型就是Nothing?,在 kotlin 中可以理解为不可达,即不返回或者返回不可访问类型,是一种约定,Nothing 的类源码如下:

//外界无法创建 Nothing 实例

public class Nothing private constructor()

在 kotlin 中 throw 表达式的返回值就是 Nothing 类型的,表示了一种不可达(因为 throw 表达式执行完毕后就异常了,自然也就是不可达后续流程了),所以如果一个函数返回值是 Nothing,那么这个函数永远不会有返回值。譬如如下场景:

//因为 pick 永远不会反回值,而是直接抛出了异常,这个时候可以用 Nothing 作为 pick 函数的返回值

fun pick(index: Int): Nothing {

throw Exception()

}

所以 Unit 与 Nothing 的区别是,Unit 类型表达式计算结果返回值是 Unit,Nothing 类型表达式计算结果永远是不会反回的。

此外Nothing?可以只包含一个值 null,Nothing?唯一允许的值是 null,可被用作任何可空类型的空引用。譬如如下场景:

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

val test = null //编译器只能推断出类型为 Nothing?,空或者不可达类型

println(test is Nothing?) //true

val test1 = listOf(null) //编译器推断的类型为 List<Nothing?>

kotlin 语法糖简化


与 java 不同的是,kotlin 的变量类型可以是类似下面这样的(其实 groovy 也有类似部分特性):

//有返回值原始写法

fun count(arg1: Int, arg2: Int): Int {

return arg1 + arg2

}

//一行表达式简写

fun count2(arg1: Int, arg2: Int): Int = arg1 + arg2

//自动类型推断简写

fun count3(arg1: Int, arg2: Int) = arg1 + arg2

//无返回值原始写法

fun printCom(arg1: Int, arg2: Int): Unit {

println(“$arg1 — $arg2”)

}

//一行表达式简写

fun printCom1(arg1: Int, arg2: Int) = println(“$arg1 — $arg2”)

//自动类型推断简写

fun printCom2(arg1: Int, arg2: Int) {

println(“$arg1 — $arg2”)

}

流程控制


java 中的 if 语句仅仅只能当作语句使用,而 kotlin 中 if 即可以当语句使用,还可以当作表达式使用,譬如:

fun main() {

var x = 10

var y = 20

var max: Int

var min: Int

//标准写法

if (x > y) {

min = y

max = x

} else {

min = x

max = y

}

//简写1,if 可以当作表达式

min = if (x > y) y else x

//简写2,if 可以当作表达式,如果 if 后面是代码块则代码块中最后一行返回值返回

max = if (x > y) {

println(“x > y”)

x

} else {

println(“x <= y”)

y

}

}

包及导入特性


我们知道,java 包名必须与磁盘目录一致,kotlin 包名没有这个限制,但是建议尽量一致,方便维护阅读。使用其他包中非 class 中定义的方法时可以直接 import 导入包,譬如:

//Test1.kt 文件使用 Test2.kt 文件

package cn.yan.test

import cn.yan.test2.funcTest

funcTest(1, 2) //调用 test2 包中的 funcTest 方法

还可以指定别名使用:

package cn.yan.test

//指定导入别名

import cn.yan.test2.funcTest as selfFuncTest

selfFuncTest(1, 2) //调用 test2 包中的 funcTest 方法

数组及遍历


kotlin 中 for 循环遍历语法与 java 有比较大的差异,具体如下:

fun main() {

//IntArray 在 jvm 中表示的是 int[] 类型,可以看其注释得知

var array: IntArray = intArrayOf(1, 2, 3)

//遍历数组元素

for (item in array) {

println(item)

}

//遍历数组下标索引

for (index in array.indices) {

println(“array[ i n d e x ] = index]= index]={array[index]}”)

}

//遍历索引及元素

for ((index1, value1) in array.withIndex()) {

println(“-array[ i n d e x 1 ] = index1]= index1]=value1”)

}

}

when 关键字


此关键字相对 java 来说是 kotlin 新增的,可以当作 switch 来使用,其 case 没有 java 常量类型限制,可以是任意表达式,如下:

fun testWhen() {

println(convertStr(“he”)) //other

println(convertStr(“h”)) //hello

var tmp = 12

var ret = when(tmp) {

in 0…20 -> “match 0…20”

30, 31, 32 -> “31, 32, 30”

33 -> “match 33”

else -> “other”

}

println(ret)

}

//简写

fun convertStr(str: String): String {

return when(str) {

“h” -> “hello”

“w” -> “word”

else -> “other”

}

}

//继续简写

fun convertStr1(str: String) = when(str) {

“h” -> “hello”

“w” -> “word”

else -> “other”

}

range 区间


range 也是 kotlin 相对于 java 新增加的东西,比较好用,具体如下:

fun testRange() {

val a = 5

val b = 10

//… 左右都是闭合区间,… 本质是 rangeTo 方法

if (a in 2…b) {

println(“range matched”)

}

if (a !in 2…b) {

println(“range not matched”)

}

for (i in 2…10) {

println(“----$i”)

}

for (i in 2.rangeTo(10)) {

println(“—x—$i”)

}

//step 是中缀表达式,遍历2到10,每次跳2个index

for (i in 2…10 step 2) {

println(“step----$i”)

}

//逆序遍历

for (i in 10 downTo 2 step 2) {

println(“downTo-step—$i”)

}

}

range 也有他的坑,具体如下案例:

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

fun testRun() {

//打印输出,range 0…2表示左右闭合区间

if (1 in 0…2) {

println(“1 in the [0, 2]”)

}

//遍历输出 1、2

for (i in 1…2) {

println(“for loop $i”)

}

//不输出任何东西,因为 range 默认按照升序查找,左区间是 4,右侧小于 3,等价于 for(int i=4; i<3; i++)

for (i in 4…3) {

println(“for loop $i”)

}

//遍历输出4、3

for (i in 4 downTo 3) {

println(“for loop current $i”)

}

//遍历跨间隔输出 6、4、2、0,step 参数必须是正数

for (i in 6 downTo 0 step 2) {

println(“for loop step $i”)

}

//遍历输出 0、1,左闭右开区间

for (i in 0 until 2) {

println(“for loop until $i”)

}

}

函数式编程


关于函数式编程,对于 java 来说有很多框架的选择,譬如 rxjava 等等,但是对于 kotlin 来说,其天生支持这一能力,譬如:

fun testList() {

var array = listOf(“aa”, “bbb”, “c”, “dddd”, “eeeee”)

//如果bbb在列表则打印

when {

“bbb” in array -> println(“bbb in the list”)

}

//函数式编程实现:找出长度大于3,转换为大写,排序后逐个输出

array.filter { it.length >= 3 }.map { it.toUpperCase() }.sorted().forEach { println(it) }

}

解构声明


这个特性很像 ES6 的解构赋值,但又有自己的注意事项规则,譬如,kotlin 中默认能被解构的类必须是 data 类。如下:

//data数据类支持解构

data class RetValue(val statusCode: Int, val message: String)

//kotlin 提供的内置两值返回解构类型 Pair,也有三值的类型 Triple

fun test1(): Pair<Int, String> = Pair(404, “NotFound”)

/**

调用结果:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

题外话

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展~

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

E-1712285113846)]

[外链图片转存中…(img-6oYKAOEH-1712285113846)]

[外链图片转存中…(img-RXB9VPEH-1712285113847)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

题外话

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-EEUfGuPS-1712285113847)]

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展~

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值