Kotlin初识、及底图切换代码分析
简介
Kotlin是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。在Kotlin 语言出现之前,几乎所有的安卓应用程序都是使用Java语言编写的。但在2017年5月,google宣布Kotlin成为安卓的官方语言后,经过半年的发展,使用Kotlin 的开发者中5%增长到了15%,并且还在呈现上升趋势。
2017年9月29日,1.2Beta版发布。并宣布 Kotlin 成为 Android 官方开发语言。它即可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。那么我们为何要使用Kotlin?官方给出四个答案:简洁、安全、兼容(JAVA 安卓 REACT)、工具友好(任何JAVA开发IDE均可)。
首现给大家推荐几个学习地址,学习起来比较容易些:
Kotlin官方文档
Kotlin中文文档
kotlin开发者社区
菜鸟教程地址
Kotlin官方代码示例
Kotlin从入门到放弃系列视频
下面讲解下Kotlin和java相比优势是什么?
- 更简洁:这是它重要的优点之一,可以比Java编写少得多的代码。
- 实例化对象:相比较Java而言,在Kotlin中实例化对象无需new关键字
- 更安全:Kotlin是空安全的,它在编译期间就会处理各种为null的情况,无需像java一样添加很多的判空代码,节约很多调试空指针异常的时间,很大程度上避免出现NullPointException。
- 易扩展:扩展函数意味着我们不仅可以扩展我们原有写好的类,还可以扩展系统级的类,非常灵活,另外如果在类里编写扩展函数,那么只对当前类生效。
- 函数式:Kotlin使用了很多函数式编程的概念,比如用到了lambda表达式来更方便地解决问题。
- Kotlin Android Extensions:再也不用编写烦人的findViewById()了,如果你集成了ButterKnife,是时候删除对它的依赖了,Kotlin支持了对于View以id形式访问。
- 拒绝分号:如果开发Java会发现,我们在写好一个方法后都需要加上分号,来标志这句话或这个方法的结束。使我们养成了习惯。对于kotlin来说,不需要写分号这一点真是节省了很多时间,对于一天写成百上千行甚至上万行代码的童鞋来说,相当于省了多少个分号。
- 强大之处(兼容性):它是一门静态语言,支持多种平台,包括移动端、服务端以及浏览器端,此外,Kotlin还是一门融合了面向对象与函数式编程的语言,支持泛型、安全的空判断。兼容JAVA、 安卓 和REACT,并且Kotlin与Java可以做到完全的交互。
简洁性
java代码:类里就两个字段,一个id一个name
1 | public class User { |
kotlin代码:这一句代码就够了,Kotlin会自动生成所有属性和它们的访问器,以及一些方法,例如toString方法及equals方法。
1 | data class User(var name: String, var id: String) |
使用说明:编译器自动从主构造函数中声明的所有属性导出以下成员
- equals()/hashCode() 对;
- toString() 格式是 “User(name=John, age=42)”;
- componentN() 函数 按声明顺序对应于所有属性;
- copy() 函数
注: Data Class 是一个final类
- 构造函数中至少有一个参数
- 构造函数中的参数都需要声明var 或者val
- data class不能是抽象的,可继承的,或者内部类,因为类本身是final类型
- 如果需要显示的声明一个无参的构造方法,需要给构造方法里面的参数设置默认值
实例化对象
在kotlin中无需new对象,定义变量user,直接给对象传入参数值即可1
var user = User("kotlin","123")
空安全
当我们用Java写代码时,我们如果不想出现NullPointerException,我们需要在使用它之前每次去判断是否为空。而Kotlin这类空安全语言默认对象和字段不能为空,如果我们非要让一个字段或对象为空,那么必须使用安全操作符(?)来指定。1
2var user: User? = null
toast(user.name)
如上代码编译是无法通过的,因为user有可能为null,而user没对空情况做处理,所以无法编译。解决方式有两种:
//第一种:利用安全调用操作符,只有在user不为空时会调用user.name,否则调用toast(null)1
toast(user?.name)
//第二种:或者我们也可以给它赋一个默认值,当user为空时调用toast(“kotlin”)1
toast(user?.name ?: "kotlin")
易扩展
kotlin允许我们对任何类添加方法,包括系统级的类,自定义类等等,比如我想在Context类中添加一个toast方法。1
2
3fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
函数式
kotlin支持Lambdas表达式
正常写法为:1
2
3
4
5view.setOnClickListener(object : OnClickListener {
override fun onClick(v: View) {
toast("Click")
}
}
Lambdas表达式写发为:大大节俭了代码量
1 | view.setOnClickListener({view -> toast("Click")}} |
Kotlin Android Extensions
#####在开发中初始化控件时必不可少的,每次都要findViewById这样很麻烦。或许有些人为了方便采用注解形式,例如ButterKnife、Annotations等注解框架。但也避免不了在代码中加上一些注解代码。随着控件变多,注解也会随之增多。1
2
3
4
5
6
7
8
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lnLeft = findViewById(R.id.ln_left);
tvNice = findViewById(R.id.tv_nice);
ivBack = findViewById(R.id.iv_back);
}
Kotlin是怎样初始化控件的呢:
kotlin提供了另外一个思路,直接通过id来绑定。
首先在appbuilde.gradle中添加 ‘kotlin-android-extensions’。并导入import kotlinx.android.synthetic.main.activity_main.*即可。则导入了布局文件Id集合,可直接使用ID名对其控件进行操作1
2lnLeft.text="Hello"
tvNice.text="kotlin"
拒绝分号
如上是否有看到“;”的展示呢,这就是Kotlin的强大之处。
函数说明
fun main(args:Array<String>){
println(Hello Kotlin!)
}
- fun 函数声明,固定写法
- main 方法程序入口
- 接受参数名是args,数据类型是String
- 向控制台打印输出
常用语法
关键字
Fan:函数定义使用。格式为(参数:类型)
var:定义可变变量
val:定义不可变变量
In:定义区间
is:类型判断符
If:包含一个布尔类型表达式和一条或多条语句,和Java相同
when:将它的参数和所有的分支条件顺序比较,直到某个分支满足条件,和java中switch语句类似
for、while::循环遍历,和java类似
(以上均支持break和return)
数据类型
4.2.1 基本数据类型包括:Byte、Short、Int、Long、Double等
4.2.2 kotlin没有自动向上转型,如Int转Long,需调用toLong方法1
2var a:Int=10
var b:Long=a.toLong()
Kotlin常用符号
- :用于类的继承,变量的定义
- in 表示区间的意思
- $ 转换符号
- : :是将方法作为参数,传递到另一个方法中使用。
- ? 表示当前对象是否可空
- !! 表示当前对象不为空时执行
- “”” 表示输入多行文本,输入的内容将会原样保留
- @ 限定this类型
字符串模版
1 | override fun onCreate(savedInstanceState: Bundle?) { |
结果为:1
2args[0] =hello
args[1] =China
Kotlin中条件表达式
1 | fun max(a: Int, b: Int): Int { |
Kotlin 中 if 条件表达式省略写法:1
fun max2(a: Int, b: Int) = if (a > b) a else b
for 循环的使用
Kotlin 中使用的 for 循环,相比于 Java 中而言,要简介了很多。主要分为两种形式:一种是 in 关键字,in 关键字是直接使用数组中的对象进行循环,判断变量是否存在,如果存在续集循环,如果不存在,停止循环;一种是 indices 方法,indices 就是通过索引来进行循环的一种方式。代码实例如下:
in关键字的 for 循环:1
2
3
4val arr = arrayOf(1, 3, 4, 5, 6)
for (num in arr) { //直接使用数组中的对象循环
println(num)
}
indices 方法的 for 循环:1
2
3
4val arr = arrayOf(1, 3, 4, 5, 6)
for (i in arr.indices) { //通过索引循环
println(arr[i])
}
Kotlin中When条件表达式
在 Kotlin 中的 when 表达式和 Java 中的 switch 表达式有些类似,但是省略了 case 和 break,而且支持各种不同的类型,Java 中的 switch 表达式只是支持单一类型。1
2
3
4
5
6
7
8
9 fun chose(obj: Any) {
when (obj) {
1 -> print("Is Int")
"Hello" -> print("Hello Kotlin")
is Long -> print("Long")
!is String -> print("Not a string")
else -> print("Unknown") // 默认,相当于switch的default
}
}
ranges 的使用
使用 in 运算符检查数字是否在某一个范围之内
1 | if (x in 1..y-1) { ... } // 1..y-1表示1到y-1的范围 |
使用 in 运算符检查字符串区间
1 | fun main(args: Array<String>) { |
使用 in 运算符检查集合
1 | fun main(args: Array<String>) { |
Kotlin中Get和Set方法
1 | var <propertyName>[: <PropertyType>] [= <property_initializer>] |
格式就如上所示, set和get可写也可不写, 不写的话会有默认的实现, 需要注意的是val修饰的变量是没有set方法的, 也不允许重写set方法, 编译不通过!
下面是一个完整的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55class Student {
var name : String = "zhang"
// 这里使用field而不是使用lastName, 是因为如果使用lastName会造成递归调用从而造成内存溢出, 因为使用lastName也会涉及到调用set/get的问题
get() = field.toUpperCase()
var no : Int = 0
get() = field
set(value) {
if (value < 10) {
field = value
} else {
field = -1
}
}
var classTeacher : String? = "孔子"
set(value) = if (value == null) {
field = "李白"
} else {
field = value
}
/*set(value) = if (value == null) {
this.classTeacher = "李白"
} else {
this.classTeacher = value
}*/
var isKZ : Boolean = true
get() {
return this.classTeacher == "李白"
}
var className : String ? = "1班"
}
fun main(args: Array<String>) {
var stu: Student = Student()
stu.name = "wang"
println("lastName:${stu.name}")
stu.no = 9
println("no:${stu.no}")
stu.no = 20
println("no:${stu.no}")
stu.classTeacher = null
println(stu.classTeacher)
println(stu.isKZ)
stu.className = "一年一班"
println(stu.className)
}
运行结果如下:1
2
3
4
5
6lastName:WANG
no:9
no:-1
李白
true
一年一班
filed用法:它的作用就类似于java里的this.属性名, 例如上面代码中的 get() = field.toUpperCase(), 就相当于java里的 this.name.toUpperCase(),但是不能直接使用this.name会造成递归调用内存溢出的,因为在set和get中是不允许有和属性本身相同名字的局部变量,属性的调用也涉及到了set/get会造成递归调用, 所以要解决引用自身的问题, kotlin发明了field(后端变量)来解决这个问题
如下例子也是没有问题的:1
2
3
4
5
6var test : Int = 0
get() {
var t = 1
field = t
return field
}
总结
由于时间原因kotlin语法先讲到这里,常用且频繁出现的。后续文档还会进一步更新!文章内容作为铺垫,接下来我们一起学习下底图切换的内容!代码没有贴出,详见项目代码。以上就是我对kotlin的部分理解与说明,感谢你花费时间阅读这篇文章,祝您生活愉快!