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 = 5
val info = when(week){
1-> "星期一"
2-> "星期二"
3-> "星期三"
4-> "星期四"
5-> "星期五"
6-> "星期六"
7-> "星期天"
else-> "错误类型"
}
println(info)
range表达式
val score = 70
when (score) {
in 0..59 -> {
println("不及格")
}
in 60 ..79 -> {
println("及格")
}
in 80 .. 89 -> {
println("良好")
}
else -> {
println("优秀")
}
}
字符串模版
val name = "Kotlin"
val age = 7
val score = 32
val detail = "I am $name and $age,I got ${score+10} in the last test."
println(detail)
函数
函数定义
在Kotlin中函数默认访问类型为Public,此处我声明为privatefun为声明函数关键字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 == AGE
if (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 == AGE
if (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 ==AGE
result
}
}
可空性
在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匿名函数在内部持有当前对象this
languages.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
// 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
languages.forEach {
print("$it ")
}
println()
元素读取
languages.elementAt(0)
防止下标越界而导致程序崩溃
//法一
val result1 = languages.elementAtOrNull(1000) ?: "越界"
//法二
val result2 = languages.elementAtOrElse(1000){
"越界"
}
可变Set
val languages:MutableSet languages += "Basic" languages -= "C++" languages.forEach { print("$it ") } 数组 数组定义 val languages = arrayOf 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 //法二 val map1:Map 读取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 map.forEach { (_, value) -> print("$value ") } 法二 val map:Map map.forEach { print("${it.value} ") } 法三 val map:Map for (entry in map) { print("${entry.value} ") } 可变Map val map:MutableMap 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() = field set(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 = name var age = age fun print(){ println(name) } } 次构造函数 次构造函数必须调用主构造函数 class Student(name: String){ var name:String = name var age:Int = 0 var score:Double = 0.0 //次构造函数必须调用主构造函数 constructor(name: String,age:Int):this(name){ this.name = name this.age = age } constructor(name: String,age:Int,score:Double):this(name){ this.name = name this.age = age this.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:String fun 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 = name class 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 { @NotNull private Student name; private int age; @NotNull public final Student getName() { return this.name; } public final void setName(@NotNull Student var1) { Intrinsics.checkNotNullParameter(var1, " 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; } @NotNull public final Student component1() { return this.name; } public final int component2() { return this.age; } @NotNull public final Student copy(@NotNull Student name, int age) { Intrinsics.checkNotNullParameter(name, "name"); return new Student(name, age); } // $FF: synthetic method public 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); } @NotNull public 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 + ba.plus(b)a - ba.minus(b)a * ba.times(b)a / ba.div(b)a % ba.rem(b)a[i]a.get(i)a += ba.plusAssign(b)a > ba.compareTo(b) > 0a < ba.compareTo(b) < 0a++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 + example2 result.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.info println("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:String var age:Int fun showInfo() } class Student(stuName:String, stuAge:Int):Information{ override var name: String = stuName override var age: Int = stuAge override 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():String abstract 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 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 //out的作用是T只能被读取,不能修改 private val arrays: Array fun show(index:Int): T = arrays[index] fun } 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 fun produce():T } 逆变 在泛型前加in,代表此泛型只能被修改不能被读取泛型的具体父类可以赋值给泛型声明处的子类 interface Consumer 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 ? = null get() { if (field ` null) field = Student() return field } fun getInstanceAction():Student = instance!! } } 懒汉式-加锁 class Student{ companion object{ private var instance:Student ? = null get() { if (field ` null) field = Student() return field } @Synchronized fun getInstanceAction():Student = instance!! } } 懒汉式-双重校验 class Student private constructor(){ companion object{ val instance:Student by lazy (mode = LazyThreadSafetyMode.SYNCHRONIZED){Student()} } } 精彩文章
发表评论