Kotlin基础语法

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,此处我声明为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 == 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 = listOf("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 = setOf("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 = mutableSetOf

数组

数组定义

val languages = arrayOf("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 = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3) 
//法二
val map1:Map = 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 = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
 map.forEach { (_, value) ->
        print("$value  ")
}
  • 法二
 val map:Map = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
 map.forEach {
    print("${it.value}  ")
}
  • 法三
val map:Map = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3) 
for (entry in map) {
    print("${entry.value}  ")
}
可变Map
val map:MutableMap = 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() = 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 + 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 + 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 (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(private vararg val params:T){
    //out的作用是T只能被读取,不能修改
    private val arrays: Array = params

    fun show(index:Int): T = arrays[index]

    fun 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{
    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()}
    }
}

你可能感兴趣的:(kotlin,kotlin,开发语言,android)