为什么学习kotlin
kotlin在今年的Google IO 上正式被确认为Android的官方开发语言,想必原因大家也能猜到一二,一是Google与oracle关于Java相关的版权相关的问题,二是kotlin语言很简洁,不罗嗦,支持很多的新特性。
由于Google都已经官方支持了,语法简洁高效,和IOS的 swift 很是相似,发展趋势不可小觑,还有个大新闻就是我们的大神 Jake Wharton 从square 辞职加入了Google,且其在最近的github中国fork了kotlin 仓库,想必是为kotlin在Android的发展做贡献,就从这可以断定kotlin的未来不会太差, 当然作为技术人就需要不断的学习,不段的挑战。如果想在Android上继续深造kotlin肯定是要学习的。
怎么学习
我的想法是,大家都是学过基本的语言的,比如C,C++,做Android的肯定学过Java,所以我的想法是对照Java的基础与kotlin基础做对比着学习, 这样印象会深刻点,差异化学习。
Kotlin基础
Kotlin 数据类型
在kotlin语言中,所有的类型都是都是对象,kotlin中没有了基础数据类型(int,boolean,char,byte)等。全部换为对象类型。类型如下: Int
,Boolean
,String
,Byte
,Float
,Char
,Double
,Short
,这些没有了Java中隐式拓宽转换,例如不能把Int类型直接赋值给Long类型了,如要要这样做这些书类型可以调用如下方法进行转换:
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
- 1
- 2
- 3
- 4
- 5
- 6
- 7
kotlin 中各数字类型所占位数如下:
Type | bit |
---|---|
Double | 64 |
Long | 64 |
Float | 32 |
Int | 32 |
Short | 16 |
Byte | 8 |
数值常量和Java中基本无区别,十进制:123,十六进制:0x1F。
主要是以下几种字面值常量:
- 十进制数值: 123
- 长整型要加大写 L : 123L
- 16进制:0x0f
- 二进制:0b00001011
- 默认双精度浮点数(Double) : 123.5 , 123.5e10
- 单精度浮点数(Float)要添加 f 或 F :123.5f
注意: kotlin不支持八进制
黑魔法: 在我们写Int或者Long类型数据时,常常一写一长串,不便于识别,现在kotlin支持在数字常量中可以添加_
了,便于阅读,不影响数据类型和值,例如电话号码可以这样写了。val phone : Long = 186_****_0814
便于我们阅读。不得不说kotlin语言的灵活性。
kotlin中不会在末尾写分号啦!!!!!
== 与 ===的区别
在kotlin中多了一种判断符===
三个等号,这个特点呢就是判断两个对象是否指向同一个对象,也就是引用相等,而==
则表示的数据的结构相等,也就是调用equals
方法的返回值。例如:
var a : Int = 3
println(a===a) // true
var b : Int = a
var c : Int = a
println(b===c) // false 因为指向的对象不是同一个
println(b==c) // true
- 1
- 2
- 3
- 4
- 5
- 6
字符串
字符串有两种表达方式,一种是可以带转义符的,另外一种是可以包含任意字符的。例如下面有转义的val s = "hello world \n"
,但如果真正的字符串就是上面带有转义字符\n
的,那么要怎么表示呢,kotlin中使用三引号 """
来表示,例如:val s = """hello world \n"""
这样\n
就不会被转义为回车,而是原封原样的字符串了。
字符串还有了很好的模板特性,会极大的方便字符串拼接,操作等。下面就直接看例子:
val a = 1
var str : String = "this num is $a"
a = 2
val s2 = "${str.replace("is", "was")}, but now is $a"
- 1
- 2
- 3
- 4
可以看到这极大的方便字符串的操作,使用$即可直接取到变量的值,如果在字符串中操作则使用表达式${}
直接对字符串进行操作。
控制流
控制流基本与java中常用的保持一致,有for
,while
,但switch
在kotlin中换为when
,学过其他语言的应该都能很容易的掌握。
for 循环
for循环使用 in 关键字进行遍历,普通的如下:
val array = 1..100
for (value in array) {
print("value = $value")
}
- 1
- 2
- 3
- 4
对于之前for循环的步长使用step
来表示
for (i in 1..100 step 2) {
print("i = $i")
}
// 1..100 表示是闭区间 ,[1,100]
- 1
- 2
- 3
- 4
为了表示开闭区间,可以使用until
来表示。如下:1 until 100
表示 [1,100)
倒序的话将..
替换为downTo
while循环
while
循环与java 一样,不在多说,以及do while
when
when 的功能与java switch 功能类似,但是其便捷性不仅仅能case 一些基本数据类型,它可以支持表达式,这样会更加的灵活便捷。下面看个例子吧:
fun describe(obj: Any): String =
when (obj) {
1,‘1‘ -> "One"
"Hello","Good" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
看到上面的是不是很灵活? 可以对不同的类型在同一个分支中进行判断,极大的提高了灵活性。
集合
- 数组:
在Kotlin中使用Array
来表示数组,它本身定义了set
,get
,size
等属性,可以使用arrayOf
来创建数组,例如:var test = arrayof(1,2,3)
,数组中的数据类型可以是任何类型,但是使用时需要注意类型,访问可以用get(index)
或者[index]
来访问,
for (ar in array) {
print("array value = $ar")
}
for (i in array.indices) {
print("array value = $array[i]")
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- List
list的创建也很简便,使用listOf
创建,使用val list = listOf(1,2,3,"string")
, 当然遍历也提供了多种方式,如下:
for (it in list) {
print("list value = $it")
}
// 带下标,以及值的遍历方式
for ((index,value) in list.withIndex()) {
print("index = $index value = $value " )
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- Map
map的创建val map = mapOf("a" to 1, "b" to 2, "c" to 3)
,访问也是很简单,比java中访问简单太多,方式如下:
for ((key, value) in map) {
print("key = $key value = $value")
}
- 1
- 2
- 3
看到上面常见集合的类型套路都是一样使用类型Of()
来创建,访问遍历也是很方便。
空安全
在kotlin是空类型安全的,所以如果要给一个变量赋值为null,则必须在其定义后面加上?,否则无法编译器会报错。
var str : String ? = null
var size = str.length //此时会编译报错,提示可能为空
- 1
- 2
那么怎么获取呢,在kotlin中提供两种方法来访问,第一种为?.
的访问形式,此种表示如果为空则不执行,非空再继续,则上面则可以写成这样val size = str?.length
,第二种就是可能在执行前给变量赋值了,我们肯定它不为空,那么可以用!!.
来获取,如下:val size = str!!.length
,当然第二种你必须为运行时控制住做好心理准备。
变量
在Java中变量有普通的变量,静态常量(final
),静态编量(static
),但在kotlin中没有static
关键字了,需要使用静态变量有另外的一种表示,后续在将这部分,那在kotlin中的变量的表示方式为var
,常量的表达方式为val
, 具体表达方式如下:
val a :Float = 1f
, val a = "Aaron", var c :Int = 2, c += 2
kotlin中定义的类型是放在变量后面的,且类型有时可省略。
var a : Int = 2
, var a = 2
这两个表达的是一样的,后面的表达式会进行自动类型推倒。
kotlin是空类型安全的,所以在赋值时也有些差别,如果想要空类型的则在赋值后面需要加?
,
延迟属性
延迟属性或者延初始化可以帮助我们在需要用到时在初始化,不需要时不初始化,帮助程序节省内存空间及启动速度。
在kotlin中使用lazy
关键字来表示。直接看下面的例子:
val answer by lazy {
println("Calculating the answer...")
42
}
if (needAnswer()) { // 返回随机值
println("The answer is $answer.") // 此时计算出答案
}else {
println("Sometimes no answer is the answer...")
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
只有执行到上面needAnswer()为true时,answer才会被初始化。
想想是不是我们写的很多初始化的代码,都可以用lazy来延迟初始化了。
- 注意
by lazy
所赋值的变量必须为val
类型
函数
函数在kotlin中使用 fun
来表示,函数参数与定义变量一样放在变量后面,参数的类型不可省略,返回值也是在放在参数括号后面,当没有返回值的时候使用Unit
代替 java中的void
关键字,当然Unit
也是可以省略的。下面我们看几个例子:
fun sum(a: Int, b: Int): Int {
return a + b
}
// 等同于下面语句,简称函数式表达式
fun sum(a:Int, b:Int) = a + b
val sum = {x:Int ,y:Int -> x + y}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
上面就是一个简单的函数,有参数又返回值。
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
// 等同于下面
fun printSum(a: Int, b: Int) {
println("sum of $a and $b is ${a + b}")
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
上面则为没有返回值,其可以将函数后面的Unit
省略掉。
函数默认参数
在java中我们如果对同一个方法名,但是有不同的参数个数,需要写多个方法出来,看起来很臃肿,对于少参数的来说,可能就是某个参数为固定或者默认值,那么在kotlin中有了默认参数的表示方式。例如:
fun sum(a :Int , b : Int = 3) : Int {
return a +b
}
//调用 sum(1,2) // 代表 1 + 2
//调用 sum (2) // 代表2 + 3
- 1
- 2
- 3
- 4
- 5
- 6
函数具名参数
具名参数是对上面的一种特殊情况的考虑,比如我们将上面的代码改为如下:
fun sum(a :Int = 3, b : Int) : Int {
return a +b
}
//调用 sum (2) 此时对于此调用,编译器认为2 是为a赋值,而b没有赋值,无法编译通过。那么要调用则采用具名参数来指明参数。
// 改为 sum(b = 2) 这样既可指定将2赋值给b,则a使用默认的值。
- 1
- 2
- 3
- 4
- 5
- 6
扩展函数
在Android可能很常见的是有一个Utils包,专门放置一些常用的公共方法,比如String,Toast,File 操作等等,然而现在kotlin可以直接对系统类,进行扩展。
fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
//在Activity,Context实例中就可以直接调用了。
toast("我是Toast")
- 1
- 2
- 3
- 4
- 5
总结
上面讲述了kotlin 很基础的知识,讲解了些kotlin的特性,当然还有很多的特性,以及在Android上开发的便捷性等等,本篇就先说这么多,下一篇将会说到kotlin更多的特性,比如:自定义类的getter和setter 方法,inline 函数,高阶函数,数据类,单例类等。敬请期待!