Kotlin语言基础入门
Posted 红日666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin语言基础入门相关的知识,希望对你有一定的参考价值。
一、变量:
Kotlin中定义一个变量,只允许在变量前声明两种关键字:val 和 var。
1、val(value):声明常量
2、var(variable):声明变量
二、函数:
Kotlin函数的语法规则:
fun methodName(param1: Int, param2: Int): Int
return 0
注:如果函数不需要返回数据,则括号后面的部分可省略。
当函数只有一行代码时,可以这么写:
fun largeNumber(num1: Int, num2: Int): Int = max(num1, num2)
然后,根据Kotlin的类型推导机制,上述函数可进一步简化为:
fun largeNumber(num1: Int, num2: Int) = max(num1, num2)
三、面向对象编程:
1、类与对象:
声明一个类:
Kotlin中也是使用class关键字来声明一个类。
实例化一个类:
Kotlin中实例化一个类的方式和Java基本类似,只是去掉了new关键字。
2、继承和构造函数:
- 要想一个类(如Student)继承另一个类(如Person),我们得做两件事才可以:
<1> 使Person类可以被继承,即需在类前面添加open关键字。因为在Kotlin中默认非抽象类都是不可以被继承的。
open class Person
...
<2> 继承使用 : 代替Java的extends关键字。
class Student : Person()
...
- kotlin将构造函数分成了两种:主构造函数和次构造函数:
主构造函数:
主构造函数是最常用的构造函数,每个类默认都会有一个不带参数的主构造函数,当然也可以显式地给它指明参数。主构造函数的特点是没有函数体,直接定义在类名的后面即可。
class Student(val name: String, val age: Int) : Person()
...
由于主构造函数没有函数体,如果想在主构造函数中编写一些逻辑,可以写到init结构体中。
//在这里,Person类后面的一对空括号表示Student类的主构造函数在初始化的时候回调用Person类的无参构造函数。
class Student(val name: String, val age: Int) : Person()
init
println("name is:" + name)
println("age is:" + age)
次构造函数:
任何一个类只能有一个主构造函数,但是可以有多个次构造函数。Kotlin规定,当一个类中既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)。次构造函数时通过constructor关键字来定义的。
class Student(val name: String, val age: Int, sno: String, grade: Int) : Person(sno, grade)
constructor(sno: String, grade: Int): this("", 18, son, grade)
...
constructor() : this("", 0)
...
Kotlin允许类中只有次构造函数,没有主构造函数:
class Student : Person()
//由于没有主构造函数,次构造函数只能直接调用父类的构造函数
constructor(name: String, age: Int) : super(name, age)
...
3、接口:
Kotlin中实现接口的关键字也是:,中间用逗号进行分隔。
interface Study
fun readBooks()
//允许对接口中定义的函数进行默认实现
fun doHomework()
pringln("do homework default implementation.")
class Student(name: String, age: Int) : Person(name, age), Study
override fun readBooks()
println(name + " is reading.")
Kotlin有四种可见修饰符:
public:对所有类都可见。但在kotlin中public修饰符是默认项,而在Java中default才是默认项。
private:跟Java的private一样,只对当前类内部可见。
protected:kotlin中表示只对当前类和子类可见。而在Java中表示对当前类、子类和同一包路径下的类可见。
internal:只对同一模块中的类可见。kotlin抛弃了Java中的default可见性(同一包路径下的类可见)。
4、数据类与单例类:
数据类:
//当在一个类前面声明了data关键字时,就表明你希望这个类是数据类,Kotlin会根据主构造函数中的参数帮你
//将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成。
data class Cellphone(val brand: String, val price: Double)
单例类:
在kotlin中创建一个单例类的方式及其简单,只需要将class改成object关键字即可:
object Singleton
fun singletonTest()
println("singletonTest is called")
四、Lambda编程:
1、集合的创建与遍历:
Kotlin专门提供了一种内置的listOf()函数来初始化集合:
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
需要注意的是listOf()函数创建的是一个不可变集合。
如果需要创建一个可变的集合,可以使用mutableListOf()函数:
val list = mutableListOf("Apple", "Banana", "Orange", "Pear", "Grape")
list.add("Watermelon")
Set集合用法类似,setOf()与mutableSetOf()分别表示不可变与可变Set集合。
同样,Map集合函数中,mapOf()和mutableMapOf()函数分别表示不可变与可变Map键值对集合:
mapOf()函数:
val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)
for((fruit, number) in map)
println("fruit is " + fruit + ", number is " + number)
mutableMapOf()函数:
val map = mutableMapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)
//以下是两种map添加数据的方式
map.put("Peach", 6)
map["Watermelon"] = 7
for((fruit, number) in map)
println("fruit is " + fruit + ", number is " + number)
2、集合的函数式API:
Lambda的(直白)定义:
Lambda就是一小段可以作为参数传递的代码。
Lambda表达式的语法结构:
参数名1: 参数类型, 参数名2: 参数类型 -> 函数体
Lambda表达式可以从 list.maxBy it.length 方法来说起。即求list集合中单词最长的那个水果:
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy it.length
println("max length is " + maxLengthFruit)
上面这种写法方式是如何生成的呢,下面一步步进行分析:
- maxBy函数实质上是接收了一个Lambda参数,根据上面定义的Lambda表达式的语法结构,可得:
val lambda = fruit: String -> fruit.length
val maxLengthFruit = list.maxBy(lambda)
即:
val maxLengthFruit = list.maxBy( fruit: String -> fruit.length )
- Koltin规定,当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面:
val maxLengthFruit = list.maxBy() fruit: String -> fruit.length
- 接下来,如果Lambda参数时函数的唯一一个参数的话,还可以将函数的括号省略:
val maxLengthFruit = list.maxBy fruit: String -> fruit.length
- 由于Kotlin拥有出色的类型推导机制,Lambda的表达式中的参数列表其实在大多数情况下不必声明参数类型:
val maxLengthFruit = list.maxBy fruit -> fruit.length
- 当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替。所以最终代码就变成了最开始列出的list.maxBy it.length 。
val maxLengthFruit = list.maxBy it.length
map函数:
集合中的map函数是最常用的一种函数式API,它用于将集合中的每个元素都映射成一个另外的值:
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val newList = list.map it.toUpperCase()
filter函数:
filter函数是用来过滤集合中的数据的,它可以单独使用,也可以结合map函数使用:
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
//过滤出单词中小于等于5的单词,并转换为大写
val newList = list.filter it.length <=5 .map it.toUpperCase()
any函数和all函数:
any函数用于判断集合中是否至少存在一个元素满足指定条件;all函数用于判断集合中是否所有元素都满足指定条件:
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val anyResult = list.any it.length <= 5 //true
val allResult = list.all it.length <= 5 //false
3、Java函数式API的使用:
如果我们在Kotlin代码中调用了一个Java方法,并且该方法接收一个Java单抽象方法接口【接口中只有一个待实现方法】参数,就可以使用函数式API:
Java代码创建并执行一个子线程:
new Thread(new Runnable()
@Override
public void run()
System.out.println("Thread is running")
).start()
Kotlin版本如下:
//由于Kotlin完全舍弃了关键字new,因此创建匿名类实例的时候就不能再使用new了,而是改用了object关键字
Thread(object: Runnable
override fun run()
println("Thread is running")
).start()
由于目前Thread类的构造方法是符合Java函数式API的使用条件的,所以可做精简:
//因为Runnable类中只有一个待实现方法,即使这里没有显示的重写run()方法,Koltin也能自动明白Runnable后面的Lambda表达式就是要在run()方法中实现的内容
Thread(Runnable
println("Thread is running")
).start()
如果一个Java方法的参数列表中不存在一个以上Java单抽象方法接口参数,我们还可以将接口名进行省略:
Thread(
println("Thread is running")
).start()
当Lambda表达式是方法的最后一个参数时,可以将Lambda表达式移到方法括号的外面。同时,如果Lambda表达式还是方法的唯一一个参数,还可以将方法的括号省略:
Thread
println("Thread is running")
.start()
五、空指针检查:
1、可空类型系统:
Java语言的NPE问题一直是个令人头疼的问题。然而,Kotlin却非常科学地解决了这个问题,它利用编译时判空检查的机制几乎杜绝了空指针异常。
也就是说,Kotlin将空指针异常的检查提前到了编译时期,如果我们的程序存在空指针异常风险就会出现编译出错,只有修正之后才能成功运行。
另外Kotlin提供了一套可为空的类型系统【用于支持业务中真的需要某个变量或参数为空的情况】,就是在类名的后面加上一个问号。如String表示不可为空的字符串,而String?表示可为空的字符串。
2、判空辅助工具:
- ?.操作符:
当对象不为空时正常调用相应的方法,为空时什么都不做。
if(a != null)
a.doSomething()
//以上代码使用?.操作符可以简化成:
a?.doSomething()
- ?:操作符:
该操作符的左右两边都接收一个表达式,如果左边的表达式不为空就返回左边表达式的结果,否则就返回右边表达式的结果。
val c = if(a != null)
a
else
b
//以上代码使用?:操作符可简化为:
val c = a ?: b
?.操作符与?:操作符结合使用举例:
fun getTextLength(text: String?): Int
if(text != null)
return text.length
return 0
//以上代码可简化为:
fun getTextLength(text: String?) = text?.length ?: 0
- !!操作符:
是一种非空断言工具,告知Kotlin确信此处不会为空,所以不用Kotlin再帮做空指针检查了。这是有风险的一种写法,慎用。
val content: String? = "hello"
fun printUpperCase()
val upperCase = content!!.toUpperCase()
println(upperCase)
- let函数配合?.:
let函数提供了函数式API的编程接口,并将原始调用对象作为参数传递到Lambda表达式中:
这里调用了obj对象的let函数,然后Lambda表达式中的代码就会立即执行,并且这个obj对象本身还会作为参数传递到Lambda表达式中。这里obj和obj2是同一个对象。
obj.let obj2 ->
//编写具体的业务逻辑
let函数结合?.操作符举例:
//?.操作符表示对象为空时什么都不做,对象不为空时就调用let函数,而let函数会将study对象本身作为参数传递到Lambda表达式中,此时的study对象肯定不为空了。
fun doStudy(study: Study?)
study?.let stu ->
stu.readBooks()
stu.doHomework()
当Lambda表达式的参数列表中只有一个参数时,可以不用声明参数名,直接使用it关键字来代替即可:
fun doStudy(study: Study?)
study?.let
it.readBooks()
it.doHomework()
另外let函数是可以处理全局变量的判空问题的,而if判断语句则无法做到这一点。
var study: Study? = null
fun doStudy()
if(study != null)
//编译时这里会报错
study.readBooks()
study.doHomework()
六、Kotlin使用小技巧:
1、字符串内嵌表达式:
kotlin允许我们在字符串里嵌入$这种语法结构的表达式,并在运行时使用表达式执行的结果替代这一部分内容:
"hello, $obj.name. nice to meet you!"
当表达式中仅有一个变量是,可以将省略:
"hello, $name. nice to meet you"
2、函数的参数默认值:
我们在定义函数的时候可以给任意参数设定一个默认值,当调用此函数时就不会强制要求调用方为此参数传值,在没有传值的情况下回自动使用该参数的默认值:
fun playMovie(num: Int, name: String = "梁朝伟")
println("num is $num, name is $name")
//调用1 -- name会打印默认值
playMovie(7788)
//调用2 -- name会打印金城武
playMovie(7799, "金城武")
以上情况正好是最后一个参数设置了默认值,如果不是这种情况,应该如何传参呢?
fun playMovie(num: Int = 8899, name: String)
println("num is $num, name is $name")
//调用1 -- 编译报错,因为String跟首个参数类型Int无法匹配
playMovie("金城武")
Kotlin提供了一种机制,即可以通过键值对的方式来传参:
//调用2 -- 键值对传参 编号打印默认值
playMovie(name = "金城武")
//调用3 -- 编号打印7799
playMovie(num = 7799, name = "金城武")
参考:
《第一行代码》第3版
以上是关于Kotlin语言基础入门的主要内容,如果未能解决你的问题,请参考以下文章