Kotlin基础语法
- Kotlin内置数据类型
- 变量
- 可读可写变量
- 可读变量
- 自动类型推导机制
- when表达式
- range表达式
- 字符串模版
- 函数
- 函数定义
- 函数简写
- 默认参数
- 具名函数参数
- Unit函数
- 反引号函数
- 匿名函数
- 隐式返回
- 函数作为形参
- 函数引用
- 函数作为返回值
- 可空性
- 高级函数 let
- 非空断言
- 空合并操作符
- 高级函数
- apply函数
- run函数
- with函数
- also函数
- takeIf函数
- takeUnless函数
- 集合
- List
- 可变List
- Set
- 可变Set
- 数组
- Map
- 可变Map
- 类
- 主构造函数
- 次构造函数
- lateinit 延迟初始化
- lazy 惰性初始化
- 继承和重载
- companion objec 伴生对象
- 内部类
- 嵌套类
- 数据类
- 运算符重载
- 枚举类
- 代数数据类型
- 密封类
- 接口
- 抽象类
- 泛型类
- vararg 动态参数
- 协变&逆变
- 协变
- 逆变
- 扩展函数
- 单例模式
- 饿汉式
- 懒汉式
- 懒汉式-加锁
- 懒汉式-双重校验
Kotlin内置数据类型
名称 | 释义 |
---|---|
String | 字符串 |
char | 字符 |
Boolean | 布尔型 |
Int | 整型 |
Float | 单精度浮点型 |
Double | 双精度浮点型 |
List | 集合 |
Set | 无重复元素集合 |
Map | 键值对集合 |
变量
可读可写变量
var name: String = "Kotlin"
name = "C++"
println(name)
可读变量
val name: String = "Kotlin"
//下列变量不可修改,因为声明成val,只能进行读操作,不能进行写操作
//name = "C++"
println(name)
自动类型推导机制
根据定义变量时进行初始化,系统可以根据初始化值自动进行类型推导,进而可以省略类型声明
val name = "Kotlin" //String
val age = 5 //Int
val sex = m' //char
val score = 99.99 //Doble
when表达式
val week = 5val info = when(week){1-> "星期一"2-> "星期二"3-> "星期三"4-> "星期四"5-> "星期五"6-> "星期六"7-> "星期天"else-> "错误类型"}println(info)
range表达式
val score = 70when (score) {in 0..59 -> {println("不及格")}in 60 ..79 -> {println("及格")}in 80 .. 89 -> {println("良好")}else -> {println("优秀")}}
字符串模版
val name = "Kotlin"val age = 7val score = 32val detail = "I am $name and $age,I got ${score+10} in the last test."println(detail)
函数
函数定义
- 在Kotlin中函数默认访问类型为Public,此处我声明为private
fun
为声明函数关键字add
为函数名a:Int,b:Int
为函数形参- 形参列表后面有一个
:Int
,代表函数返回Int
private fun add(a:Int,b:Int):Int{
val result = a+b
println(result)
return result
}
函数简写
当函数体只有一行代码时,可以不写括号,直接在等号后面接代码即可
private fun add(a:Int,b:Int) = println(a+b)
若函数需要返回值,则直接将计算结果接在等号后面返回
private fun add(a:Int,b:Int):Int = a+b
默认参数
fun printfInfo(name:String,age:Int) = println("I am $name and $age")fun printfInfo(name:String="Li",age:Int) = println("I am $name and $age")fun printfInfo(name:String="Li",age:Int=20) = println("I am $name and $age")
具名函数参数
具名参数可以任意调整实参的顺序
printfInfo(age = 10,name = "Kotlin")
...
fun printfInfo(name:String,age:Int) = println("I am $name and $age")
Unit函数
在JAVA中void为空返回类型,是一个关键字
在Kotlin中Unit是一个类类型,为函数默认返回类型
private fun exe():Unit{return println()
}
反引号函数
打印分数(20.22)
...
private fun `打印分数`(score:Double){println("分数=$score")
}
匿名函数
val len = "Kotlin".count()println("len=$len")val len1 = "Kotlin,in".count { it->it == 'i'}println("len1=$len1")
隐式返回
函数声明
val printfScore:(score:Double)->String
函数实现,匿名函数无需使用return
返回结果,以最后一行作为返回值进行返回
printfScore = { it->println("score$it")"打印成功!"}
函数调用
printfScore(50.50)
函数作为形参
const val NAME = "Kotlin"
const val AGE = 10
//...
JudgeInfo("Kotlin",10){ info,code->println("info=$info,code=$code")}
//...
fun JudgeInfo(name:String,age:Int,respond:(String,Int)->Unit){val result = name == NAME && age == AGEif (result == true){respond("success",200)}else{respond("failed",404)}
}
函数引用
const val NAME = "Kotlin"
const val AGE = 10
//...
JudgeInfo("Kotlin",10,::printfInfo)fun printfInfo(info:String,code:Int) = println("info=$info,code=$code")
//...
fun JudgeInfo(name:String,age:Int,respond:(String,Int)->Unit){val result = name == NAME && age == AGEif (result == true){respond("success",200)}else{respond("failed",404)}
}
函数作为返回值
const val NAME = "Kotlin"
const val AGE = 10
//...
val exe = JudgeInfo()
println(exe("Kotlin",10))//...
fun JudgeInfo():(name:String,age:Int)->Boolean{return { name,age->val result = name ==NAME && age ==AGEresult}
}
可空性
在Kotlin中不能直接给一个变量赋值null
,这也极大减少了空异常频发问题
如果需要给一个变量赋null,则需要在声明时,在变量类型后面加一个?
,示意准许此变量在程序中为null
val name:String ? = null
println(name)//打印出null
将一个可空类型字符串变量转为大写,需要在调用uppercase
函数时前面加一个?
,代表如果name不为空则执行uppercase
函数,否则不执行?
后面的函数
var name:String ? = null
name = "kotlin"
val msg = name?.uppercase()
println(msg)
高级函数 let
var name:String ? = null
name = "kotlin"
val msg = name?.let {it.uppercase()
}
println(msg)
非空断言
var name:String ? = null
name = "kotlin"
val msg = name!!.uppercase()
println(msg)
空合并操作符
var name:String ? = null
println(name ?: "name为空!")
高级函数
apply函数
- apply函数始终返回对象本身
- apply匿名函数在内部持有当前对象
this
val languages = arrayOf("C++","JAVA","Kotlin","C")//apply函数始终返回对象本身,且apply匿名函数在内部持有当前对象thislanguages.apply {println("数组长度=${size}")}.apply {forEach {println(it)}}.apply { println("遍历数组完毕")}
run函数
- 以最后一行作为返回值返回
- 匿名函数内部持有当前对象
this
val len = languages.run {filter {it.contains('C')}.size}println("包含字符C的元素个数=${len}")
with函数
- 以最后一行作为返回值返回
- 匿名函数内部持有当前对象
this
- 不能以拓展函数形式调用,只能将当前对象以形参形式传递
val languages = arrayOf("C++","JAVA","Kotlin","C")val len = with(languages){filter {it.contains('C')}.size}
println("包含字符C的元素个数=${len}")
also函数
- also函数始终返回对象本身
- 匿名函数内部持有
it
val languages = arrayOf("C++","JAVA","Kotlin","C")languages.also {println(it.first())}.also {println(it.last())}.also {println("元素个数=${it.size}")}
takeIf函数
如果takeIf
函数内部为true
则返回对象本身,否则返回null
const val NAME = "Kotlin"
const val AGE = 10
fun main() {val result = JudgeInfo("Kotlin",10)println(result)
}fun JudgeInfo(name:String,age:Int):String{return name.takeIf { name`NAME&&AGE`age } ?: "信息不匹配!"
}
takeUnless函数
takeUnless函数与takeIf函数功能相反,如果takeUnless
内部为true则返回null,否则返回对象本身
集合
List
val languages:List<String> = listOf<String>("C++","C","JAVA","Kotlin","Dart")// public operator fun get(index: Int): E//与C++的运算符重载类似println("第一个元素:${languages[0]}")languages.forEach {println(it)}
列表越界处理
//方法一
val result = languages.getOrElse(5){"数组越界"}
println(result)//方法二
val result1 = languages.getOrNull(1000) ?: "数组越界"
println(result1)
可变List
val languages = mutableListOf("C++","C","JAVA","Kotlin","Dart")
- 删除List中包含字符C的元素
languages.removeIf {it.contains('C')}languages.forEach{println(it)}
- 添加元素
通过运算符重载函数为List添加新元素
public inline operator fun MutableCollection.plusAssign(element: T) {
this.add(element)
}
languages += "C#"languages += "Basic"languages.forEach{println(it)}
- 遍历List
forEach
languages.forEach{println(it)
}
for-in
for(element in languages){println(element)
}
forEachIndexed
languages.forEachIndexed { index, s ->println("第${index+1}元素=$s")}
Set
不允许存在重复元素,如果存在重复元素,会自动忽略
下列输出C++ C JAVA Kotlin Dart
val languages:Set<String> = setOf<String>("C++","C","JAVA","Kotlin","Dart","C++")languages.forEach {print("$it ")}
println()
元素读取
languages.elementAt(0)
防止下标越界而导致程序崩溃
//法一
val result1 = languages.elementAtOrNull(1000) ?: "越界"
//法二
val result2 = languages.elementAtOrElse(1000){"越界"}
可变Set
val languages:MutableSet<String> = mutableSetOf<String("C++","C","JAVA","Kotlin","Dart","C++")languages += "Basic"languages -= "C++"languages.forEach {print("$it ")}
数组
数组定义
val languages = arrayOf<String>("C++","C","JAVA","Kotlin","Dart","C++") //对象数组
val intNumbers = intArrayOf(1,2,3,4,5)
val doubleNumbers = doubleArrayOf(10.1,11.2,12.1)
val charArray = charArrayOf('a','b','c')
读取数组元素
println(languages[0])val result1 = languages.elementAtOrElse(1000){"越界"
}val result2 =languages.elementAtOrNull(1000) ?: "越界"println(result1)
println(result2)
Map
map定义
//法一
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
//法二
val map1:Map<String,Int> = mapOf(Pair("C",1),Pair("C++",2),Pair("Kotlin",3))
读取map元素,如果读取map中没有的元素,则返回null
val value = map["C"]
println(value)
定义默认值
val value = map.getOrDefault("Go",-1)
println(value)
通过匿名函数定义错误读取
val value = map.getOrElse("Go"){"没有对应的值"}println(value)
遍历map
- 法一
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)map.forEach { (_, value) ->print("$value ")
}
- 法二
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)map.forEach {print("${it.value} ")
}
- 法三
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
for (entry in map) {print("${entry.value} ")
}
可变Map
val map:MutableMap<String,Int> = mutableMapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
map += Pair("JAVA",4)
map += "Basic" to 5
map -= "C"map.forEach { (_, value) ->print("$value ")
}
类
在Kotlin中,类的成员属性默认访问权限为public
class Student{var name:String = "Kotlin"//下列get和set默认存在get() = fieldset(value) {field = value}var sex:Char = 'm'get() = field.uppercaseChar()set(value) {field =value.lowercaseChar()}private var age:Int = 0
}
fun main() {val zhangsan = Student()println(zhangsan.name)
}
主构造函数
//主构造函数,下列形参为输入类型,不能直接使用,需要通过接收成为变量才能使用
class Student(name: String, age:Int){fun print(){//此处不能直接调用name// println(name)}
}
通过下列两种方式,主构造函数的形参就可以在类中使用
//法一
class Student(var name: String, var age:Int){fun print(){println(name)}
}//法二
class Student(name: String, age:Int){var name = namevar age = agefun print(){println(name)}
}
次构造函数
次构造函数必须调用主构造函数
class Student(name: String){var name:String = namevar age:Int = 0var score:Double = 0.0//次构造函数必须调用主构造函数constructor(name: String,age:Int):this(name){this.name = namethis.age = age}constructor(name: String,age:Int,score:Double):this(name){this.name = namethis.age = agethis.score = score}
}
fun main() {val lisi = Student("李四")val zhangsan = Student("张三",20)val wangwu = Student("王五",20,50.50)println(zhangsan.score)
}
lateinit 延迟初始化
class Student{lateinit var name:Stringfun initName(name:String){this.name = name}fun showName(){val flag = ::name.isInitialized//判断是否初始化if(flag){println(name)}else{println("未初始化name")}}
}
fun main() {println(Student().showName())
}
lazy 惰性初始化
class Student{//当调用的时候才初始化val name:String by lazy { readName() }private fun readName(): String {println("loading...")println("loading...")println("loading...")return "FranzLiszt"}
}
fun main() {val zhangsan = Student()Thread.sleep(3000)println(zhangsan.name)
}
继承和重载
在Kotlin中,类默认是final修饰,不能被继承;只有通过open修饰才能被继承
//类默认是final修饰,不能被继承;只有通过open修饰才能被继承
open class Person(val name:String){private fun printfName() = println("parent class name:$name")open fun showName() = println(printfName())
}
class Student(val subname:String): Person(subname){private fun printfName() = println("sub class name:$name")override fun showName() = printfName()
}
fun main() {val person:Person = Student("张三")person.showName()
}
companion objec 伴生对象
伴生对象,与Java的Static类似,同样无论调用多少次,伴生对象只会初始化一次
class Student(){//伴生对象,与Java的Static类似companion object{private val name = "student"fun showName() = println(name)}
}fun main() {println(Student.showName())
}
内部类
内部的类不能访问外部类属性,通过添加inner修饰,成为内部类才能访问
class Person(name:String){val name = name//内部的类不能访问外部类属性,通过添加inner修饰,成为内部类才能访问inner class Male{fun show() = println("male $name")}inner class Female{fun show() = println("female $name")}
}fun main() {val p = Person("zs")p.Male().show()
}
嵌套类
嵌套类的内部的类不能访问外部类属性
class Person(name:String){val name = nameclass Male{//不能访问外部类属性//fun show() = println("male $name")}class Female{fun show() = println("嵌套类")}
}fun main() {Person.Female().show()
}
数据类
定义数据类
data class Student(var name:Student,var age:Int)
反编译上面的数据类,可以看见除了成员变量的get()、set()函数外,还拓展了拷贝函数、toString()、equals()函数等;比起JAVA的JavaBean更加丰富;其中上述扩展的函数只会覆盖主构造函数的成员属性,不会覆盖次构造函数的成员属性
public final class Student {@NotNullprivate Student name;private int age;@NotNullpublic final Student getName() {return this.name;}public final void setName(@NotNull Student var1) {Intrinsics.checkNotNullParameter(var1, "<set-?>");this.name = var1;}public final int getAge() {return this.age;}public final void setAge(int var1) {this.age = var1;}public Student(@NotNull Student name, int age) {Intrinsics.checkNotNullParameter(name, "name");super();this.name = name;this.age = age;}@NotNullpublic final Student component1() {return this.name;}public final int component2() {return this.age;}@NotNullpublic final Student copy(@NotNull Student name, int age) {Intrinsics.checkNotNullParameter(name, "name");return new Student(name, age);}// $FF: synthetic methodpublic static Student copy$default(Student var0, Student var1, int var2, int var3, Object var4) {if ((var3 & 1) != 0) {var1 = var0.name;}if ((var3 & 2) != 0) {var2 = var0.age;}return var0.copy(var1, var2);}@NotNullpublic String toString() {return "Student(name=" + this.name + ", age=" + this.age + ")";}public int hashCode() {Student var10000 = this.name;return (var10000 != null ? var10000.hashCode() : 0) * 31 + Integer.hashCode(this.age);}public boolean equals(@Nullable Object var1) {if (this != var1) {if (var1 instanceof Student) {Student var2 = (Student)var1;if (Intrinsics.areEqual(this.name, var2.name) && this.age ` var2.age) {return true;}}return false;} else {return true;}}
}
运算符重载
下列列出一些常用的重载运算符
表达式 | 翻译为 |
---|---|
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.times(b) |
a / b | a.div(b) |
a % b | a.rem(b) |
a[i] | a.get(i) |
a += b | a.plusAssign(b) |
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a++ | a.inc() |
a– | a.dec() |
下面重写了加减乘除四个运算符,可以与C++的运算符重载做对比,差异如下
- C++直接对运算符进行重新标识,而Kotlin需要进行转化,例如重载加号运算符,需要改为
plus
函数
class Calculation(private val num1:Int){//重载加号运算符operator fun plus(param:Calculation):Calculation = Calculation(num1+param.num1)//重载减号运算符operator fun minus(param:Calculation):Calculation = Calculation(num1-param.num1)//重载乘号号运算符operator fun times(param:Calculation):Calculation = Calculation(num1*param.num1)//重载除号运算符operator fun div(param:Calculation):Calculation{if (param.num1 ` 0 )return Calculation(0)return Calculation(num1/param.num1)}fun printfNum() = println("num=$num1")
}
fun main(){val example1 = Calculation(5)val example2 = Calculation(10)val result = example1 + example2result.printfNum()
}
枚举类
data class WeekInfo(var info:String)
enum class Week(private val weekInfo: WeekInfo) {Sunday(WeekInfo("星期天")),Monday(WeekInfo("星期一")),Tuesday(WeekInfo("星期二")),Wednesday(WeekInfo("星期三")),Thursday(WeekInfo("星期四")),Friday(WeekInfo("星期五")),Saturday(WeekInfo("星期六"));fun show() = println("info = ${weekInfo.info}")fun update(weekInfo: WeekInfo){this.weekInfo.info = weekInfo.infoprintln("info = ${weekInfo.info}")}
}
fun main(){Week.Friday.show()Week.Sunday.update(WeekInfo("XINGQITIAN"))
}
代数数据类型
enum class Judge{Bad,Mid_Good,Superior
}
fun testScore(score: Judge): String =when (score) {Judge.Bad -> "不及格"Judge.Mid_Good -> "良好"Judge.Superior -> "优秀"}fun main(){println(testScore(Judge.Superior))
}
密封类
sealed class Scores{object Fail:Scores()object Pass:Scores()object Superior:Scores()
}fun testScore(score: Scores): String =when (score) {is Scores.Fail -> "不及格"is Scores.Pass -> "良好"is Scores.Superior -> "优秀"}
fun main(){println(testScore(Scores.Pass))
}
接口
在Kotlin中,接口实现类不仅要实现其接口的函数,还需要重写其成员变量
interface Information{var name:Stringvar age:Intfun showInfo()
}class Student(stuName:String, stuAge:Int):Information{override var name: String = stuNameoverride var age: Int = stuAgeoverride fun showInfo() {println("name=$name,age=$age")}}
fun main(){val zhangsan:Student = Student("张三",20)zhangsan.showInfo()
}
抽象类
abstract class Base{fun run(){running(getAnimalName())eating(getAnimalName())}abstract fun getAnimalName():Stringabstract fun running(name:String)abstract fun eating(name:String)
}class Cat:Base(){override fun getAnimalName(): String = "Cat"override fun running(name:String) = println("$name running")override fun eating(name:String) = println("$name eating")fun show(){super.run()}}
fun main(){val cat:Cat = Cat()cat.show()
}
泛型类
class BasePrintf<T> (private val obj:T){fun printf() = println("输出结果:$obj")
}data class Student(val name:String,val age:Int)
data class Teacher(val name:String,val age:Int,val id:Int)fun main() {val zhangsan = Student("张三",20)val lisi = Teacher("李四",30,111)BasePrintf(zhangsan).printf()BasePrintf(lisi).printf()BasePrintf(111).printf()BasePrintf("aaa").printf()
}
vararg 动态参数
class Person<T>(private vararg val params:T){//out的作用是T只能被读取,不能修改private val arrays: Array<out T> = paramsfun show(index:Int): T = arrays[index]fun<o> map(index:Int,action:(T)->o) = action(arrays[index])
}fun main() {val param = Person("Kotlin",20,false,99.99)println(param.show(0))println(param.show(1))param.map(3){println(it)}
}
协变&逆变
协变
- 在泛型前加out,代表此泛型只能被读取不能被修改
- 泛型的子类对象可以赋值给泛型的父类对象
interface Producer<out T>{fun produce():T
}
逆变
- 在泛型前加in,代表此泛型只能被修改不能被读取
- 泛型的具体父类可以赋值给泛型声明处的子类
interface Consumer<in T>{fun consumer(param:T)
}
扩展函数
class Student(val name:String,val age:Int)fun Student.printf() = println("name=$name,age=$age")fun main() {val zhangsan = Student("张三",20)zhangsan.printf()
}
单例模式
饿汉式
object Student
懒汉式
class Student{companion object{private var instance:Student ? = nullget() {if (field ` null) field = Student()return field}fun getInstanceAction():Student = instance!!}
}
懒汉式-加锁
class Student{companion object{private var instance:Student ? = nullget() {if (field ` null) field = Student()return field}@Synchronizedfun getInstanceAction():Student = instance!!}
}
懒汉式-双重校验
class Student private constructor(){companion object{val instance:Student by lazy (mode = LazyThreadSafetyMode.SYNCHRONIZED){Student()}}
}