美文网首页我爱编程
Kotlin 快速入门

Kotlin 快速入门

作者: 灯不利多 | 来源:发表于2018-05-20 23:17 被阅读26次

    这篇文章是给有过 Java 或其他面向对象编程语言开发经验的朋友看的。省略了对很多面向对象编程的解释,希望大家能用最少的时间了解 Kotlin 的基础知识。你可以用 Intellij 、 Android Studio 或 Try Kotlin 运行文中的代码。

    本文内容:

    • 变量与常量
    • 基本类型
    • 值域
    • 循环
    • 异常处理
    • 引用等价与结构等价
    • 控制流
    • when 表达式
    • 类型层级

    变量与常量

    Kotlin 有两个声明变量和常量的数据类型,分别是 val 和 var。

    var 变量能直接赋值,也能先声明后赋值:

     // 无类型声明
     var age = 12
    
     // 显式声明变量类型
     var name1: String = "老王"
    
     // 重新赋值
     var name2 = "kotlin"
    

    val 常量相当于是 Java 中的 final 变量,必须在创建时初始化,且不能重新赋值:

    val name = "kotlin"
    
    // 编译时异常
    name = "changed kotlin" 
    

    类型推断

    在 Kotlin 中,声明变量时不需要声明具体类型,比如上面代码中的 age 变量。这种机制称为类型推断(type inference)。

    基本类型

    Kotlin 没有 int 和 Integer 等 Java 中的基本类型和包装类。但在 Kotlin 中有和 Java 包装类相似的装箱类(boxed type)。

    数值类型

    下面是 Kotlin 中内置的数值装箱类

    类型 字节
    Long 8
    Int 4
    Short 2
    Byte 1
    Double 8
    Float 4

    创建数值常量:

    val int = 123
    val long = 123456L  // 长整型结尾为 L
    val double = 12.34
    val float = 12.34F  // 浮点型结尾为 F
    val hexadecimal = 0xAB  // 十六进制开头为 0x 
    val binary = 0b010101  // 二进制开头为 0b
    

    Kotlin 中数值类型的相互转换可以通过类型转换函数:

    val int = 123
    val long = int.toLong()
    
    val float = 3.0F
    val double = float.toDouble()
    

    Kotlin 的类型转换函数:

    • toByte()
    • toShort()
    • toInt()
    • toLong()
    • toFloat()
    • toDoble()
    • toChar()

    下面是 Kotlin 的按位运算操作,按位取反在 Kotlin 是一元运算符,因此用 inv() 函数来进行运算:

    // 左移
    val leftShift = 1 shl 2 
    
    // 右移
    val rightShift = 1 shr 2  
    
    // 无符号右移
    val unsignedRightShift = 1 ushr 2  
    
    // 按位与
    val and = 1 and 0x00001111 
    
    // 按位或
    val or = 1 or 0x00001111  
    
    // 按位异或
    val xor = 1 xor 0x00001111  
    
    // 按位取反
    val inv1 = 1.inv()  
    
    // 编译时异常,要用 inv()
    val inv2 = ~1
    

    字符类型

    Kotlin 中的字符型变量不能用作数值,因为 Kotlin 中对该运算符的定义:

    // 编译时异常
    var a = 'a' == 10
    
    // 编译通过
    var b = 'a'.toInt() == 10
    

    字符串类型

    在 Kotlin 中可以用三个双引号 “”“ 将字符串括起来,这种字符串也叫原始字符串(raw string)。当字符串要换行的时候,不需要再用加号:

    val rawString = """
    strings that span many lines 
    strings that span many lines 
    """
    println(rawString)
    

    数组类型

    在 Kotlin 中可以通过 arrayOf() 函数来创建数组,还可以通过数组长度和字面函数来创建数组,函数计算值将会赋值到每一个元素中:

    val array = arrayOf(1, 2, 3)
    
    // 0、1、4、9、16、...、81
    val perfectSquares = Array(10, {k -> k * k})
    

    Kotlin 中的数组不是特殊数据类型,因此它有 get 、set 方法,但是一般不推荐使用:

    val array = arrayOf(1, 2, 3)
    var element1 = array[0]
    var element2 = array.get(1)
    array[2] = 5
    

    因为装箱类是对象,开销比基本类型要大。当你对性能要求高,可以使用 Kotlin 提供的几种数组类型,它们会被转换成基本类型 :

    • ByteArray
    • CharArray
    • ShortArray
    • IntArray
    • LongArray
    • BooleanArray
    • FloatArray
    • DoubleArray

    导包重命名

    当导入的类同名时,可以用 as 运算符对导入的包进行重命名:

    import com.packt.myproject.Foo
    import com.packt.otherproject.Foo as Foo2
    
    fun doubleFoo() {
      val foo1 = Foo()
      val foo2 = Foo2()
    }
    

    字符串模板

    Koltin 的字符串模板(template)允许你在字符串中插入多个变量,而不需要用加号拼接它们,使用字符串模板只需要在变量前面加美元符号($):

    val name1 = "Sam"
    val name2 = "Alex"
    val str = "$name1, $name2"
    
    // Sam, Alex
    println(str)
    

    如果插入的变量需要进行运算,比如访问某个对象的属性,则需要用花括号 { } 将它括起来:

    val name = "Sam"
    val str = "${name.length}"
    
    // 3
    println(str)
    

    值域

    Kotlin 中的值域(range)是由区间定义的。任何可比较的数据类型(如 Int、Long、Char)都能用于创建值域,创建值域可以用两点 .. 或 until 运算符:

    val aToZ = "a".."z"
    val oneToNine = 1..9
    
    // until 适用于遍历数组和列表等集合时
    // 10...19
    val zeroToNine =  0 until 10
    for(i in zeroToNine) println(i)
    

    用 in 运算符判断某个值是否在值域内:

    val aToZ = "a".."z"
    val isTrue = "c" in aToZ
    
    val oneToNine = 1..9
    val isFalse = 11 in oneToNine
    

    值域从该值往下和从该值往上分别是 downTo() 和 rangeTo() :

    // 0...100
    val countingDown = 100.downTo(0)
    
    // 10...20
    val rangeTo = 10.rangeTo(20)
    

    step() 函数可以创建不同步长的值域:

    val oneToTwenty = 1..20
    
    // 1、3、5、...、19
    val oddNumbers = oneToTwenty.step(2)
    

    用 reversed() 函数将值域的顺序颠倒:

    // 100、98、96、...、2
    val down2 = (2..100).step(2).reversed()
    

    循环

    Kotlin 的 for 循环能够遍历任何实现了 Iterator 接口的类中的元素,如数组、List、Set、Map :

    var array = listOf(1, 2, 3)
    for (i in array) println(i)
    
    val list = listOf(2, 3, 4)
    for (k in list) println(k)
    
    var map = mapOf("a" to 1, "b" to 2)
    
    // key: a, value: 1
    // key: b, value: 2 
    for((key, value) in map) 
      println("key: $key, value: $value")
    

    在 Kotlin 的 String 类中,Kotlin 也为它提供了一个 Iterator 扩展函数,因此 String 也能被遍历:

    val string = "print my characters"
    for (char in string) println(char)
    

    Kotlin 的数组有一个 indices 扩展函数,它可以用于遍历整个数组的下标:

    val array = arrayOf("a", "b", "c")
    
    // 0 1 2
    for (i in array.indices) 
      println(i)
    

    异常处理

    在 Kotlin 中异常都是非强制处理的(unchecked):

        fun error() {
            throw FileNotFoundException()
        }
    
    error()
    

    类的实例化

    在 Kotlin 中实例化一个类不需要 new :

    val date = BigDecimal(100)
    

    引用等价与结构等价

    引用等价指的是两个对象是否为同一个引用,也就是两个对象是否在同一块内存中,结构等价指的是对象结构是否相同,比如 List 的长度以及每个元素是否相同:

    var a = listOf(1, 2)
    var b = listOf(1, 2)
    
    // false, 非引用等价
    println(a === b)  
    
    // true,结构等价
    println(a == b)   
    

    this 表达式

    当 Kotlin 的 this 语句在扩展函数或字面函数(Function Literals)中时,this 指的是该扩展函数或字面函数。可以用 @ 加标签来修饰 this 指向的对象:

    class A {  
    
      inner class B {
        
        var foo = 100.foo()
        
        fun Int.foo() {
          
          // 用标签指向类 A 的实例 
          var a = this@A
          
          // 用标签指向类 B 的实例 
          var b = this@B
          
          // 当前扩展函数实例
          var c = this
         
          println(a)
          println(b)
          println(c)
        }
      }
    }
    

    可见度修饰符

    private

    使用 private 修饰的顶层函数、顶层类或接口只能在同一个文件中被访问。

    在一个类、接口或对象,任何 private 函数或属性只对其他该类的成员变量、接口或对象可见:

    class A {
      private var a = 10
      
      private fun b() { }
      
      fun c() {
        var c = a
        var d = b()
      }
    }
    
    class B {
      // 编译时异常,a 为私有变量
      var e = A().a
      
      // 编译时异常,a 为私有函数
      var f = A().b()
    }
    

    Protected

    顶层函数、类、接口或对象不能声明为 protected 。任何在类或接口中声明为 protected 的函数或属性只对该类或接口的成员变量以及子类可见。

    open class A {
      protected var a = 10
    }
    
    class B {
      // 编译时异常,a 为 protected
      var a = A().a
    }
    
    class C: A() {
      var c = a
    }
    

    Internal

    同模块的类可见。这里的模块指的是 Intellij 中定义的 Maven 或 Gradle 模块。

    控制流语句

    在 Kotlin 中,if...else 和 try...catch 代码块是表达式,这些代码块的运算结果可以赋值给变量、用作函数的返回值或当做参数传给一个函数:

    var a = 10
    val b = if (a == 10) true else false
    
    val success = try {
      true
    } catch (e: IOException) {
      false
    }
    

    if...else 作为返回值和参数:

    fun isZero(x: Int): Boolean {
      return if (x == 0) true else false
    }
    
    isZero(if (a == 10) 0 else 10)
    

    Kotlin 中没有定义三元运算符:

    // 编译时异常,不支持三元运算符
    var b = a == 10 ? 5 : 0
    

    当使用 if 作为表达式时,要包含 else 语句 :

    // 编译时异常
    var a = if (1 == 2) true
    
    // 编译通过
    var b = if (1 == 2) true else false
    

    空值处理

    一个能赋为空值变量需要在变量类型后加上问号:

    // 编译时异常
    var str1: String = null
    
    // 编译通过
    var str2: String? = null
    

    类型检查与转换

    Kotlin 中可以用 is 运算符替换 Java 的 instnaceof 运算符,在经过 is 运算符类型检查通过后编译器都会帮我们自动转换类型:

    fun isString(any: Any) {  
      var str = ""
      // 经过 is 检查后编译器会帮我们将 Any 转成 String 
      str = if (any is String) any else "b"
    }
    

    如果要进行转换的是布尔值那么 if...else 都可以省了:

    fun isEmptyString(any: Any) : Boolean {
      return any is String && any.length == 0
    }
    

    在这个例子中,函数测试我们没有一个字符串,或者我们有,然后必须为空

    显式转换

    若要显式地进行类型转换,可以用 as 运算符,转换不成功时会抛出一个类型转换异常:

    val str1 = "123" as String
    
    // elvis 安全转换,转换不成功会返回 null 字符串
    val str2 = 123 as? String
    
    // 类型转换异常
    val str3 = 123 as String
    

    when 表达式

    Kotlin 的 when 表达式有两种形式。第一种类似于 Java 的 switch 表达式。第二种用一系列条件判断语句条件进行语句切换。

    when(value)

    类似于 switch ,需要一个常量:

    fun foo(x: Int) {
      when (x) {
        0 -> println("x is zero")
        1 -> println("x is 1")
        else -> println("x is neither 0 or 1")
      }
    }
    

    Kotlin 中的 when 表达式类似于 if...else 代码块可以赋值给变量、作为参数或返回值:

    fun isMinOrMax(x: Int): Boolean {
      val isZero = when (x) {
        Int.MIN_VALUE -> true
        Int.MAX_VALUE -> false
        else -> false
      }
    }
    

    当两个分支的代码是一样时,可以用逗号将它们分隔开以执行同一个分支:

    fun isZeroOrOne(x: Int) : Boolean {
      return when (x) {
        0, 1 -> true
        else -> false
      }
    }
    

    没有参数的 when

    没有参数的 when 代码块,用条件语句进行切换:

    fun foo (x: Int, y: Int) {
      when {
        x < y -> println("x 小于 y")
        x > y -> println("x 大于 y")
        else -> println("x 等于 y0")
      }  
    }
    

    函数返回值

    在 Kotlin 中,当函数返回值不为空时,需要声明函数返回值的类型,当允许返回空值时,要加问号表明:

    fun foo1() {
      // 编译时异常,没声明返回值类型
      return ""
    }
    
    fun foo2(): String {
      // 编译时异常,没有加问号
      return null
    }
    
    fun foo3(a: Int, b: Int) : Int {
      // 编译成功
      return a + b
    }
    

    如果从闭包中返回一个值,需要用标签修饰返回类型,否则返回的是外部函数,标签可以是显式也可以是隐式的:

    fun printUtilStop1() {
      val list = listOf("a", "b")
      list.forEach stop@ {
        // 显式标签
        if (it == "stop") return@stop
        else println(it)
      }
    }
    
    fun printUtilStop2() {
      val list = listOf("a", "b")
      list.forEach {
        // 隐式标签
        if (it == "stop") return@forEach
        else println(it)
      }
    }
    

    类型层级

    在 Kotlin 的 Any 类型相当于 Java 的 Object,它是所有对象的父类。Any 中定义了 toString,hashCode 以及 equal 等函数。它也定义了apply 、let 和 to 等扩展方法。

    Kotlin 的 Unit 类型相当于 Java 中的 void,Unit 与 void 的区别在于 Unit 是一个类而且是单例对象。

    Kotlin 中的 Nothing 类型是所有类型的子类。同时它也是 elvis 运算符和 emptyList() 函数的实现。当函数没有返回值时可以返回
    Nothing 类型:

    fun reportError(): Nothing = throw RuntimeException()
    
    fun a (x: Int): String{
      if (x > 10)
        return "OK"
      // 编译时异常,没有返回值
    }
    
    fun b (x: Int): String {
      if (x > 10)
        return "OK"
      
      // 自动返回 Nothing
      reportError()
    }
    

    参考资料

    Kotlin 官方文档

    Programming Kotlin

    相关文章

      网友评论

        本文标题:Kotlin 快速入门

        本文链接:https://www.haomeiwen.com/subject/detadftx.html