kotlin学习笔记

初识

  • kotlin是一门用于现代多平台应用的编程语言,被广泛应用于Android平台的开发
  • 特点:更有安全性(避免null指针)、可互操作(与java交互操作)、协程

适用的应用平台

  • Android:使用 Kotlin 语法,可以为 Android创建移动应用程序。
  • JS:Kotlin 还与 JavaScript 兼容,能够开发客户端 Web 应用程序并在浏览器中运行它们。

学习内容概述

1、基础语法

掌握基本变量类型、声明(val、var)、循环语句、函数及类的定义使用等

  • 字符串模板及格式

    • 用$

    • val i = 10
      println("i = $i") 
      // i = 10
      
    • ${}

    • val s = "abc"
      println("$s.length is ${s.length}") 
      // abc.length is 3
      
    • 字符串格式-- String.format()

    • val num = String.format("%07d", 31416)
      println(num)
      // 0031416
      
      val floatNumber = String.format("%+.4f", 3.141592)
      println(floatNumber)
      // +3.1416
      
      val helloString = String.format("%S %S", "hello", "world")
      println(helloString)
      // HELLO WORLD
      
  • var/val的区别

    • var:可变 val:不可变

    • 推荐先使用val定义,可以避免被不小心修改,如果需要修改时再更改为var

  • 数组创建、比较数组

    • 数组创建

    • val simpleArray = arrayOf(1, 2, 3)
      println(simpleArray.joinToString())
      // 1, 2, 3
      
      val initArray = Array<Int>(3) { 0 }
      println(initArray.joinToString())
      // 0, 0, 0
      
      val asc = Array(5) { i -> (i * i).toString() }
      asc.forEach { print(it) }
      // 014916
      
    • 比较数组:比较两个数组是否具有相同顺序的相同元素

    • val simpleArray = arrayOf(1, 2, 3)
      val anotherArray = arrayOf(1, 2, 3)
      
      // 比较	
      println(simpleArray.contentEquals(anotherArray))
      // true
      
  • is操作符

    • 检测对象是否符合给定类型

    • if (obj is String) {
          print(obj.length)
      }
      
      if (obj !is String) { // 与 !(obj is String) 相同
          print("Not a String")
      }
      
  • if特殊用法

    • 作为表达式可以返回值

    •   // 作为表达式
       max = if (a > b) a else b
      
    • 可以是代码块,表达式作为返回值

    • val max = if (a > b) {
          print("Choose a")
          a  // 返回a
      } else {
          print("Choose b")
          b
      }
      
  • when

    • 类比Switch, else->default,可以使用任意表达式(不一定要常量)

    • when (x) {
          1 -> print("x == 1")
          2 -> print("x == 2")
          else -> {
              print("x is neither 1 nor 2")
          }
      }
      
      when (x) {
          in 1..10 -> print("x is in the range")  // 1..10 区间 [1,10]
          !in 10..20 -> print("x is outside the range")
          else -> print("none of the above")
      }
      
  • 类型转换

    • fun demo(x: Any) {
          if (x is String) {
              print(x.length) // x 自动转换为字符串
          }
      }
      

2、函数

了解函数式编程思想,能熟练掌握函数应用

  • 使用

    • 通过fun关键字声明,参数可以有默认值

    • fun double(x: Int): Int {
          return 2 * x
      } // 每个参数必须有显式类型
      
    • 单表达式函数

    • fun sum(x: Int, y: Int): Int {
          return x + y
      }
      // 缩短
      fun sum(x: Int, y: Int) = x + y
      

  • lambda表达式

    • fun uppercaseString(text: String): String {
          return text.uppercase()
      }
      // 改为lambda表达式
      val upperCaseString = { text: String -> text.uppercase() } 
      // ->前面是参数,后面是返回值
      
      val numbers = listOf(1, -2, 3, -4, 5, -6)
      val positives = numbers.filter ({ x -> x > 0 }) // 参数x,获取列表的每个元素,返回x>0的集合
      
      val isNegative = { x: Int -> x < 0 }
      val negatives = numbers.filter(isNegative) // 参数x,获取列表的每个元素,返回x<0的集合
      
      println(positives)
      // [1, 3, 5]
      println(negatives)
      // [-2, -4, -6]
      

3、面向对象编程

理解类和对象的作用,掌握主构造和次构造以及各种类

  • 构造函数

    • 在 Kotlin 中的一个类有一个主构造函数并可能有一个或多个次构造函数

    • 主构造函数

      • 在类头中声明,它跟在类名与可选的类型参数后,初始化类实例及其属性。

      • class Person constructor(firstName: String) { 
        /*……*/ 
        }  // 没有注解时constructor可以省略不写   属性可以写默认值
        
      • 如果要在对象创建期间运行一些代码,使用init关键字,初始化块按照它们出现在类体中的顺序执行

      • class InitOrderDemo(name: String) {
            val firstProperty = "First property: $name".also(::println)
        
            init {
                println("First initializer block that prints $name")
            }
        
            val secondProperty = "Second property: ${name.length}".also(::println)
        
            init {
                println("Second initializer block that prints ${name.length}")
            }
        }
        
    • 次构造函数(简单了解),会委托给主构造函数

      • class Person(val name: String) {
            val children: MutableList<Person> = mutableListOf()
            constructor(name: String, parent: Person) : this(name) {
                parent.children.add(this)
            }
        }
        
    • 创建类实例

      • val invoice = Invoice()
        
        val customer = Customer("Joe Smith")
        
  • 继承

    • 共同超类:Any,有三个默认方法:equals,hashCode、toString

    • 用open关键字开放继承

      • open class Base(p: Int) // 开放继承
        
        class Derived(p: Int) : Base(p)
        
    • 覆盖(了解):Kotlin 对于可覆盖的成员以及覆盖后的成员需要显式修饰符

      • open class Shape {
            open fun draw() { /*……*/ }
            fun fill() { /*……*/ }
        }
        // open 开放覆盖 override禁止覆盖
        class Circle() : Shape() {
            override fun draw() { /*……*/ }
        }
        
  • 属性

    • Getter与Setter

    • // 声明一个属性的完整语法

      var <propertyName>[: <PropertyType>] [= <property_initializer>]
          [<getter>]
          [<setter>]
      // 初始器(initializer)、getter 和 setter 都是可选的
      
      class Rectangle(val width: Int, val height: Int) {
          val area: Int // 类型可以省略   val area get() = this.width * this.height
              get() = this.width * this.height
      }
      
  • 接口

    • 既包含抽象方法的声明也包含实现,使用关键字interface定义

    • interface MyInterface {
          val prop: Int // 抽象的
      
          val propertyWithImplementation: String
              get() = "foo"
      
          fun foo() {
              print(prop)
          }
      }
      
      class Child : MyInterface {  // 实现接口(一个或多个)
          override val prop: Int = 29
      }
      
    • 接口可以从其他接口派生

    • interface Named {
          val name: String
      }
      
      interface Person : Named {
          val firstName: String
          val lastName: String
      
          override val name: String get() = "$firstName $lastName"
      }
      
      data class Employee(
          // 不必实现“name”
          override val firstName: String,
          override val lastName: String,
          val position: Position
      ) : Person
      
    • 覆盖冲突:实现多个接口时,可能遇到同一方法继承多个实现的问题,需要实现从多个接口继承的所有方法,并指明应该如何实现它们。

    • interface A {
          fun foo() { print("A") }
          fun bar()
      }
      
      interface B {
          fun foo() { print("B") }
          fun bar() { print("bar") }
      }
      
      class C : A {
          override fun bar() { print("bar") }  // foo已实现,重写bar
      }
      
      class D : A, B {
          override fun foo() { // A、B的foo方法不一样,需要自己重写定义
              super<A>.foo()
              super<B>.foo()
          }
      
          override fun bar() {
              super<B>.bar()
          }
      }
      
    • 函数式接口:只有一个抽象方法的接口,可以有多个非抽象成员,只能有一个抽象成员

      • fun interface KRunnable {
           fun invoke()
        }
        
  • 可见性修饰符

    • 如果你不使用任何可见性修饰符,默认为public ,这意味着你的声明将随处可见。

    • 如果你声明为 private,它只会在声明它的文件内/类内部可见。

    • 如果你声明为internal ,它会在相同模块内随处可见。

    • protected 修饰符不适用于顶层声明,在本类和子类中可见。

    • // 文件名:example.kt
      package foo
      
      private fun foo() { …… } // 在 example.kt 内可见
      
      public var bar: Int = 5 // 该属性随处可见
          private set         // setter 只在 example.kt 内可见
      
      internal val baz = 6    // 相同模块内可见
      
  • 扩展(了解)

    • 对一个类或接口扩展新功能而无需继承该类

    • 可以为一个你不能修改的、来自第三方库中的类或接口编写一个新的函数。 这个新增的函数就像那个原始类本来就有的函数一样,可以用寻常方式调用。 这种机制称为扩展函数

    • fun MutableList<Int>.swap(index1: Int, index2: Int) {
          val tmp = this[index1] // “this”对应该列表
          this[index1] = this[index2]
          this[index2] = tmp
      } // MutableList<Int>增加swap函数
      
  • 数据类

    • 主要用于保存数据,自动附带其他成员函数。这些成员函数允许您轻松地将实例打印为可读输出、比较类的实例、复制实例等

    • data class User(val name: String, val age: Int)
      
    • 主要成员函数

      函数描述
      equals()比较类的实例。
      copy()通过复制另一个类实例来创建类实例,该实例可能具有一些不同的属性。
      toString()打印类实例及其属性的可读字符串。

4、高级知识

  • 泛型

    • 类似java的类型参数

    • class Box<T>(t: T) {
          var value = t
      }
      

  • 集合

    • list:按添加顺序存储项目,并允许重复项目

    • val readOnlyShapes = listOf("triangle", "square", "circle")  // 只读
      println(readOnlyShapes)
      // [triangle, square, circle]
      
      val shapes: MutableList<String> = mutableListOf("triangle", "square", "circle") // 可变
      println(shapes)
      // [triangle, square, circle]
      
    • set:无序,只存储唯一项

    • val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry") // 只读
      // 只保留一个cherry
      val fruit: MutableSet<String> = mutableSetOf("apple", "banana", "cherry", "cherry") // 可改
      
      println(readOnlyFruit)
      // [apple, banana, cherry]
      
    • map:将内容存储为键值对,用key来访问

    • val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) //只读
      println(readOnlyJuiceMenu)
      // {apple=100, kiwi=190, orange=100}
      
      val juiceMenu: MutableMap<String, Int> = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100) // 可改
      println(juiceMenu)
      // {apple=100, kiwi=190, orange=100}
      

  • 异常

    • 可以捕获错误信息

    • try {
          // 一些代码
      } catch (e: SomeException) {
          // 处理错误的程序
      } finally {
          // 可选的 finally 块 一定会执行
      }
      
  • 空安全

    • 值可能为空时,需要用“?”标记

    • fun parseInt(str: String): Int? {
          // ...
      }
      

5、多平台开发

  • 安装Android Studio

  • MyFirstApp/: 项目的根目录。

    .idea/: Android Studio 的配置目录,包含项目的 IDE 设置,通常不需要手动更改。

    app/: 应用模块的主目录。

    src/: 源代码和资源文件存放的目录。

    main/: 主要的源代码和资源目录。

    java/: Java 或 Kotlin 源代码的目录。

    res/: 资源文件的目录。

    drawable/: 存放图像资源。

    layout/: 存放布局文件,定义应用界面的结构。

    mipmap/: 存放应用的图标和启动图。

    values/: 存放字符串、颜色、尺寸等资源。

    AndroidManifest.xml: 应用的清单文件,包含应用的配置信息、权限和组件声明。

    build.gradle: 应用级别的构建配置文件,定义了应用的依赖、插件和其他构建设置。

    build.gradle: 项目级别的构建配置文件,定义了整个项目的配置和依赖。

    gradle/: 存放与 Gradle 构建系统相关的文件和目录。

    gradle/wrapper/: Gradle Wrapper 文件,用于自动下载和使用指定版本的 Gradle。

    settings.gradle: 项目的全局设置文件,定义了项目包含的模块。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐