Kotlin-初识

380 阅读6分钟

前言

鉴于很早之前学习过 Kotlin,遗憾的是并未在项目中实际使用,时间一长就忘得差不多了。时过境迁,现在正好有机会在实战中使用 Kotlin。为此自己想要提前捡起来复习一遍以便快速开始上手开发,特此记录一下。如有不对的地方,还请帮忙指正!

Hello Kotlin

方法

如下是一个简单的代码示例,其中 main() 方法是程序的入口,fun 用来声明函数。

fun main() {
    println("hello kotlin")
}

变量

Kotlin 中,当我们声明变量时,可以选择下面。

  • 可变变量 var
  • 只读变量 val
fun main() {
    val num = 1
    val name = "Jack"

    var count = 1
    count = 8
    println(count)
}

字符串

Kotlin 中如果想插入字符串,可以用 $ 引用,如下示例。需要注意的是,若要计算模板表达式中的一段代码,请将代码放在美元符号后面的大括号内。

fun main() {
    val name = "Jack"
    println("i am $name")

    val num = 10
    println("current number is ${num + 1} ")
}

基本类型

整数类型

Kotlin 有自己的内置数字类型,如下所示。

类型大小(位数)最小值最大值
Byte8-128127
Short16-3276832767
Int32-2,147,483,648 (-231)2,147,483,647 (231 - 1)
Long64-9,223,372,036,854,775,808 (-263)9,223,372,036,854,775,807 (263 - 1)

初始化没有显式类型规范的变量时,编译器会自动推断具有最小范围的类型,若要显式指定该值,请将后缀追加到该值。显式类型规范触发编译器检查值不超过指定类型的范围。

val mBype: Byte = 1
val mShort: Short = 2
val mInt: Int = 1
val mLong: Long = 1L

浮点类型

类型大小(位)有效位指数位十进制数字
Float322486-7
Double64531115-16

若要显式指定值的类型,请添加后缀 fF。如果此类值包含超过6-7个十进制数字,则将四舍五入。

val mDouble: Double = 2.0
val mFloat: Float = 1.2F
val mFloatMax: Float = 1.12345678f

布尔类型

该类型可声明两个值,即 truefalse,在 JVM 中占8个字节。

val mTrue: Boolean = true
val mFlase: Boolean = false

字符串

Kotlin 中字符串用 String 关键字声明,可以不用显示指定类型。

val name = "canny"
val name:String = "canny"

控制流

条件和循环

if/for/while表达式

Kotlin 中,上述表达式和 Java 在语法上保持一致,所以就不详细介绍了。

when表达式

when 表达式比较特殊,具有多个分支来表示结果。

when (x) {
    1 -> println("x == 1")
    2 -> println("x == 2")
    else -> {
        println("x is not 1 or 2")
    }
}

中断关键字

Kotlin 中断关键字是 continue/break/return,与 Java 语言保持一致。

异常

Kotlin 并不会检查异常,如果要主动抛出异常,可以使用 throw Exception("xxx exception"),捕获异常通过 try catch

类和对象

Kotlin 中声明一个类使用关键字 class,跟 Java 是一致的。

构造函数

Kotlin 中的类具有一个主要构造函数,也可能有一个或多个辅助构造函数。主构造函数在类头中声明,它位于类名和可选类型参数之后。

class Man constructor(mName: String) {  }

如果主构造函数没有任何注释或可见性修饰符,则可以省略关键字 constructor

class Man (mName: String) {  }

构建实例

Kotlin 中并没有关键字 new 来实例化对象,可以像调用函数来创建对象。

val manBean = Man()
val manBean = Man("Jack")

类的属性

Kotlin 类中的属性可以使用关键字声明为可变属性,也可以使用关键字声明为只读属性。

class Address {
    var name: String = "Holmes, Sherlock"
    var street: String = "Baker"
    var city: String = "London"
    var state: String? = null
    var zip: String = "123456"
}

要使用属性,只需通过其名称来引用它,不需要显式的声明 getset 方法。

fun copyAddress(address: Address): Address {
    val result = Address() // there's no 'new' keyword in Kotlin
    result.name = address.name // accessors are called
    result.street = address.street
    // ...
    return result
}

抽象类

用关键字 abstract 修饰,抽象类中没有具体实现。

abstract class Polygon {
    abstract fun draw()
}

class Rectangle : Polygon() {
    override fun draw() {
        // draw the rectangle
    }
}

继承

Kotlin 中的所有类都有一个通用的超类,它是未声明超类型的类,默认超类 Any

class Example // Implicitly inherits from Any

需要注意的是,Kotlin 中类默认情况下是 final 类型,需要被继承时需要显示声明 open

open class Base // Class is open for inheritance

覆写

重写机制对属性的工作方式与对方法的工作方式相同,每个声明的属性都可以由具有初始值设定项的属性或具有方法的属性重写。

open class Shape {
    open val vertexCount: Int = 0
}

class Rectangle : Shape() {
    override val vertexCount = 4
}

Kotlin 中,实现继承受以下规则的约束:如果一个类从其直接超类继承同一成员的多个实现,则它必须覆盖此成员并提供自己的实现。

若要表示从中获取继承实现的超类型,请在尖括号中使用由超类型名称限定的超类型名称.

    open fun draw() { /* ... */ }
}

interface Polygon {
    fun draw() { /* ... */ } // interface members are 'open' by default
}

class Square() : Rectangle(), Polygon {
    // The compiler requires draw() to be overridden:
    override fun draw() {
        super<Rectangle>.draw() // call to Rectangle.draw()
        super<Polygon>.draw() // call to Polygon.draw()
    }
}

接口

Kotlin 中的接口可以包含抽象方法的声明,也可以包含方法实现。它们与抽象类的不同之处在于接口不能存储状态。它们可以具有属性,但这些属性必须是抽象的或提供访问器实现。

使用关键字 interface 定义接口。

interface MyInterface {
    fun bar()
    fun foo() {
      // optional body
    }
}

编译时常量

如果只读属性的值在编译时已知,请使用修饰符 const 将其标记为编译时常量。此类属性需要满足以下要求:

  • 它必须是顶级属性,或者是对象声明的成员或伴随对象。
  • 它必须使用 type 或基元类型的值进行初始化 String
  • 它不能是自定义 getter
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... }

延迟初始化

通常,必须在构造函数中初始化声明为具有不可为 null 类型的属性。但是,通常情况下这样做并不方便。例如,可以通过依赖项注入或在单元测试的设置方法中初始化属性。在这些情况下,不能在构造函数中提供不可为 null 的初始值设定项,但在引用类主体中的属性时,仍希望避免 null 检查。

若要处理此类情况,可以使用修饰符 lateinit 标记属性。

public class MyTest {
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }

    @Test fun test() {
        subject.method()  // dereference directly
    }
}

检查 lateinit var 是否初始化

若要检查是否已初始化,请使用下述方式。

if (foo::bar.isInitialized) {
    println(foo.bar)
}

泛型

Kotlin 中的类可以有类型参数,就像在 Java 中一样:

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

枚举类

枚举类最基本的用例,是类型安全枚举的实现。

enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

参考

kotlinlang.org/docs/gettin…