Kotlin学习笔记之入门篇

一、基本概念

1. 函数

1.1 基本形式

fun showMessage(message: String?): Unit {

    message?.let {
        println(it)
    }
}

1.2 参数使用默认值

fun showName(name: String, age: Int = 2) : Unit {
    println("My name is $name, my age is $age years old")
}

1.3 函数返回值

fun doubleOf(number: Int): Int {
    return number + number;
}

1.4 函数简单形式

fun total(single: Double, count: Int, percent: Double) : Double = single * count * percent

1.5 中缀函数

类的成员函数, 并且参数个数为1, 调用形式比较特殊, 函数的名字需要像操作符一样放在类对象和参数的中间用空格分开: obj op arg
常用中缀函数 to, “age” to 18 结果为 Pair(“age”, 18)

infix fun Char.repeat(times: Int) = "${this}".repeat(times)

1.6 操作符函数

/// 比如定义乘法操作符 *
/// 整数 * 字符串 => 重复(整数次)输入字符串的字符串
operator fun Int.times(message: String) = message.repeat(this)

1.7 vararg参数

/// 表示数量不定的同类型参数
/// 在运行期间, vararg 标记的参数会表现为数组, 如果需要在函数内部传递给另一个vararg 参数的函数, 需要用 * 来引用
fun multiPrint(vararg messages: String) {
    for (i in messages) {
        print(i)
        print(if (i === messages.last()) "" else ", ")
    }
}

2. 常量和变量

2.1 常量的定义,

  • 使用 val 关键字, 形式: val 常量名[: 常量类型] = 常量值
    /// 定义时必须初始化, 可以通过类型推断省略常量的类型标志
    /// 常量定义后, 不可再修改常量的值, 否则编译报错
    val n: Int = 100
    val name = "God"

2.2 变量的定义

  • 使用 var 关键字, 形式: var 变量名[: 变量类型] = 初始值
    /// 变量同样在定义时必须给定初始值, 及时是可空/可选类型, 也要使用null进行初始化
    var number: String? = null
    var age: Int = 0
    var message = "Hahahaha"

2.3. 空值安全保障

  • kotlin中规定:不可以对任何类型的变量赋值为null, 如果认定为该变量可以为null, 则必须将该变量定义为可空类型, 即在原来的类型后面加上?
  • 并且可空类型的变量也不可传递到非可空类型参数的函数中
  • 如果函数的参数类型有可能为空, 则应该使用可空类型的参数
    var myName = "oyoung"
    /// myName = null // 不允许

    var yourName: String? = "Big SB"
    yourName = null

3. 类

3.1 不包含任何属性和自定义构造函数的类

class One

3.2 包含属性和自定义构造的类

class Two(val value: Int, var name: String)

fun  classUsage() {

    val one = One()
    var two = Two(0, "O")

    /// 3.3 访问类属性
    println(two.value)

    /// 3.4 修改类属性
    two.name  = "Fuck"
}

4 泛型

4.1 泛型类

class Queue<E>(vararg items: E) {
    private val children = items.toMutableList()

    fun enqueue(item: E) = children.add(item)

    fun dequeue(): E = children.removeAt(0)

    fun size() = children.size

    fun isEmpty() = children.isEmpty()
}

4.2 泛型函数

fun <E> queueOf(vararg items: E) : Queue<E> = Queue(*items)

fun queueUsage() {

    val qa = Queue(1, 2, 3, 4)
    val qb = queueOf("a", "b", "c")

    qa.enqueue(8)
    qb.dequeue()

}

5. 继承

5.1 open关键字

  • 在Kotlin里面, 所有的类默认都是final的, 即不可继承的,
  • 如果需要将某各类设计成父类,需要加上open 关键字
  • 如果需要重载父类的成员函数, 父类的函数也要加上open关键字
open class Animal {
    open fun say() {
        println("Nothing")
    }
}

open class Dog(val name: String, var age: Int): Animal() {
    override fun say() {
        println("Wow Wow, My name is $name, I'm $age years old")
    }
}

5.2 继承父类时,可以直接调用父类构造函数

class Keji: Dog("Keji", 0)

二、流程控制

1. when 语句, 加强版的 switch case

fun useWhen() {

    for (i in 0..9) println( when(i) {
        2 -> "i is 2"
        is Int -> "i is int"
        else -> "i is not 2"
    })

}

2 循环

fun useLoops() {

    println("for 循环")
    /// 2.2.1 for 循环
    for (i in 0..9) {
        print(i)
        print(if (i == 9) "" else ", ")
    }

    println()
    println("while 循环")
    /// 2.2.2 while 循环
    var i = 0
    while (i < 10) {
        print(i++)
        print(if (i == 10) "" else ", ")
    }

    println()
    println("do {} while 循环")

    /// 2.2.3 do {} while
    do {
        print(i--)
        print(if (i == 0) "" else ", ")
    } while (i > 0)


    println()
    println("迭代器循环")

    /// 2.2.4 迭代器
    /// 当集合类型重载了 iterator() 接口并返回一个 iterator时,该集合类型的对象可以直接使用 for ( in ) 循环
    /// iterator的特征是 拥有以下两个接口函数
    /// hasNext() -> Boolean
    /// next() -> E

    val list = listOf(0, 1, 2, 3, 4)

    val it = list.iterator()

    while (it.hasNext()) {
        print(it.next())
        print(if (it.hasNext() ) ", " else "")
    }

    println()

}

3. 范围

fun useRange() {

    /// 2.3.1 使用 ..
    val range1 = 0..5  // 0, 1, 2, 3, 4, 5
    /// 2.3.2 使用 .. + step
    val range2 = 0..6 step 2 // 0, 2, 4, 6
    /// 2.3.3 使用 downTo
    val range3 = 5 downTo 0 // 5, 4, 3, 2, 1, 0
    /// 2.3.4 使用 downTo + step
    val range4 = 50 downTo 0 step 10 // 50, 40, 30, 20, 10, 0

    println("Range: ")

    range1.forEach {
        print(it)
        print(if (it == range1.last) "" else ", ")
    }
    println()

    range2.forEach {
        print(it)
        print(if (it == range2.last) "" else ", ")
    }
    println()

    range3.forEach {
        print(it)
        print(if (it == range3.last) "" else ", ")
    }
    println()

    range4.forEach {
        print(it)
        print(if (it == range4.last) "" else ", ")
    }
    println()

}

4. 相等比较

fun useEquals() {

    val a = setOf(1, 2, 3)
    val b = setOf(3, 2, 1)

    /// 2.4.1 == 值比较
    println(a == b)

    /// 2.4.2 === 引用比较
    println(a === b)

}

5. 条件表达式 if else

  • kotlin 的条件表达式可以有返回值
  • 其他语言中的三目运算符 a ? b: c 在kotlin 中仍旧是 if (a) b else c
fun  useConditionExpression() {

    var  number = 9

    if (number % 2 == 0) {
        println("偶数")
    } else {
        println("奇数")
    }

    println( if(number % 3 == 0) "是3的倍数" else "不是3的倍数" )
}

三、特殊类

1. 数据类(data class)

  • 数据类表示用来存储一组相关数据,
  • 定义数据类时, kotlin会自动为定义的类生成copy方法和toString方法
data class User(var id: Int, var name: String)

fun useDataClass() {

    val xiaoming = User(0, "xiaoming")

    /// 自动生成的 toString 方法
    println(xiaoming)

    /// 自动生成的copy 方法
    val xiaoming2 = xiaoming.copy()

    println(xiaoming2)

    /// 自动生成的 copy 方法有和构造函数一样的参数列表
    val xiaohong = xiaoming.copy(1, "xiaohong")

    println(xiaohong)


    /// 自动生成的相等判断会认为 所有属性值都相等时两个对象相等
    /// 相等的 data class 对象有相同的 hashCode
    println("xiaoming hashCode: ${xiaoming.hashCode()}, xiaoming2 hashCode: ${xiaoming2.hashCode()}, xiaoming == xiaoming2 result: ${xiaoming == xiaoming2}")
    println("xiaohong hashCode: ${xiaohong.hashCode()}, xiaoming == xiaohong result: ${xiaoming == xiaohong}")


    /// 自动生成 componentN() 方法 用来获取按定义时的顺序对应的属性
    println(xiaoming.component1() == xiaoming.id)
    println(xiaoming.component2() == xiaoming.name)

}

2. 枚举类

枚举类使用关键字 enum class 定义

enum class Fruit {
    Apple, Pear, Banana
}

枚举类定义时可以带有属性, 还可以带有方法

/// 在定义方法前, 需要使用在最后一个枚举值后面加上分号(;)
enum class Color(val r: Int, val g: Int, val b: Int) {
    RED(255, 0, 0),
    GREEN(0, 255, 0),
    BLUE(0, 0, 255),
    PURPLE(255, 0, 255),
    YELLOW(255, 255, 0),
    BLACK(0, 0, 0),
    WHITE(255, 255, 255);

    fun containsRed() = this.r != 0
    fun containsBlue() = this.b != 0
}

fun  useEnumClass() {

    /// 获取枚举值
    val fruit = Fruit.Banana

    /// 当枚举类型使用when 语句时, 应该枚举出所有的值, 并且无需else 分支
    println( when(fruit) {
        Fruit.Apple -> "It's an apple"
        Fruit.Pear -> "It's a pear"
        Fruit.Banana -> "It's a banana"
    })

    val red = Color.RED;

    println(red)
    println(red.containsRed())
    println(Color.YELLOW.containsBlue())

}

3. 密封类

  • 密封类使用 sealed class 定义
  • 使用密封类时, 只能在定义密封类的同一个文件中定义其子类, 不允许文件外定义任何子类
sealed class Dog(val type: String, var name: String)

class Hashiqi(var hashiqiName: String): Dog("hashiqi", hashiqiName)
class Keji(var kejiName: String): Dog("keji", kejiName)

fun kissDog(dog: Dog): String {
    return when (dog) {
        is Hashiqi -> "kiss a Hashiqi named ${dog.hashiqiName}"
        is Keji -> "kiss a Keji named ${dog.kejiName}"
    }
}


fun  useSealedClass() {

    val dawang = Keji("Dawang")
    val xiaowang = Hashiqi("Xiaowang")

    println(dawang)

    println(xiaowang)


    println(kissDog(dawang))
    println(kissDog(xiaowang))

}

3.4 object 关键字

  • 使用 object 关键字可以随时定义一个 带有定义属性和属性值的匿名类的对象
  • 使用 class 定义的类, 在访问其属性时,需要先构造出该类的一个对象
  • 使用 object 定义的对象, 可以直接访问其属性
fun useObject( ) {

    val result = object {
        val code = 404
        val message = "Not Found"
    }

    println(result.code)
    println(result.message)

}

范围函数

/// 四、范围函数
fun main(args: Array<String>) {


    /// 4.1 let
    /// let 用来做空值检测, 使用可选值对象时非常有用

    var number: Int? = if(Math.random() < 0.5) 100 else null


    /// 当调用 let 方法的对象非空时, let 方法返回参数block 内最后一行表达式的值
    /// 否则直接返回 null
    /// 在 block 中使用 it 来引用调用对象
    val str = number?.let {
        it.toString()
    }

    println(str)

    /// 与let 相同功能的还有 run, 但是 run 方法有点不太一样, 在 block 使用 this 引用引用调用对象
    /// 这样有个好处是可以直接调用 对象的所有成员方法而不需要任何对象名前缀

    println(number?.run {
        "run: ${toString()}"
    })


    /// with 不是像 let run 一样的扩展方法, 但是也可以像run 一样针对对象来使用, 同样在 block 中可以使用 this 引用来引用 with 的参数对象

    with (number) {
        println("with: ${toString()}")
    }


    /// 还有两个比较好用的 扩展方法 apply 和 also
    /// 当调用对象非空时, 才会调用参数 block
    /// 这两个方法 都是返回调用对象本身, 不同之处是 apply 的参数block 中, 使用this 引用调用对象, 而 also 的参数block 中, 使用 it 引用调用对象

    number?.apply {
        println("apply: ${toDouble()}")
    }

    number?.also {
        println("also: $it")
    }
}

扩展 defer

class Defer {
    fun defer(block: () -> Unit) =  blocks.add(block)

    fun invokeAll() {
        while (blocks.isNotEmpty()) {
            blocks.removeAt(blocks.lastIndex)()
        }
    }
    private val blocks = mutableListOf<() -> Unit>()
}

fun  useDefer(block: Defer.() -> Unit) = Defer().apply(block).invokeAll()

fun main(args: Array<String>) {
    useDefer {
        println(1)
        defer {
            println(2)
        }

        println(3)
        defer {
            println(4)
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值