Kotlin基礎掌握

1.Kotlin簡介

Kotlin 是一个用于现代多平台应用的静态编程语言,Kotlin可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。

 

Kotlin,如前面所说,它是JetBrains开发的基于JVM的语言。JetBrains因为创造了一个强大的Java开发IDE被大家所熟知。Android Studio,官方的Android IDE,就是基于Intellij,作为一个该平台的插件。

Kotlin是使用Java开发者的思维被创建的,Intellij作为它主要的开发IDE。对于Android开发者,有两个有趣的特点:

 

对Java开发者来说,Kotlin是非常直觉化的,并且非常容易学习。语言的大部分内容都是与我们知道的非常相似,不同的地方,它的基础概念也能迅速地掌握它。

它与我们日常生活使用的IDE无需配置就能完全整合。Android Studio能够非常完美地理解、编译运行Kotlin代码。而且对这门语言的支持来正是自于开发了这个IDE的公司本身.

 

1.1語言優勢

1.它更加易表现:这是它最重要的优点之一。你可以编写少得多的代码。

2.它更加安全:Kotlin是空安全的,也就是说在我们编译时期就处理了各种null的情况,避免了执行时异常。如果一个对象可以是null,则我们需要明确地指定它,然后在使用它之前检查它是否是null。你可以节约很多调试空指针异常的时间,解决掉null引发的bug

3.它是函数式的:Kotlin是基于面向对象的语言。但是就如其他很多现代的语言那样,它使用了很多函数式编程的概念,比如,使用lambda表达式来更方便地解决问题。其中一个很棒的特性就是Collections的处理方式。

4.它可以扩展函数:这意味着我们可以扩展类的更多的特性,甚至我们没有权限去访问这个类中的代码

5.它是高度互操作性的:你可以继续使用所有的你用Java写的代码和库,因为两个语言之间的互操作性是完美的。甚至可以在一个项目中使用KotlinJava两种语言混合编程。

 

2.基礎語法

2.1定義函數

(1)带有两个 Int 参数、返回 Int 的函数:

fun sum(a: Int, b: Int): Int {

    return a + b

}

 

(2)将表达式作为函数体、返回值类型自动推断的函数:

fun sum(a: Int, b: Int) = a + b

 

(3)函数返回无意义的值:

fun printSum(a: Int, b: Int): Unit {

    println("sum of $a and $b is ${a + b}")

}

 

(4)Unit 返回类型可以省略:

fun printSum(a: Int, b: Int) {

    println("sum of $a and $b is ${a + b}")

}

 

2.2定义变量

var表示變量

Val表示常量

(1)一次赋值(只读)的局部变量:

val a: Int = 1  // 立即赋值

val b = 2   // 自动推断出 `Int` 类型

val c: Int  // 如果没有初始值类型不能省略

c = 3       // 明确赋值

 

(2)可变变量:

var x = 5 // 自动推断出 `Int` 类型

x += 1

 

 

 

2.3定義變量

(1)使用条件表达式:

fun maxOf(a: Int, b: Int): Int {

    if (a > b) {

        return a

    } else {

        return b

    }

}

 

(2)使用 if 作为表达式:

fun maxOf(a: Int, b: Int) = if (a > b) a else b

 

2.4使用可空值及null檢測

(1)当某个变量的值可以为 null 的时候,必须在声明处的类型后添加 ? 来标识该引用可为空。

如果 str 的内容不是数字返回 null:

fun parseInt(str: String): Int? {

    Return (null)

}

 

2.5使用类型检测及自动类型转换

(1)is 运算符检测一个表达式是否某类型的一个实例。 如果一个不可变的局部变量或属性已经判断出 为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换:

fun getString(obj: Any): Int? {

    if (obj is String) {

        // `obj` 在该条件分支内自动转换成 `String`

        return obj.length

    }

    // 在离开类型检测分支后,`obj` 仍然是 `Any` 类型

    return null

}

 

2.6使用 for 循环

var a:IntArray= intArrayOf(1,2,6,5,4,7)

    for (item in a) {

        println(item)

    }

 

 

 

 

 

 

 

2.7使用 when 表达式

fun sum(obj: Any): String =

when (obj) {

    1          -> "One"

    "Hello"    -> "two"

    is Long    -> "Long"

    !is String -> "No string"

    else       -> "No obj"

}

 

2.8使用区间

(1)使用 in 运算符来检测某个数字是否在指定区间内:

val x = 10

val y = 9

if (x in 1..y+1) {

    println("fits in range")

}

 

(2)区间迭代

for (x in 1..5) {

    print(x)

}

 

2.9使用集合

(1)对集合进行迭代:

val items = listOf("apple", "banana", "kiwifruit")

    for (item in items) {

        println(item)

    }

(2)使用 in 运算符来判断集合内是否包含某实例:

val items = setOf("apple", "banana", "kiwifruit")

    when {

        "orange" in items -> println("juicy")

        "apple" in items -> println("apple is fine too")

    }

 

 

3.習慣用法

一些在 Kotlin 中广泛使用的语法习惯

 

3.1創建DataClass,關鍵字data

data class user(val name: String, val email: String)

 

3.2list的過濾

val positives = list.filter { x -> x > 0 }

或者還可以寫成這樣

val positives = list.filter { it > 0 }

 

3.3Map創建

val map = mapOf("a" to 1, "b" to 2, "c" to 3)

 

3.4創建單例

使用object關鍵字加函數名就可以聲明一個單例對象,object一樣可以繼承其他類或者實現接口

object Resource {

    val name = "Name"

}

 

3.5單表達式函數

fun theAnswer() = 42

等价于

fun theAnswer(): Int {

    return 42

}

单表达式函数与其它惯用法一起使用能简化代码,例如和 when 表达式一起使用:

fun transform(color: String): Int = when (color) {

    "Red" -> 0

    "white" -> 1

    "Blue" -> 2

    else -> println("no  color ")

}

 

4.類和繼承

4.1kotlin中使用關鍵字聲明類

Class A {

 

}

类声明由类名、类头(指定其类型参数、主构造函数等)以及由花括号包围的类体构成。类头与类体 都是可选的; 如果一个类没有类体,可以省略花括号。

Class A

 

4.2構造函數

在 Kotlin 中的一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数是类头的一部       分:它跟在类名(和可选的类型参数)后.

class Person constructor(firstName: String) {

}

如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。

class Person(firstName: String) {

}

 

4.3次构造函数

类也可以声明前缀有 constructor的次构造函数:

class Customer{

    constructor(name: String) {

 

    }

    constructor(name: String, age: Int) : this(name) {

 

    }

}

 

4.4创建类的实例

val invoice = Invoice()

val customer = Customer("Joe Smith")

注意 Kotlin 并没有 new 关键字。

 

 

4.5类成员

类可以包含:

构造函数和初始化块

函数

属性

嵌套类和内部类

对象声明

 

4.6繼承

在 Kotlin 中所有类都有一个共同的超类 Any,这对于没有超类型声明的类是默认超类:

class Example // 从 Any 隐式继承

注意:Any 并不是 java.lang.Object;尤其是,它除了 equals()hashCode()toString()外没有任         何成员。

 

要声明一个显式的超类型,我们把类型放到类头的冒号之后:

open class Base(p: Int)

class Derived(p: Int) : Base(p)

注意:要添加open關鍵字的類才能被繼承,在默認情況下,Kotlin中所有的類都是final

 

4.7重寫方法

與繼承一樣,需要重寫的方法也是需要加open

open class Base {

    open fun v() {}

    fun nv() {}

}

在子類上重寫的方法上需要加上override

class Derived() : Base() {

    override fun v() {}

}

注意:标记为 override 的成员本身是开放的,也就是说,它可以在子类中覆盖。如果你想禁止再次覆 盖,使用 final 关键字:

class Derived() : Base() {

    final override fun v() {}

}

 

4.6覆盖属性

属性覆盖与方法重寫类似;在超类中声明然后在派生类中重新声明的属性必须以 override 开头,并 且它们必须具有兼容的类型。每个声明的属性可以由具有初始化器的属性或者具有 getter 方法的属          性覆盖。

open class Foo {

    open val x : Int get() { …… }

}

 

class Bar1 : Foo() {

    override val x : Int = ……

}

 

也可以用一个 var 属性覆盖一个 val 属性,但反之则不行。这是允许的,因为一个 val 属性本质     上声明了一个 getter 方法,而将其覆盖为 var 只是在子类中额外声明一个 setter 方法。

注意,你可以在主构造函数中使用 override 关键字作为属性声明的一部分。

interface Foo {

    val count: Int

}

 

class Bar1(override val count: Int) : Foo

 

class Bar2 : Foo {

    override var count: Int = 0

}

 

4.7覆蓋規則

在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现, 它 必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继     承的实现,我们使用由尖括号中超类型名限定的 super,如 super<Base>:

open class A {

    open fun f() { print("A") }

    fun a() { print("a") }

}

 

interface B {

    fun f() { print("B") } // 接口成员默认就是“open”的

    fun b() { print("b") }

}

 

class C() : A(), B {

    // 编译器要求覆盖 f():

    override fun f() {

        super<A>.f() // 调用 A.f()

        super<B>.f() // 调用 B.f()

  }

}

同时继承 A 和 B 没问题,并且 a() 和 b() 也没问题因为 C 只继承了每个函数的一个实现。 但是          f() 由 C 继承了两个实现,所以我们必须在 C 中覆盖 f() 并且提供我们自己的实现来消除歧义。

 

4.8抽象類

类和其中的某些成员可以声明为 abstract。 抽象成员在本类中可以不用实现。 需要         注意的是,我    们并不需要用 open 标注一个抽象类或者函数——因为这不言而喻。

 

我们可以用一个抽象成员覆盖一个非抽象的开放成员

open class Base {

    open fun f() {}

}

 

abstract class Derived : Base() {

    override abstract fun f()

}

 

5.接口

Kotlin 的接口与 Java 8 类似,既包含抽象方法的声明,也包含实现。与抽象类不同 的是,接口无    法保存状态。它可以有属性但必须声明为抽象或提供访问器实现。

(1)使用关键字 interface 来定义接口

interface A {

    fun bar()

    fun foo() {

      // 可选的方法体

    }

}

(2)实现接口

class B : A {

    override fun bar() {

        // 方法体

    }

}

(3)接口中的属性

你可以在接口中定义属性。在接口中声明的属性要么是抽象的,要么提供访问器的实现。

interface A {

    val prop: Int // 抽象的

 

    val name: String

        get() = "name"

 

    fun foo() {

        print(prop)

    }

}

 

class B : A {

    override val prop: Int = 29

}

 

 

 

6.數據類

(1)我们经常创建一些只保存数据的类。 在这些类中,一些标准函数往往是从数据机械推导而来的。  在Kotlin 中,这叫做 数据类 并标记为 data:

data class user(val name: String, val email: String)

会为 user 类提供以下功能:

所有属性的 getters (对于 var 定义的还有 setters)

equals()

hashCode()

toString()

copy()……等等

 

为了确保生成的代码的一致性和有意义的行为,数据类必须满足以下要求:

主构造函数需要至少有一个参数;

主构造函数的所有参数需要标记为 val 或 var;

数据类不能是抽象、开放、密封或者内部的;

(在1.1之前)数据类只能实现接口。

 

(2)在类体中声明的属性

注意,对于那些自动生成的函数,编译器只使用在主构造函数内部定义的属性。如需在生成的实现中 排出一个属性,请将其声明在类体中:

data class Person(val name: String) {

    var age: Int = 0

}

 

7.泛型

(1)与 Java 类似,Kotlin 中的类也可以有类型参数:

class Box<T>(t: T) {

    var value = t

}

(2)一般来说,要创建这样类的实例,我们需要提供类型参数:

val box: Box<Int> = Box<Int>(1)

(3)但是如果类型参数可以推断出来,例如从构造函数的参数或者从其他途径,允许省略类型参数:

val box = Box(1) // 1 具有类型 Int,所以编译器知道我们说的是 Box<Int>。

 

7.1泛型函數

(1)不仅类可以有类型参数。函数也可以有。类型参数要放在函数名称之前:

fun <T> singletonList(item: T): List<T> {

    // ……

}

 

fun <T> T.basicToString() : String {  // 扩展函数

    // ……

}

 

(2)要调用泛型函数,在调用处函数名之后指定类型参数即可:

val l = singletonList<Int>(1)

或者kotlin自動識別可以寫成這樣

val l = singletonList(1)

 

8.嵌套类与内部类

(1)类可以嵌套在其他类中:

class Outer {

    private val bar: Int = 1

    class Nested {

        fun foo() = 2

    }

}

val demo = Outer.Nested().foo()

 

8.1內部類

(1)类可以标记为 inner 以便能够访问外部类的成员。内部类会带有一个对外部类的对象的引用:

class Outer {

    private val bar: Int = 1

    inner class Inner {

        fun foo() = bar

    }

}

val demo = Outer().Inner().foo()

 

9.枚举类

(1)枚举类的最基本的用法是实现类型安全的枚举:

enum class Direction {

    A, B, C, D

}

每个枚举常量都是一个对象。枚举常量用逗号分隔。

 

9.1初始化

因为每一个枚举都是枚举类的实例,所以他们可以是这样初始化过的:

 

enum class Color(val rgb: Int) {

        RED(0xFF0000),

        GREEN(0x00FF00),

        BLUE(0x0000FF)

}

 

9.2匿名類

(1)枚举常量也可以声明自己的匿名类:

enum class ProtocolState {

    WAITING {

        override fun signal() = TALKING

    },

 

    TALKING {

        override fun signal() = WAITING

    };

 

    abstract fun signal(): ProtocolState

}

及相应的方法、以及覆盖基类的方法。注意,如果枚举类定义任何成员,要使用分号将成员定义中的 枚举常量定义分隔开,就像在 Java 中一样。

 

 

PS:kotlin接口