【Kotlin】初识Kotlin(一)
1、浅短认识Kotlin
首先,咱们只需要认识一点,就可以看见这门语言的含金量!
在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。
其次,我们在认识到一点,就可以看见这门语言的兼容性!
Kotlin能够和Java达到100%互通,也就是说,使用Kotlin依旧可以调用 Java已有的代码或库,也可以同时使用Java和Kotlin来混合编写代码。
最后,Kotlin中的很多语法的规范性和安全性都得到了质的提高,同时,其语法的难易度也下降了很多,学习过Java的基本上入门Kotlin也是非常友好的!
我对Kotlin初步的看法是什么呢?
- 代码简短,很多语法糖有python的影子,格式也类似
- 思想典型,面向对象的思想基本和Java可以一一对应
- 美观易懂,在lambda上的精简程度可以说是完美
- ......
Kotlin有很多优点,而学习它能过在未来的编程过程中打下坚实的基础!
2、如何创建Kotlin项目?
无论是IDEA还是Android Studio,都是可以直接编辑Kotlin代码的。
- 目前Spring boot框架已经兼容了Kotlin,并且可以创建Kotlin项目
- Android开发也可以使用Kotlin来进行app的编写
我这里使用IDEA来举例子:
新建一个项目
创建Kotlin项目
一路next就完事了
最后需要等待gradle的第一次构建(需要比较长的时间,耐心等待一下)
3、hello world
使用Kotlin简简单单的写一个hello world
fun main(args: Array<String>) {
println("hello world!")
}
上面的方法和Java中的如下代码是一样的
public class test {
public static void main(String[] args) {
System.out.println("hello world!");
}
}
和Java的区别:
- 不必用分号结束
- 参数使用
参数名: 参数类型
的方式 - main方法不需要写在一个class中
4、Kotlin控制台的输入输出
入门一门语言,最开始学习都是这样的流程
- 输出 “输入姓名”
- 通过控制台输入...
- 输出 “你的姓名是XXX”
很多人都喜欢使用如上的方法来接触一门语言中最基本的方法(函数),如果想利用Kotlin来进行控制台交互,那么可以如此:
- 使用
println()
或者print()
来进行输出 - 使用
readLine()
来进行控制台输入 - 导入
Java的Scanner
来进行控制台输入
我们来演示一个最简单的例子
fun main() {
println("请输入你的姓名:")
val name = readLine()
println("请输入你的年龄:")
val scanner = Scanner(System.`in`)
val age = scanner.nextInt()
println("你的姓名是:$name")
println("你的年龄是:$age")
}
/*
请输入你的姓名:
woodwhale
请输入你的年龄:
19
你的姓名是:woodwhale
你的年龄是:19
进程已结束,退出代码0
*/
4、Kotlin中的变量与常量
1.可读写变量var
可读写变量在Kotlin中使用关键字var
来表示,我们可以理解为一个具有getter和setter的private属性对象
格式就是: var 变量名:变量类型 = 赋值
var value:Int = 1
当然,kotiln很智能,可以推断出当前这个变量是什么类型的,所以上面的赋值我们可以简写为:
var value = 1
上面这个情况是整数,而我们知道,除了int类型,大部分语言中还有其他的数字数据类型,Kotlin中有如下几种基本的数据类型:
- 整型
- Short(16位)
- Int(32位)(默认推断)
- Long(64位)
- 浮点型
- Float(32位)
- Double(64位)
- 字节
- Byte(8位)
- 字符型
- Char
- String
- 布尔型
- Boolean
注意:
- 不同的数据类型可以通过
toXX()
方法来转换,并且Kotlin不会Java一样,自动装箱拆箱,无法直接将一个Int类型值转为Long类型,需要调用toLong()
方法来转换 - 从较大的类型转换为较小的类型可能会
截断该值
,例如Long转为Byte
将上述的各个变量都使用Kotlin写一遍
fun main() {
// 整型
var oneShort:Short = 1
var twoInt:Int = 1
var threeLong:Long = 1
// 浮点型
var fourFloat:Float = 4.0f
var fiveDouble:Double = 5.0
// 字节
var sixByte:Byte = 6
// 字符
var sevenChar:Char = '7'
var eightString:String = "8"
// 布尔型
var flag:Boolean = true;
}
值得一提的是String变量使用了python中的三个引号的方式来声明变量,可以支持换行
fun main() {
var longString = """
oneLine
twoLine
threeLine
""".trimIndent()
println("my input : \n$longString")
}
如果上述代码没有trimIndent()
方法,那么连tab缩减也会一并打印出来
细心的你还发现了一个$
符号,其实这是Kotlin的一个特性,可以用$
来指代变量(或者常量)
如果你想仅仅打出$
这个符号,只需要加一个转义字符\
到前面就可以了\$
println("\$longString") // 这样输出的就是 $longString
2.可读不可写变量val
可读但是不可写的变量使用关键字val
来修饰,我们可以把它理解成一个具有getter但是没setter的private对象
也就是说,val修饰的变量是只能读的,一旦申明就无法更改了
值得注意的是,Kotlin官方建议:能用val处理的变量尽量不要用var来处理
这里就不多细讲了,就是上述的var没有第二次更改的权限的一种变量
3.编译器常量const val
使用const val修饰的是常量,是在编译时期就会进行初始化的常量,我们可以理解为Java中public static final修饰的一个值
一般我们使用大写的字母加上下划线来对常量赋值,并且Kotlin中常量的赋值位置有两个
top-level级别
- 所谓的top-level就是位于代码文件的最外部,比如常见的类(非内部类和嵌套类)就是在top-level。意思是在结构上常量不属于任何的类,而是属于文件。
object级别
- object中可以指的是最外部的object也可以指的是companion object(伴生类)
// top-level
const val BASE_URL = "https://www.woodwhale.top/"
class Test {
companion object {
const val BASE_URL = "https://www.woodwhale.top/"
}
}
现在还没学习到Kotlin的面向对象,所以不需要深入理解类与对象的思想
5、Kotlin中的区间和过程
区间在每个语言中都有,从最基础的for循环开始,就有区间的涉及了
Kotlin中对于区间有专门的数据对象IntRange
,有专门的过程数据对象IntProgression
fun rangeFun() {
val firstRange:IntRange = 0..1
val secondRange = 0.rangeTo(1)
val thirdRange = 0 until 2
val fourthRange = 0.until(2)
}
fun progressionFun() {
val firstProgression : IntProgression= 0 .. 100 step 2
val secondProgression = 0 until 100 step 4
}
如上述代码,第一个和第二个区间是等价的,表示[0,1]
,第三个和第四个区间是等价的,表示[0,2)
当然IntRange
类型和IntProgression
类型可以省略不写,让Kotlin自动识别
我们一般使用区间和for循环一起使用
for (i in firstRange) {
println(i)
}
for (i in firstProgression) {
println(i)
}
6、Kotlin中的数据容器
数据容器最常用的就几种
- 数组
- set
- map
- list
后三种可以统称为集合
让我们来学习Kotlin中这些数据容器的基本使用方法!
1.数组
Kotlin中创建数组的方法有很多
- arrayOf()方法
- arrayOfNulls()方法
- 动态创建数组
(1) arrayOf方法创建数组
创建一个数组并且将元素初始化,数组中的元素可以是任何类型
fun main() {
val testArray = arrayOf(1,2,3)
val testArray2 = arrayOf("String",'c',114,false)
}
(2) arrayOfNulls方法创建数组
创建一个指定大小
,元素为空的数组,必须指定元素类型
fun main() {
val testArrayOfNulls = arrayOfNulls<String>(114)
testArrayOfNulls[0] = "first"
testArrayOfNulls[113] = "last"
}
(3) 动态创建数组
我们可以使用Array()类的构造方法进行动态数组的实例化,需要初始化Array对象的大小,这里使用的是10,同时可以给其中的对象使用lambda进行赋值,如下代码就是将0~9这些数据存入到了Array中
fun main() {
// 创建一个Array<Int>初始化为[0,1,2,3,4,5,6,7,8,9]
val testArray = Array(10){i -> i} // 使用lambda表达式
println(testArray.joinToString())
}
/*
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
进程已结束,退出代码0
*/
(4) 原生类型数组
在Kotlin中有无装箱开销的专门的类来表示原生数组
原生数组类型 | 含义 |
---|---|
ByteArray | 字节数组 |
ShortArray | 短整型数组 |
IntArray | 整型数组 |
LongArray | 长整型数组 |
BooleanArray | 布尔型数组 |
CharArray | 字符型数组 |
FloatArray | 浮点型数组 |
DoubleArray | 双精度浮点数组 |
举个例子:
fun main() {
// 初始化一个[0,1,2,3,4]的Int数组
val testIntArray = IntArray(5){it}
println(testIntArray.joinToString())
}
这里的it其实是lambda表达式中的内容,我们现在就理解为遍历这个数组时候的下标就可以了,将下标这个数字赋值给当前下标的数组内容,就可以得到[0,1,2,3,4]的Int数组啦
2.数组的遍历
我们尝试使用for循环进行数组的遍历,结合我们上面所学的区间和过程
来完成
for循环有两种方式
- 普通的for循环
- foreach循环
在Kotlin中,也是具有这两种循环的方式,并且结合了Java中Array.steam的优点,也具有foreach循环的方法
下面我们就来学习一下两种循环如何写!
(1) for循环下标遍历
在Java
中,我们最常见的写法如下
for (int i = 0; i < someArray.length; i++) {
doSomething()
}
很明显,这是在遍历一次数组,在``Kotlin`中可以结合区间来写
// 初始化一个[0,1,2,3,4]的Int数组
val testIntArray = IntArray(5){it*2}
for (index in 0 until testIntArray.size) {
println(testIntArray[index])
}
0 until testIntArray.size
表示[0,testIntArray.size)这个区间,是不是和Java中的代码对应了呢?
但是Kotlin其实有更简单的遍历表达方式,已经帮你想好啦
// 初始化一个[0,1,2,3,4]的Int数组
val testIntArray = IntArray(5){it*2}
for (index in testIntArray.indices) {
println(testIntArray[index])
}
使用testIntArray.indices
属性,就可以得到当前这个数组的步频为1的区间过程啦,减少了代码量
(2) foreach元素遍历
foreach是进行元素遍历的,在Java
中,这样的遍历如下:
for (String s in strs) {
doSomething(s);
}
那么在kotln
中,写法与Java类似,只不过方便了不用再写一次数据类型,Kotlin会自动推断
// 初始化一个[0,1,2,3,4]的Int数组
val testIntArray = IntArray(5){it*2}
for (intItem in testIntArray) {
println(intItem)
}
当然了,我们不用担心存在不同元素类型的数组,我们在遍历的时候,都是可以对这些元素进行操作的
fun main() {
val arr = arrayOf(1,"2",false,'4')
for (item in arr) {
when (item) {
is Int -> println("Int type $item")
is String -> println("String type $item")
is Boolean -> println("Boolean type $item")
is Char -> println("Char type $item")
}
}
}
/*
Int type 1
String type 2
Boolean type false
Char type 4
进程已结束,退出代码0
*/
上述代码使用了when关键字,等到我们下一章再开始学,我们先理解其为switch就可以啦。并且,使用的is关键字表示判断item是否是某个数据类型。
在Kotlin中,还有一种forEach()方法
,可以进行循环使用
arr.forEach {
when (val item = it) {
is Int -> println("Int type $item")
is String -> println("String type $item")
is Boolean -> println("Boolean type $item")
is Char -> println("Char type $item")
}
}
如上代码的效果与我们使用经典的forEach的效果是一样的,这里的it是迭代器中当前的item
(3)foreach带上下标
Kotlin中有一种特殊的foreach,可以将index和item同时使用,减少代码量
使用arr.withIndex()
的方法,可以带出index和item两个值,就可以同时对这两个元素进行操作
val arr = arrayOf(1,"2",false,'4')
for ( (index,item) in arr.withIndex()) {
println("$item 's index == $index")
}
/*
1 's index == 0
2 's index == 1
false 's index == 2
4 's index == 3
进程已结束,退出代码0
*/
同时在Kotlin中,还有一种arr.forEachIndexed()
的方法,也可以做到index和item同时更改
arr.forEachIndexed() {
index, item ->
println("$item 's index == $index")
}
或者将代码写在括号内也是可以的
arr.forEachIndexed({ index, item -> println("$item 's index == $index") })
这些方法都是使用了lambda表达式,现在看看用法就可以了,我们之后再详细学习!
3.集合
集合这种数据结构在各种工程中是必不可少的一部分。与数组不同的是可变集合的大小是可以动态改变的
- List:有序集合,可以通过下标访问元素,同一元素可以在list中
出现多次
- Set:唯一元素集合,一组无重复元素的集合,一般不注重顺序,注重
是否存在
- Map:键值对集合,键唯一,值可以重复,一个映射,注重
一一对应
与Java中的集合不同的是,Kotlin中的集合有可变的和不可变的,可变的集合可以动态添加元素,不可变的集合只能在初始化的时候就进行申明
(1) List的创建
我们先来创建一个可变集合,可以使用两种方法
- arrayListOf<T>()
- mutableListOf<T>()
fun main() {
val mutableListOf = mutableListOf<String>("-1","0")
mutableListOf.add("1")
mutableListOf.add("2")
mutableListOf.forEach() { println(it)}
val arrayListOf = arrayListOf<String>()
arrayListOf.add("3")
arrayListOf.add("4")
for (s in arrayListOf) { println(s)}
}
当前阶段,这两个方法返回的都是ArrayList
,但是Kotlin官方计划将之后的mutableList与ArrayList区分开来。所以在Kotlin中咱们尽量使用mutableListOf()方法来创建list吧!
再来创建一个不可变的集合,使用方法
- listOf<T>()
val listOf = listOf<String>("1", "2", "3")
println(listOf)
注意,listOf得到的集合是不可变
的,也就是没有set方法,只能get!
(2) Map的创建
首先介绍Kotlin中的键值对,可以使用Pair("key", "value")
的方式来创建,也可以简写成"key" to "value"
可变Map的创建也有很多方法
- mutableMapOf<K,V>() (返回可变的mutableMap)
- hashMapOf() (返回可变的HashMap)
- linkedMapOf() (返回可变的LinkedHashMap)
- sortedMapOf() (返回可变的TreeMap)
可变的map可以使用put方法
动态添加,用get方法
获取。当然也可以使用Kotlin自己的方式,使用下标来获取、赋值
fun main() {
val mutableMap = mutableMapOf("key" to "value")
mutableMap.put("key1","value1")
mutableMap["k2"] = "v2"
val hash = hashMapOf<String, String>("name" to "alfred")
val linkedMap = linkedMapOf<String, String>("age" to "27")
val treeMap = sortedMapOf("sex" to "man")
println(mutableMap.get("key1"))
println(hash["name"])
println(linkedMap)
println(treeMap)
}
那么如何删除map的key呢
- 使用
remove()
方法 - 或者使用
-
号
fun main() {
val mutableMap = mutableMapOf("key" to "value")
mutableMap.put("key1","value1")
mutableMap["k2"] = "v2"
mutableMap.remove("k2")
mutableMap -= "key1"
println(mutableMap)
}
不可变的Map创建的方式如下,使用mapOf<K,V>()
方法
val mapOf = mapOf<String,String>(Pair("key", "value"))
val mapOf1 = mapOf("key" to "value")
需要注意的是,用mapOf创建的map是不可变的,所以需要在初始化的时候就申明key和value。
(3) Set的创建
和上面的集合结构一样,也是具有可变set和不可变的set
可变set的创建方式,与map类似
- mutableSetOf<K,V>() (返回可变的mutableSet)
- hashSetOf() (返回可变的HashSet)
- linkedSetOf() (返回可变的LinkedHashSet)
- sortedSetOf() (返回可变的TreeSet)
fun main() {
val mutableSetOf = mutableSetOf("1", "2")
mutableSetOf.remove("1")
mutableSetOf -= "2"
println("1" in mutableSetOf)
println("3" in mutableSetOf)
}
不可变的set创建方式就是 setOf()
方法
fun main() {
val of = setOf("1", "2")
println(of)
}
(4) 集合的总结
- listOf 创建不可变 List, mutableListOf() 创建可变的 List
- setOf 创建不可变 Set, mutableSetOf() 创建可变 Set
- mapOf 创建不可变 Map, mutableMapOf() 创建可变的 Map
- mutable 前缀的函数创建是可变的集合,没有 mutable 前缀的创建不可变的集合
- 不可变集合可通过 toMutable*() 函数换成可变的集合,也就是创建新的可变集合并把数据放进去
7、Kotlin的更多内容
由于篇幅限制,后面更多的Kotlin语法、关键字的使用方法在下一篇文章中讲述!