Kotlin零基础入门到精通(精选)

  • 一. Kotlin课程概述
    • 1.1 课程安排:
    • 1.2 什么是Kotlin?
    • 1.3 Kotlin的发展历程
    • 1.4 学习目标
    • 1.5 必备知识
    • 1.6 参考资料
    • 1.7 Hello,world
  • 二. 数据类型
    • 2.1 本章目标
    • 2.2 Boolean类型
    • 2.3 Number类型
    • 2.4 Char类型
    • 2.5 类与对象
    • 2.6 空类型和智能类型转换
    • 2.7 包
    • 2.8 区间
    • 2.9 数组
  • 三. 程序结构
    • 3.1 常量与变量
    • 3.2 函数
    • 3.3 Lambda表达式
    • 3.4 类成员
    • 3.5 运算符
    • 3.6 表达式
    • 3.7 循环
    • 3.8 捕获异常
    • 3.9 各种类型参数
    • 3.10 导出为可执行程序
  • 四. 面向对象
    • 4.1 面向对象-抽象类与接口
    • 4.2 继承
    • 4.3 可见性
    • 4.4 Object类
    • 4.5 伴生对象与静态成员
    • 4.5 方法重载与默认
    • 4.6 扩展成员
    • 4.7 属性代理
    • 4.8 数据类
    • 4.9 内部类与匿名内部类
    • 4.10 枚举
    • 4.11 密封类
  • 五. 高阶函数
    • 5.1 高阶函数的基本概念
    • 5.2 常用高阶函数
    • 5.3 尾递归优化
    • 5.4 闭包
    • 5.5 中缀表达式
    • 5.6 Currying 科理化
    • 5.7 偏函数
    • 5.8 小案例: 统计字符串个数
  • 六. 领域特定语言: DSL
    • 6.1 DSL的特点
    • 6.2 HTML DSL
    • 6.3 Gradle Kotlin脚本编写
  • 七、协程
    • 7.1 协程的基本概念
    • 7.2 了解协程
    • 7.3 kotlin.coroutine框架介绍
  • 八. Kotlin与Java混合开发
    • 8.1 基本互操作
    • 8.2 SAM转换
    • 8.3 正则表达式
    • 8.4 集合框架
    • 8.5 IO操作
    • 8.6 拆箱与装箱
    • 8.7 注解处理器
  • 九. Kotlin的未来与展望
    • 9.1 Kotlin的应用场景
    • 9.2 Kotlin-Script脚本编写
    • 9.3 创建SpringBoot项目
    • 9.4 Kotlin-Natie项目开发
    • 9.5 结束

一. Kotlin课程概述

1.1 课程安排:

  1. 课程介绍、Kotlin介绍、开发环境搭建
  2. 基本语法:基本类型、空安全类型、智能转换、类与对象同步、数组与区间
  3. 程序结构:常量与变量、函数、Lambda、类成员、条件表达式、循环语句、运算符、异常捕获
  4. 面向对象:抽象类和接口、Object、伴生对象、扩展方法、属性代理、数据类、内部类、枚举与密封类
  5. 高阶函数:基本概念、常见高阶函数、尾递归优化、闭包、函数复合、科里化、偏函数
  6. DSL:基本概念、案例开发、Gradle脚本
  7. 协程:基本概念、协程的使用、封装协程库、协程原理分析;
  8. 与Java混编:基本互操作、正则表达式、集合框架、IO操作、装箱与拆箱、NoArg插件、AllOpen插件、注解处理器
  9. 应用与展望:前景与展望、编写脚本、服务端、前端、Android、Native

1.2 什么是Kotlin?

  • Kotlin就是一门可以运行在Java虚拟机、Android、浏览器上的静态语言,它与Java 100%兼容,如果你对Java非常熟悉,那么你就会发现Kotlin除了自己的标准库之外,大多仍然使用经典的Java集合框架;
  • 总结来说:
    1. Android官方开发语言
    2. 100%兼容Java
    3. Kotlin-Js 前端开发
    4. Kotlin-Jvm 服务端开发
    5. Kotlin-Native 本地执行程序

    Kotlin 是一门全栈语言

1.3 Kotlin的发展历程

  • 2010年立项
  • 2011.6对外公开
  • 2012.2开源
  • 2013.8 支持 Android Studio
  • 2014.6全新的开源web站点和域名 Kotlinlang.org
  • 2016.2 发布1.0
  • 2016.9 发布1.0.4, 支持apt

1.4 学习目标

  • 学会使用Kotlin
  • 熟悉Java生态
  • 了解一些特性的背后实现

1.5 必备知识

  • 熟悉计算机基础、操作系统相关的知识
  • 了解Java及其生态
  • 了解Java工程组织的常用工具
  • 熟悉IntelliJ Idea

1.6 参考资料

  • 官方文档:https://kotlinlang.org/docs/reference
  • Kotlin源码:https://github.com/JetBrains/kotlin
  • Kotlin官博:https://blog.jetbrains.com/kotlin/
  • Kotlin微信公众号:Kotlin

1.7 Hello,world

  1. 安装Kotlin插件,如图所示:

    安装后要重启一次才能生效;

  2. 创建一个Kotlin工程,如图所示:

    3. 根据实际,填写项目的groupId,ArtifactId,以及Version,如图所示:

  3. 一路默认下去即可,然后成功创建项目,然后在此项目中创建Kotlin包,如图所示:

  4. 紧接着创建包net.println.kotlin(根据实际来,此处可不一致),然后创建HelloWorld.kt,如图所示:

  5. 编写Hello,world代码如下:

    fun main(args:Array<String>){println("Hello World")
    }
    
  6. 执行,如图所示:

    执行成功后,控制台会打印Hello,world字样,说明运行成功,如图所示:

  7. 点击println进去,可以看到源码,其打印操作是调用的Java的System.out.println,如图所示:

二. 数据类型

2.1 本章目标

  • 认识基本类型
  • 初步认识类及其相关概念
  • 认识区间和数组

简单来说就是看懂如图例子:

2.2 Boolean类型

  • Boolean 值 只有true或者false两个值,它无处不在,相当于Java类型的boolean
  • 示例代码:
    val aBoolean : Boolean = true
    val anotherBoolean : Boolean = false
    

    > var是可变变量(可读可写),val是可读变量(只能读);同时 : 后面的Boolean 是指它的类型,前面的aBoolean或anotherBoolean是它的变量名称,=号后面的true或false是它的值;

2.3 Number类型

  • 数字类型如下:

  • int,Long类型的最大值和最小值

    // 2147483647
    val maxInt: Int= Int.MAX_VALUE
    // -2147483648
    val mintInt: Int=Int.MIN_VALUE
    val maxLong : Long=Long.MAX_VALUE
    val minLong: Long=Long.MIN_VALUE
    val aFolat: Float=20F
    val maxFolat: Float=Float.MAX_VALUE
    val minFolat: Float=- Float.MAX_VALUE
    val maxShort : Short=Short.MAX_VALUE
    val minShort : Short=Short.MIN_VALUE
    val maxByte: Byte= Byte.MAX_VALUE
    val minByte : Byte= Byte.MIN_VALUE
    

    val后面的为变量名,可替换为实际名称;Long类型的长整形后面可以加个L; Float类型后面必须加F,f;Float是浮点类型,有精度问题,计算钱相关的不要用这个;

  • 装箱和拆箱

    • 在Kotlin中不区分装箱和拆箱;

2.4 Char类型

  • 特点:

    • 字符对应Java的Character
    • 占两个字节,表示一个16位的Unicode字符
    • 字符用单引号’‘引起来,例如: ‘a’,‘0’,’\n’
  • Char类型转义字符如图:

  • 不可隐式转换

    • 在java中,一个int类型与Long相加,原本的Int类型会自动隐式转换为Long类型,这在Kotlin中是不允许的;
  • 比较相等

    • ==表示equals 值得相等比较
    • === 三个等号表示引用地址的比较,即比较两个值是否是同一个引用地址;
  • 字符串模板

    • 代码如图:

      val arg1: Int =0
      val arg2: Int =1
      // java款式的加法
      println(""+arg1+"+"arg2+"="+(arg1+arg2))
      // kotlin款式的加法
      println("$arg1+ $arg2=${arg1+arg2}")
      // 如果要打印美元 $这个符号,则再加一个$
      val salary: Int = 1000
      println("$"+"$salary")
      // 或者使用转义符号
      println("\$salary")
      // 三个引号,转义会失效,支持换行
      val txt:String ="""
      hello
      ,
      world
      """
      // 打印它的字符数量
      println(rawString.length)
      

2.5 类与对象

  • 什么是类?

    • 类,一个抽象的概念
    • 具有某些特征的事物的概括
    • 不特定指代任何一个具体的事物
    • 举例:
      • 人、车、书
    • 写法:
      class<类名>{<成员>}
      
  • 什么是对象?

    • 是一个具体的概念,与类相对
    • 描述某一种类的具体个体
    • 举例:
      • 某些人、领导的车、你手里的那本书
  • 类和对象的关系?

    • 一个类通常可以有很多个具体的对象
    • 一个对象本质上只能从属于一个类
    • 某一个人,他是工程师,但本质上还是属于人这一类
  • 对象也经常被称作“类的对象”或者“类的实例”

    • 比如 类: 城市 --> 上海、深圳(对象)
  • 类的继承

    • 提取多个类的共性得到一个更抽象的类,即父类;
    • 子类拥有父类的一切特征
    • 子类也可以自定义自己的特征
    • 所有类都最终继承自Any
  • 类与对象的实例图示:

  • 如果在类中加了init字段,则在创建过程中会自动执行其中的方法,如图所示:

  • 当构造只有一个的时候可以进行省略,如果有多个则不可以,如图所示:

  • 子类继承了父类中的一些方法,如图所示:

  • Any是一切类的父类,它拥有equals,hashCode,toString方法,则说明在Kotlin中的其他所有类,都拥有这些方法,如图所示:

2.6 空类型和智能类型转换

  • 任意类型都有可空和不可空两种

    • val notNull:String = null // 错误,不能为空。 如果为空会抛出异常
    • val nullable:String ?= null // 正确,可以为空。 如果为空,则被赋值的nullable的值为null
    • notNull.length // 正确,不为空的值可以直接使用
    • nullable.length // 错误,可能为空,不能直接获取长度
    • nullable!!.length // 正确,强制认定nullable不可空(如果在这段代码前进行了if判断,比如不为空的时候才执行的这段代码,就没有问题。我们已经认定了这个nullable变量不为空)
    • nullable?.length // 正确,若nullable为空,返回空
  • Java Style类型转换
    • val sub: SubClass = parent as SubClass
    • 类似于Java 的类型汉族那换,失败则抛出异常;

    这里的含义是,判断parent变量为SubClass的子类,若为其子类,则sub是SubClass类型,如不为则直接抛出异常;

- 安全类型转换
val sub: SubClass? = parent as? SubClass
- 如果转换失败,返回null,不抛异常
> 如果parent不是SubClass的子类,则类型转换失败,sub不能编程SubClass类型,则sub的值为null;

2.7 包

  • 概述:

    • 包就是命名空间
    • 包的声明必须在非注释代码的第一行
    • 类的全名:
      • net.println.kotlin,chapter2.HelloWorld
  • 包即类的全名,import字段进行导入,import同时可以对此包进行命名,可以以另外一个名称进行替代和调用。如图所示:
    package net.println.koltin.DemoTest
    import net.println.kotlin.HelloWord as Hellofun main(args:Array<String>){val sayHello:Hello=Hello();
    }
    

    这里导入的Hello,就是HelloWorld类。通过创建Hello,就相当于创建了一个HelloWord,所以sayHello看似是对Hello实例化,实际上是对HelloWorld进行了实例化;

2.8 区间

  • 概述:

    • 一个数学上的概念,表示范围
    • ClosedRange的子类,IntRange最常用
  • 基本写法:
    • 0…100表示[0,100]
    • 0 until 100 表示 [0,100)
    • i in 0…100判断 i 是否在区间 [0,100]中
    • 示例代码:
      // 前后都闭区间  [0,1024]
      val range:IntRange=0..1024
      // 前闭后开的区间  [0,1024) = [0,1023]
      val range_exclusive:IntRange= 0 until 1024
      val empty_Range:IntRange=0..-1fun main(args:Array<String>){// true   是为空,因为此范围中没有值println(emptyRange.isEmpty())// true 此范围中包含了50println(range.contains(50))// true 检查50是否在range的范围中println(50 in range)
      }// 下面打印出来的结果为: 0,1,2,3,4,5,6,7,8,9,10...
      for(i in range_exclusive){println("$i,")
      }
      

      用i in IntRange可以作范围判断,以及辅助遍历等操作

2.9 数组

  • 数组是什么?

    • 对应英文单词Array:

      • An impressive display or range of a particular type of thing or an ordered arrangement,in particular
    • 跟数一点关系没有
    • 就是一系列对象,这个对象可以是各类型的数字,字符,字符串,或者自定义对象等;
  • 基本写法

    • val array:Array arrayOf(…)
  • 基本操作:

    • println array[i] 输出第i个成员
    • array[i] 指定数组的第i个成员值;我们可以通过此进行赋值或者获取值
    • array.length 数组的长度
  • 为了避免不必要的装箱和拆箱,基本类型的数组是定制的,如图所示:

  • 数组示例代码:

    • 创建对象,如图所示:
    • 创建示例代码如下:
      // 创建一个int数组
      val arrayOfint: IntArray = intArrayOf(1,3,5,7)
      // 创建一个Char数组
      val arrayOfChar: CharArray = charArrayOf("H","e","l","o","W","o","r","l","d")
      // 创建一个自定义对象数组,根据上面创建的类
      val arrayOf书记: Array<市委书记> = arrayOf(市委书记("张"),市委书记("赵"),市委书记("黄"))fun main(args: Array<String>){// 打印 int数组println(arrayOfInt.size)for(int in arrayOfInt){println(int)}
      }println(arrayOf书记[1])
      // 这里将方书记赋值给了数组的1 索引处。此处1索引原来的对象会变成新替换的对象,所以重新打印1索引处的书记会变成新的方书记;
      arrayOf书记[1] = 市委书记("方")
      println(arrayOf书记[1])// 这里的joinToString("")表示每个字符之间不用什么连接。 传入制定参数就以指定值进行连接。如果不传,默认以,号连接,比如: H,e,l,l,o...    此处代码打印结果为: HelloWorld
      println(arrayOfChar.joinToString(""))

三. 程序结构

3.1 常量与变量

  • 什么是常量?

    • val= value, 值类型
    • 类似Java 的final
    • 不可能重复复制;
    • 举例:
      • 运行时常量: val x=getX()
      • 编译期常量(Java中的静态常量 final): const val x=2
  • 什么是变量:

    • var = variable
    • 举例:
      • var x =“HelloWorld” //定义变量
      • x= “HiWorld” // 再次赋值
  • 类型推导- 编译器可以推导量的类型

    • val String =“Hello” // 推导出String类型
    • val int =5 // Int类型
    • var x =getString() + 5 // String类型
  • var是可变量,val 是不可变,它是常量;

  • val虽然是不可变,但是它不是静态的,如果需要在编译期时就加在,可以在前面加一个const字段;

3.2 函数

  • 什么是函数?

    • 以特定功能组织起来的代码块

      • fun函数名:[返回值类型]{[函数体]}
      • fun函数名=[表达式]
    • 举例:
      • fun sayHi(name:String){println(“Hi,$name”)}
        // 简写的方式:
      • fun sayHi(name:String)=println(“Hi,$name”)
  • 任何函数都是以fun 开头,然后后面为它的名字,括号内为它的参数若有范围值,在后面用:Any ,Any代表返回值类型;
  • 比如我们的Main函数:
    fun main(args: Array<String>){println("Hello,world")// 打印args数组的索引为1 的值println(${args[0]})if (args.size !=2){}
    }
    

    如果没有传参,会报数组索引异常。这里main函数没有为args赋值;如果启动时,传入了参数就可以打印了;同时如果有返回值,则需要在main(…)这个括号后面加 :返回值类型来定义返回值类型;

  • 代码示例:
    fun main(args: Array<String>){checkArgs(args)val arg1=args[0].toInt()val arg2=args[1].toInt()println("$arg1+$arg2=${sum(arg1,arg2)}")
    }fun checkArgs(args: Array<String>){if(args.size != 2){println("请传入两个整形参数,例如 1, 2")System.exit(-1)}
    }fun sum(arg1: Int ,arg2:Int):Int{return arg1+arg2
    }
    

3.3 Lambda表达式

  • 什么是lambda表达式?

    • 匿名函数
    • 写法:
      {[参数列表]->[函数体,最后一行是返回值]}
      
    • 举例:
      val sum ={a:Int,b:Int-> a+b}
      
  • Lambda的类型表示举例:

    // 无参,返回值为Unit
    ()->Unit
    // 传入整型,返回一个整型
    (Int)->Int
    // 传入字符串、Lambda表达式,返回Boolean
    (String,(String)->String)->Boolean
    
  • Lambda表达式的调用

    • 用()进行调用
    • 等价于invoke()
    • 举例:
      val sum ={a:Int,b:Int->a+b}
      sum(2,3)
      sum.invoke(2,3)
      
  • Lambda表达式的简化

    • 函数参数调用时最后一个Lambda可以移出去
    • 函数参数只有一个Lambda,调用时小括号可省略
    • Lambda只有一个参数可默认为it
    • 入参,返回值与形参一致的函数可以用函数引用的方式作为实参传入;
  • 使用for 我们用foreach也可以进行遍历;

3.4 类成员

  • 什么是类成员?

    • 属性:或者说成员变量,类范围内的变量
    • 方法:或者说成员函数,类范围内的函数
  • 函数和方法的区别?

    • 函数强调功能本身,不考虑从属
    • 方法的称呼通常是从类的角度出发
    • 叫法不同而已,不要纠结;
  • 函数如何定义方法?

    • 写法与普通函数一致,函数如果写在类中,它就是方法
    • 举例:
      class Hello{fun sayHello(name:String)=println("Hello,$name")
      }
      
  • 定义属性

    • 构造方法参数中val/var的都是属性
    • 类内部也可以定义属性
    • 举例:
      class Hello(val aField:Int,notAField:Int){val anotherFIeld:Float=3f
      }
      
  • 属性的访问规则:

    • 属性可以定义getter/setter
    • 举例如下:
      val a:Int=0
      get()=field
      var b:Float=0f
      set(value){field=value}
      

      get(){return field} 其中field指代了此变量

  • 属性初始化

    • 属性的初始化尽量在构造方法中完成
    • 无法在构造方法中初始化,尝试降级为局部变量
    • val用lateinit延迟初始化,val用lazy
    • 可空类型谨慎用null直接初始化;
    • 举例:
      class X
      class A{
      // 使用lateinit延迟初始化,不需要立即给值
      lateinit var c: String
      val e: X by lazy{X()            }
      }
      

3.5 运算符

  • 任何类可以定义或者重载父类的基本运算符
  • 通过运算符对应的具名函数来定义
  • 对参数个数作要求,对参数和返回值类型不作要求
  • 不能像Scala一样定义任意运算符

3.6 表达式

  • 中缀表达式

    • 只有一个参数,且用infix修饰的函数
    • 举例:
      class Book{infix fun on(place: String){...}
      }
      if(Book() on "My Desk"){...}
  • if 表达式

    • 举例:

      if(a==b)...
      else...
      

      在if表达式中,我们既可以用来做条件判断,也可以类似java三元运算符一样直接用来当一个值进行使用。比如

      val b=2
      // 当b等于2时,则a等于3  否则等于5
      val a= if(b==2) 3 else 5
      
    • 表达式完备性:
      • 当我们用于类似三元运算符的操作时,必须要有else
  • When 表达式

    • 加强版Switch,支持任意类型
    • 支持纯表达式条件分支(类似if)
    • 表达式与完备性
    • 举例:
      fun main(args: Array<String>){val x=5when(x){is Int-> 逻辑代码...in 1..100-> 逻辑代码...!in 1..100-> 逻辑代码...args[0].toInt()-> 逻辑代码...}
      }
      

      这里的when处传入值,下面任意满足条件且按先后只执行第一个符合条件的代码逻辑;

    • 同时还有when不带括号的方式:
        var str="今天是周末;"val biaodian = when {str.contains(";") -> {";"}str.contains(";") -> {";"}str.contains(",") -> {","}else -> {","}
      

      含义可以参考此java代码:

      var str="今天是周末;"
      val biaodian = if (str.contains(";")){";"}else if (str.contains(";")){";"}else if (str.contains(",")){","}else{","}
      

3.7 循环

  • for循环

    • 基本写法

      for(element in elements)...
      
    • 代码示例:
      fun main(args: Array<String>){// 遍历一for(arg in args){println(arg)}// 遍历二for((index,value) in args.withIndex()){println("$index-> $value")}// 遍历三for(indexedValue in args.withIndex()){println("${indexedValue.index} -> ${indexedValue.value}")}
      }
      
    • 给任意类实现Iterator方法

      可网上找

  • While循环

    • 古董级语法
    • do … while(…)…
    • while(…)…
    • 代码示例:
      fun main(args:Array<String>){var x=5while(x>0){println(x)x--}do {println(x)x--}while(x>0)
      }
      
  • 跳过和终止循环

    • 跳过当前循环用continue
    • 终止循环用break
    • 多层循环嵌套的终止结合标签使用

3.8 捕获异常

  • catch 分支匹配异常类型
  • 表达式,可以用来赋值
  • finally: 无论代码是否抛出异常都会执行
  • 注意下面的写法:
    return try(x/y)catch(e:Exception){0}finally{...}
    

    异常的捕获及处理与java类似,不过其可以作为值进行使用;

3.9 各种类型参数

  • 具名参数

    • 给函数的实参附上形参
    • 举例:
      fun sum(arg1:Int, arg2:Int)= arg1+arg2
      sum (arg1=2 ,arg2=3)
      
  • 变长参数

    • 某个参数可以接收多个值
    • 可以不为最后一个参数
    • 如果传参时有歧义,需要使用具名参数
  • Spread Operator

    • 只支持展开Array
    • 只用于变长参数列表的实参
    • 不能重载
  • 默认参数:

    • 为函数参数指定默认值
    • 可以为任意位置的参数指定默认值
    • 传参时,如果有歧义,需要使用具名参数
  • 代码示例:

    fun main(vararg args: String){var array= intArrayOf(1,3,4,5)// string="Hello" 是一个默认参数// *array表示将array数组展开,将一个个元素传入,如: hello(3.0,1,3,4,5,string="Hello")hello(3.0,*array,string="Hello")
    }fun hello(double:Double, vararg ints:Int, string:String){ints.forEach(::println)println(string)
    }
    

3.10 导出为可执行程序

  • 在可执行的类上加上如下字段:
apply plugin:'application'
mainClassName="net.println.kotlin.chapter3.CalcKt"

然后gradle会下载一些相关插件,完成后会在Gradle的窗口中,在Tasks-> distribution-> InstallDist 中执行InstallDist. 如图所示:

  • 会各生成一个windows和Linux下的脚本,如图所示:

四. 面向对象

4.1 面向对象-抽象类与接口

  • 面向对象的基本概念

    • 本质上就是解决如何用程序描述世界的问题
    • 讨论如何把实际存在的东西映射成程序的类和对象
    • 一种程序设计的思路、思想、方法
  • 类实例:

    // 定义一个类
    class Demo{// 定义一个可读变量val i=4// 定义一个方法fun out(i: int){println(i)}
    }// 定义一个接口
    interface chouxianglei{// 定义一个接口方法fun hello()
    }
    
  • 继承一个接口的时候,使用类名(),实现一个接口的时候,使用类名即可,在Kotlin 中是单继承,多实现;如图所示:

  • 什么是接口?

    • 接口,直观理解就是一种约定。 Kotlin的接口与Object-C的Protocol比较类似
    • 举例,输入设备接口:
      interface InputDevice{fun input(event: Any)
      }
      
  • 接口与抽象类的区别:

    • 接口:

      • 不能有状态
      • 必须由类对其进行实现后使用
    • 抽象类:
      • 实现了一部分协议的半成品
      • 可以有状态,可以有方法实现
      • 必须由子类继承后使用
    • 共性:
      • 比较抽象,不能直接实例化
      • 有需要子类(实现类)实现的方法
      • 父类(接口)变量可以接受子类(实现类)的实例赋值

4.2 继承

  • 继承(实现)语法要点

    • 父类需要open才可以被继承
    • 父类方法、属性需要open才可以被覆写
    • 接口、接口方法、抽象类默认为open
    • 覆写父类(接口)成员需要override关键字
  • Class D: A(),B,C

    • 注意继承类时实际上调用了父类的构造方法
    • 类只能单继承,接口可以多实现
  • class Manager(driver: Driver): Driver by driver

    • 接口方法实现交给代理类实现
  • 接口方法冲突

    • 接口方法可以有默认实现
    • 签名一致且返回值相同的冲突
    • 子类(实现类)必须覆写冲突方法

4.3 可见性

  • 可见性Java与Kotlin对比,如图所示:

4.4 Object类

  • 特点:

    • 只有一个实例的类
    • 不能自定义构造方法
    • 可以实现接口、继承父类
    • 本质上就是单例模式最基本的实现

使用object类可以创建一个最简单的单例类

4.5 伴生对象与静态成员

- 伴生对象的特点:
- 每个类可以对应一个伴生对象
- 伴生对象的成员全局独一份
- 伴生对象的成员类似Java的静态成员
> 伴生对象就相当于静态变量和静态方法的整体;

- 使用伴生对象需要注意的地方:
- 静态成员考虑用包级函数、变量替代
- @JvmField 和 @JvmStatic的使用

  • 示例代码:

    class Latitude private constructor(val value: Double){companion object{@JvmStaticfun ofDouble(double:Double):Latitude{return Latitude(double)}fun ofLatitude(latitude: Latitude): Latitude{return Latitude(latitude.value)}@JvmFieldval TAG: String="Latitude"}
    }
    

    这里@JvmStatic和@JvmField不加此注解,在companion object代码块中均可作为静态方法或静态属性,但是如果不加不能被java代码所识别。如果涉及到java代码调用此静态方法或静态属性,则需要加@JvmStatic或@JvmField注解;它们分别修饰方法和属性;

4.5 方法重载与默认

  • 方法重载的特点:

    • Overloads
    • 名称相同、参数不同的方法
    • Jvm函数签名的概念: 函数名、参数列表
    • 跟返回值没有关系
  • 默认参数的特点:

    • 为函数参数设定一个默认值
    • 可以为任意位置的参数设置默认值
    • 函数调用产生混淆时用具名参数
  • 重载与默认:

    • 二者的相关性以及@JvmOverloads
    • 避免定义关系不大的重载
    • 代码示例如图:

方法重载能够用默认参数来解决,所以能不使用就尽量不使用。@JvmOverloads能用于被java代码所识别,如果只在Kotlin中使用可以不用加这个注解;

4.6 扩展成员

  • 在Java中,一些java库的一些方法不够全面,往往我们会自己定义一些Utils,在Kotlin中,我们可以对一些现有的类进行扩展;
  • 特点:
    • 为现有成员添加方法、属性:

      // 添加方法:
      fun X.y():Z{...}
      // 添加属性
      val X.m 注意扩展属性不能初始化,类似接口属性
      
    • Java调用扩展成员类似调用静态方法
    • 代码如图所示:

4.7 属性代理

  • 如图所示,此懒加载就是一个代理:

  • 特点:

    • 定义方法:

      val/var <property name>: <Type> by <expression>
      
    • 代理者需要实现相应的setValue/getValue方法

    实际上就是说,当我们使用了 val/var xxx by yyy()的属性代理时,其代码执行逻辑主要看yyy()了。如果是var方法我们需要实现setValue和getValue,如果是val则只需要实现getValue方法即可,因为val是可读常量;

  • 代码示例:

    其中定义了存值和赋值的get,setValue方法;当我们创建时则会自动执行setValue,当取值时则会调用getValue;

4.8 数据类

  • 特点:

    • 再见,JavaBean
    • 默认实现的copy、toString等方法
    • componentN方法
    • allOpen和noArg插件
  • 代码示例:

  • 同时,我们可以直接在类中直接定义构造参数值,如图所示:

  • 此时不需要传入构造参数,便可将构造参数值外传并执行其他操作,如打印,如图所示:

  • 数据类有一个问题,就是它没有空的默认的构造方法。编译生成的类是一个final的且无空构造方法,所以不是JavaBean,在有些时候使用是有问题的。我们可以通过noarg和allopen插件解决:

    1. 引入依赖:

      ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200611225801792.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MTI4MDQ5,size_16,color_FFFFFF,t_70)
      
    2. 定义并应用插件:
    3. 对指定的数据类使用@PoKo注解,如图所示:

4.9 内部类与匿名内部类

  • 特点:

    • 定义在类内部的类
    • 与类成员有相似的访问机制
    • 默认是静态内部类,非静态用inner关键字
    • this@Outter,this@Inner的用法
  • 匿名内部类:

    • 没有定义名字的内部类
    • 类名编译时生成,类似Outter$1.class
    • 可继承父类、实现多个接口,与Java注意区别
  • 定义一个内部类(非静态):

    非静态内部类,需要在 类的class 前面加inner关键字

  • 定义一个内部类(静态):

    静态内部类。默认内部类为静态内部类;调用时,外部类.内部类()即可;静态内部类无法获取非静态的外部类的属性和方法,因为它是先被编译加载的;而非静态内部类可以持有外部类的非静态属性和方法;

  • 当调用外部类的属性时,我们可以直接调用,也可以用this.@外部类名.属性或方法来执行,如图所示:

  • 匿名内部类实现方法示例:

4.10 枚举

  • 特点:

    • 实例可数的类,注意枚举也是类
    • 可以修改构造,添加成员
    • 可以提升代码的表现力,也有一定的性能开销
    • 枚举的属性和方法之间必须要用 ; 号隔开,这里可能是Kotlin中唯一强制要求使用 ; 号的地方
  • 定义一个枚举类,如图所示:

    $name 是它的名称 $ordinal 是它括号里的值

  • 调用示例:

    // 打印指定的枚举类  1,DEBUG
    println(LogLevel.DEBUG.getTag())
    // 打印指定枚举类的序号 1
    println(LogLevel.DEBUG.ordinal)
    // 打印指定枚举类的实例  ERROR,4
    println(ERROR,4)

4.11 密封类

  • 特点:

    • 子类可数:

      1. Kotlin版本小于1.1时,子类必须定义为密封类的内部类
      2. 在1.1之后,子类只需要与密封类在同一个文件中
    • 仔细体会与枚举的不同
  • 密封类代码示例:

    使用枚举适用于没有参数的情况下,而使用密封类可以用在多参数的情况下,每个类的参数都不尽然相同,同时又想保护此类,不让其他fun方法返回此类,就可以使用密封类;

  • 密封类在class前面加 sealed关键字

五. 高阶函数

5.1 高阶函数的基本概念

  • 高阶函数就是把函数作为参数或者返回值的函数
  • 传入或者返回函数的函数
  • 函数引用 ::prinltn
    > 其他都以此延伸,调用与此类似
    -带有Receiver的引用 pdfPrinter::println
  • 示例:

第一种方式 ::println 说明任何对象(Any)都可以调用此方法,所以才能这样写;

5.2 常用高阶函数

  • map: 一对一映射处理

  • flatMap: 最细化分离

    • 第一个是可以跟map一样进行一一映射
    • 第二是可以把集合中的集合进行打散;
  • joinToString(",") 字符串连接

  • taskWhile 符合条件立即结束,返回符合条件之前被校验的数据

  • .let 调用者不为空时,则执行后面的逻辑;

  • 常见高阶函数

    • map/flatMap
    • fold/reduce
    • filter/takeWhile
    • let/apply/with/use

具体可百度详细学习

5.3 尾递归优化

  • 函数在调用自己之后没有任何操作,这就是尾递归;
  • 使用tailrec可以检查是否是尾递归函数;
  • 它是递归的一种特殊形式
  • 调用自身后无其他操作
  • tailrec关键字提示编译器尾递归优化
  • 尾递归与迭代的关系;

5.4 闭包

  • 概念:

    • 函数运行的环境
    • 持有函数的运行状态
    • 函数内部可以定义函数
    • 函数内部也可以定义类
  • 代码示例:
    • 定义类的闭包函数:

      fun main(args: Array<String>){val add5=add(5)println(add5(2))
      }fun add(x: Int):(Int)->Int{data class Person(val name:String,val age:Int)return fun(y:Int):Int{return x + y}
      }
      
    • 定义闭包函数,内部的count能够一直累加,而不会被释放
      fun makeFun():()->Unit{var count=0return fun(){println(++count)}
      }fun main(args: Array<String>){val x=makeFun()x()x()x()...
      }
      

5.5 中缀表达式

  • infix 关键字可以简化操作函数,具体可以百度;
  • P1,P2,R 表示:参数1,参数2,返回值
  • 代码图1:

  • 代码图2:
  • 函数复合:
    • f(g(x))
    • 如何实现函数复合
    • 回顾:infix的使用

5.6 Currying 科理化

  • 概述:

    • 理解Currying的概念

      • 简单说就是多元函数变换成一元函数调用链(就是将多个参数的函数变成一个参数的函数的调用链)
    • 了解Currying的实现方法
    • 有科理化就有反科化,就是将一元函数调用链变成多元函数
  • 代码图片示例:

    这里是打印参数的例子;

5.7 偏函数

  • 把函数中其中一个或多个值固定为某值的函数
  • 概述:
    • 理解函数的概念:

      • 传入部分参数得到的新函数
    • 仔细体会与Currying的不同
    • 了解偏函数的实现方法
  • 图示:

5.8 小案例: 统计字符串个数

  • 图示:
  • 总结:本章节主要讲解到了高阶函数的一些简单概念及基本使用,为了解及熟悉高阶函数打开了大门,在日常使用过程中,熟悉这些高阶函数,能够让我们更快的写入Kotlin的代码,让程序更加简洁优雅;

六. 领域特定语言: DSL

6.1 DSL的特点

  • 概述: 它是一门计算机编程语言,具有语言的表达能力,但是它的表达能力有限,通常只关注某个特定的领域,与java可以写web,可以写安卓可以写桌面程序不一样,它的适用面仅限于特定领域,作用范围更小;

6.2 HTML DSL

  • 通过写Kotlin代码能生成处Html代码;
  • 代码如图所示:

6.3 Gradle Kotlin脚本编写

  • 概述:我们项目工程是以Gradle编写的,可以用Kotlin脚本编写;

  • 好处:

    • 带提示
    • 更简洁
    • 能使用Kotlin语法
    • 功能更丰富
  • 一些区别:

    • Kotlin脚本需要将build.gradle改名为build.gradle.kts
    • 改名后需要重启
    • Kotlin脚本中需要将单引号改为双引号
  • 改造前:

  • 改名后,全部爆红:

  • 重启之后,按照Kotlin写法改正后:(可以与原来代码比对,以学习kotlin脚本语法)

    改写之后能够正常编译、打包、运行操作,与之前一样;

七、协程

7.1 协程的基本概念

  • 什么是协程

    • 协作程序,解决异步问题
    • 应用层完成调度
    • 支持协程的语言例如:
  • 协程的特点:

    • 协程是协同作事情、Java的多线程是抢占的
    • 协程是以同步的代码作异步的活;
    • 协程消耗资源更少,只需要记录位置,和结束标记等;
    • 协程的图片示例:
  • 协程要解决什么问题

    • 异步代码像同步代码一样直观
    • 简化异步代码异常处理
    • 轻量级的并发方案
    • 它从1.1开始支持,是实验性质的API,后面可能有一定的变化,但目前已经变化很小了;
  • 如何支持协程

    • 编译器对suspend函数的编译支持
    • 标准库的基本API支持
    • kotlinx.coroutine应用级支持
  • 本章目标

    • 掌握协程标准库API的使用方法
    • 了解协程的运行原理
    • 了解 kotlinx.coroutine框架

7.2 了解协程

  • enqueue: 表示异步处理
  • 协程是没有异步能力的,这需要我们手动去操作;
  • 协程的基本API
    • createCoroutine:创建协程
    • startCoroutine:启动协程
    • suspendCoroutine:挂起协程
    • Continuation接口: 运行控制类,负责结果和异常的返回
    • CoroutineContext接口:运行上下文,资源持有,运行调度
    • ContinuationInterceptor接口
      • 协程控制拦截器
      • 可用来处理协程调度
  • 执行流程:
    1. 携程被编译成状态机
    2. suspend函数即状态转移,如图所示:
    3. 详细来说,就是正常的结果通过resume返回,异常通过resumeWithException抛出,如图所示:

      这里的圈可能会转很多次,取决于调用多少次suspend函数;

7.3 kotlin.coroutine框架介绍

  • 主要模块,如图所示:

八. Kotlin与Java混合开发

8.1 基本互操作

  • 属性读写:

    • Kotlin自动识别Java Getter/Setter
    • Java操作Kotlin属性通过Getter/Setter
  • 空安全类型
    • Kotlin有空安全
    • Java没有,所以可能会涉及Platform Type,我们可以通过@Nullable和@NotNull来弥补java的不足
  • 几类函数的调用:
    • 包级函数: 静态方法
    • 扩展方法:带Receiver的静态方法
    • 运算符重载: 带Receiver的对应名称的静态方法
  • 几个常见注解的使用:
    • @JvmField: 将属性编译为Java变量
    • @JvmStatic: 将对象的方法编译成Java静态方法

      上面这两个都是加上之后与java的静态变量|静态方法 没有差别,否则不能被java所识别;

    • @JvmOverloads: 默认参数生成重载方法

      标注这个注解后能被java识别,它是一个默认参数,java中没有这个,标注后就可以使用了

    • @file:JvmName : 指定Kotlin文件编译后的类名
  • NoArg与AllOpen
    • NoArg为被标注的类生成无参构造;

      • 支持JPA注解,如@Entity
    • AllOpen为被标注的类去掉final,允许被继承
      • 支持Spring注解,如@Component
    • 支持自定义注解类型,例如:@PoKo
  • 泛型
    • 通配符Kotlin的*对应于Java 的 ?
    • 协变和逆变 out/in
      • ArrayList
    • 没有Raw类型
      • Java的List->Kotlin的List<*>

8.2 SAM转换

  • 概述:

    • Single Abstract Method
    • SAM转换的条件
      • Java的接口,单一接口方法
    • 注意转换后的实例变化

8.3 正则表达式

  • 概述:

    • 用Raw字符串定义正则表达式(就是不需要转义符,然后***三个)
    • Java的Pattern
    • Kotlin的Regex
  • 代码如图:

8.4 集合框架

  • 概述:

    • Kotlin到Java的类型映射
    • 不可变与可变集合接口
    • 部分接口优化
  • 代码如图:

  • 集合类型of 表示为不可变集合,初始化之后就不能进行操作了;而Mutable集合类型表示为可变集合

    • 代码如图:

8.5 IO操作

  • Java版本读取操作:
  • Kotlin读取操作:
  • 使用use关键词能自动关闭流,如图所示:
  • 小文件可以用Kotlin的扩展方法:
  • 总结IO操作:
    • File、Stream、Reader、Writer的扩展方法
    • 使用use扩展自动关闭资源
    • 小文件一次性读取操作

8.6 拆箱与装箱

  • 了解Kotlin基本类型到Java的映射关系
  • 注意规避基本类型相关的问题
  • 代码示例:

    如果遇到这种问题,可以定义java代码或者中间通过java代码进行处理

8.7 注解处理器

  • 首先添加插件:

    apply plugin: "kotlin-kapt"// 添加生成路径
    sourceSets{main.kotlin.srcDirs+= "build/generated/source/kapt/main"
    }
    

    然后更新Gradle,通过Gradle右侧Build命令,使用IDEA的Build不能编译,IDEA还不支持

  • 如图所示:

九. Kotlin的未来与展望

9.1 Kotlin的应用场景

  • Kotlin Sript

    • Gradle脚本,Gradle 3.0开始部分支持,尚在完善中
  • Java虚拟机应用

    • Web应用,完美支持
    • JavaFx,完美支持
  • 前端开发

    • 1.1开始正式支持Kotlin-JavaScript
  • Android应用开发

    • Kotlin目前的主战场
  • Native程序

    • 直接编译Kotlin代码为机器码,不依赖Jvm
    • 支持与C代码交互
    • 技术预览版功能有限,前途无量

9.2 Kotlin-Script脚本编写

  • 代码示例:
  • 只要以后缀名为kts,就能马上识别出这是脚本
  • 还能创建安卓、前端项目,SpringBoot项目,具体省略;

9.3 创建SpringBoot项目

  • 选择项目类型:

  • 输入项目名称和组名:

    然后一直next 成功创建后到主界面;

  • 创建成功后如图所示:

  • 配置noarg插件,它能在程序编译的时候,自动的为对象生成默认的无参构造方法

  • 配置allopen插件,因为kotlin的类都是final的,我们继承它的时候需要open,能在编译的时候去掉final;

以上两个只有编译期能使用

  • 操作如图所示:(添加的不止于上方所述的内容)

里面配置的如jpa的部分可以根据实际情况决定,不需要可以去掉;

9.4 Kotlin-Natie项目开发

  • 可以不需要使用jvm进行编译
  • 目前还未正式发布,仅用于了解
  • 可直接与C语言进行交互

更多可百度学习

9.5 结束

  • 互勉互励,点个关注一起加油吧!( ^∀^)

Kotlin零基础入门到精通(精选)相关推荐

  1. simulink仿真及代码生成技术入门到精通_Simulink仿真零基础入门到精通实用教学教程 自学全套...

    Simulink仿真零基础入门到精通实用教学教程 自学全套,以教程文字为主,毕业论文和报告均可以借鉴. Simulink是电气工程必学的模型仿真专业工具软件,非常的实用.小编在全网中搜索都没有找到非常 ...

  2. 如何从零基础入门并精通PS?PS如何快速入门?

    本文由:"学设计上兔课网"原创,图片素材来自网络,仅供学习分享 如何从零基础入门并精通PS?PS如何快速入门?ps作为时下最受欢迎的p图软件,经常有同学私信问兔课菌:零基础自学ps ...

  3. python零基础入门教程(非常详细),从零基础入门到精通,看完这一篇就够了

    前言 本文罗列了了python零基础入门到精通的详细教程,内容均以知识目录的形式展开. 第一章:python基础之markdown Typora软件下载 Typora基本使用 Typora补充说明 编 ...

  4. keyshot7工业产品零基础入门到精通自学教程视频全套设计课程

    keyshot7工业产品零基础入门到精通自学教程视频全套设计课程9205 课程内容-玛丽圈资源网 --/A21 keyshot7工业产品零基础入门到精通自学教程视频全套设计课程/ ├──素材 | └─ ...

  5. 300集ps视频从零基础入门到精通

    目前来说,PS是一项很基本的工作技能了.并且Photoshop一直都被纳入大学计算机等级考试中,photoshop已经像Word,Excel,PPT那么普及了.相信同学们在写简历的时候也会写上去. 其 ...

  6. PowerMill模具数控编程视频教程全套产品三轴零基础入门到精通

    最近有很多人在问什么是结构设计?结构要处理的东西算是比较灵活,因为一个产品有了外形设计之后,要做结构设计来处理其运动特性.这样的产品在结构上是否坚固,是否能满足产品的要求,就成了结构设计的重要内容,而 ...

  7. Marvelous Designer布料和角色服装造型完整教程零基础入门到精通实用教学视频教程

    Marvelous Designer布料和角色服装造型完整教程零基础入门到精通实用教学视频教程 marvelous designer是目前世界上最流行的服装打板和模拟软件,能够即时的演算服装的打板,外 ...

  8. Python入门教程(非常详细)从零基础入门到精通,看完这一篇就够了

    前言 本文罗列了了python零基础入门到精通的详细教程,内容均以知识目录的形式展开. 第一章:python基础之markdown Typora软件下载 Typora基本使用 Typora补充说明 编 ...

  9. python 二进制流转图片_Python零基础入门到精通-5.1节:Python程序的执行过程

    教程引言: 系统地讲解计算机基础知识,Python的基础知识, 高级知识,web开发框架,爬虫开发,数据结构与算法,nginx, 系统架构.一步步地帮助你从入门到就业. 5.1.1 在命令行中执行Py ...

最新文章

  1. jq 读取office插件_800+页麦肯锡经典图示发送!让你不用插件,轻松搞定逻辑图...
  2. expdp / impdp 用法详解
  3. 非对称性密钥加密 java 实例_JAVA实现非对称加密
  4. C语言 · 黑色星期五
  5. mysql explain 为空_车祸现场!我的MySQL千万级数据表选错索引了!
  6. 带哨兵节点的链_HBA公链 | IPFS:区块链“不可能三角”的可能解
  7. pytorch torch.utils.data.TensorDataset
  8. 第八届蓝桥杯第五题取数位
  9. git 设置忽略文件类型 gitignore
  10. phonegap2.9.1 android 环境搭建,PhoneGap 开发环境搭建
  11. HttpUtil工具
  12. Guava guava-18.0.jar下载
  13. WS2811彩带驱动库函数
  14. 分支定界-附Python代码
  15. win10计算机远程连接命令,详细教你win10设置远程桌面连接命令
  16. Matlab笔记——License Manager Error -9解决办法——matlab反激活
  17. 转载:Android Studio 快捷键
  18. 用c语言计算运费.c
  19. java向飞秋发文件_飞秋如何发文件夹
  20. NBA16大亿元合同:鲨鱼飞侠双份肥约 大将军败坏亿元

热门文章

  1. html中hr标签有哪些属性,htmlhr标签的属性有哪些?HTMLhr标签的样式详解
  2. 标准体系,技术标准,政策标准,开发模板
  3. Partial Dependence Plots —— 部分依赖图_特征如何影响模型预测
  4. Linux下NFS服务器的配置
  5. 阿里服务器网站访问非常慢,更换本地DNS 解决网站访问速度变慢问题
  6. 该卸载PhotoShop了!MIT用AI实现3分钟自动抠图,精细到头发丝
  7. Java向pdf模板中写入数据并在模板之后添加新的表格内容
  8. Eigen/Matlab库矩阵运算方法
  9. Logger Log4j2 could not find a logging implementation.解决方法
  10. #umn 来美国近一个月的简单见闻