美文网首页kotlin入门学习笔记
《极客时间---快速上手Kotlin开发》学习笔记(一)

《极客时间---快速上手Kotlin开发》学习笔记(一)

作者: 青_雉 | 来源:发表于2019-11-19 10:45 被阅读0次

    kotlin 学习笔记(一)

    笔记整理至极客时间《快速上手kotlin开发》,本文整理至1~10集系列视频。

    变量声明

    //var <变量名> 类型 = ...  
    //结尾不需要分号
    var name: String = "zhangsan"
    
    //也可以利用类型自动判断,省去类型
    var name = "zhangsan"
    

    函数

    //函数写法和golang有点像,返回值在入参列表的后面
    //入参: name
    //返回值: String 类型
    //字符串拼接不需要像java里一样的String.format("hello %s", name), 和shell脚本一样,比较方便
    fun sayHello(name: String): String {
      return "hello $name"
    }
    

    类扩展

    扩展函数

    假设有自定义类在文件TeacherService.kt

    class TeacherService(private val student: Student) {
        fun sHello() {
            student.hello()
        }
    }
    

    下面针对这个类进行扩展 e.kt

    public fun TeacherService.getStudentName():String  = "hello"
    
    public fun TeacherService.fuza(name: String = "haha"):String {
        return name
    }
    

    可进行如下测试

    var ts = TeacherService(Student())
    ts.sHello()
    
    println(ts.getStudentName())
    println(ts.fuza())
    

    下面针对jdk标准类库进行扩展

    fun <T> Collection<T>.joinToString(
            separator: String = ",",
            prefix: String = "",
            postfix: String = ""
    ): String{
        val result = StringBuilder(prefix)
        for ((index, value) in this.withIndex()) {
            if (index > 0) {
                result.append(separator)
            }
            result.append(value)
        }
        result.append(postfix)
        return result.toString()
    }
    

    测试

    println(listOf("a", "b", "c").joinToString(prefix = "[", postfix = "]"))
    

    kotlin里,针对jdk的许多标准库进行了函数扩展,比如 FileReadWrite.kt

    当然扩展函数,只是相当于在扩展类里面添加的静态方法,如果用java代码进行调用,就没什么黑魔法了

    TeacherService ts = new TeacherService(new Student());
    ts.sHello();
    EKt.getStudentName(ts);
    
    扩展属性

    相关文档里讲,属性也是可以扩展的,但是研究了一下,有一点不明白属性扩展能做啥

    var String.s: Int
    get() = this.length
    set(value){
      //set方法并没有field可以用来存储value,
      //其实际作用是使用通过value来操作调用者,即this
      println(this.plus(value))
    }
    

    Lambda 闭包

    var hello = {s: String -> println(s)}
    fun main(args: Array<String>) {
        hello("hah")
    }
    

    最基本的lambda写法

    fun main(args: Array<String>) {
        val thread = Thread({ -> Unit })
        thread.start()
    }
    

    如果没有参数,可以省略箭头符号 ->

    fun main(args: Array<String>) {
        val thread = Thread({ })
        thread.start()
    }
    

    如果lambda是函数的最后一个参数,可以将大括号放在小括号外部

    fun main(args: Array<String>) {
        val thread = Thread(){}
        thread.start()
    }
    

    如果函数只有一个参数切这个参数是lambda,可以省略小括号

    fun main(args: Array<String>) {
        val thread = Thread{}
        thread.start()
    }
    

    为什么在lambda上玩出这么多花头精?因为想支持函数式编程,必须要简洁,java原生的匿名内部类写法太过臃肿,java8之后出的lambda有一些改善,kotlin在此基础上进行更加好的改善。

    为什么要匿名内部类?主要在两个领域会经常用到匿名内部类

    • 移动端开发,各种注册listener
    • 异步编程,各种回调函数

    java或者说jvm体系,没有函数的概念,只有方法, 想要支持函数式编程,jvm体系上,基本上是基于匿名内部类来实现的,kotlin里在kotlin.jvm.functions包里内置了很多的Function接口,无非是让人感觉是在写函数。

    高阶函数

    传入函数

    把函数传给函数(jvm层面,无非是把一个对象传给一个函数,实现一种回调的效果)

    fun main(args: Array<String>) {
        onlyif(true) {
            println("ddd")
        }
    }
    
    fun onlyif(isDebug: Boolean, block: () -> Unit){
        if(isDebug) block()
    }
    

    所以,如果大量使用高阶函数,就会造成大量的临时对象产生(没有追求性能极致,貌似也没什么问题),所以kotlin里发明了inline 关键字。

    返回函数

    (想起了早些年写的js,记得js里为了实现某一种封装,是通过返回一个函数来实现的)

    fun main(args: Array<String>) {
        println(doSth()())
    }
    
    fun doSth(): () -> String {
        var name = "xiaoming"
        return {name}
    }
    

    构造函数

    定义父类和接口

    //open 的类才能被继承
    open class Person {
        //open的方法才能被覆盖
        open fun sayHi(){
            println("hello")
        }
    }
    
    interface Runer {
        fun run()
    }
    

    实现父类和接口

    class Student(var name: String) : Person(), Runer {
        //构造函数执行的时候,init代码块里的代码将被执行(不管是主构造函数还是次级构造函数)
        init {
            println(name)
        }
    
        //主构造函数的name,不需要额外声明;次级构造函数的参数需要额外声明
        var age: Int = 0
    
        /**
         * 次级构造函数必须直接或间接的继承主构造函数或父级构造函数
         */
        constructor(name: String, age: Int) : this(name) {
            this.age = age
        }
    
        //覆盖父类的方法,必须带override关键字
        override fun sayHi() {
            println("hi I'm $name, I'm $age years old")
        }
    
        override fun run() {
    //        TODO("not implemented") 这个TODO是可以编译通过的,运行时报错
            println("student run")
        }
    }
    

    伴生对象

    静态工具类

    //通过伴生对象来做
    class StringUtils {
        companion object {
            fun isEmpty(str: String) : Boolean {
                return "" == str
            }
        }
    }
    
    //通过jvmStatic注解来做
    object XXUtils {
        @JvmStatic
        fun isBlank(str: String) : Boolean {
            return "" == str
        }
    }
    
    fun main(args: Array<String>) {
        println(StringUtils.isEmpty(""))
        println(XXUtils.isBlank("abc"))
    }
    

    单例

    class Student private constructor() {
    
        companion object {
            fun get() :Student {
                return Holder.instance
            }
        }
    
        private object Holder {
            var instance: Student = Student()
        }
    
    }
    
    fun main(args: Array<String>) {
        println(Student.get())
        println(Student.get())
    }
    

    关于object的修饰符

    • object修饰一种特殊的类,类里的属性和方法都是静态的
    • 如果object放在一个类的内部,那就是一个静态内部类,除非用inner修饰
    • 参考

    参考文档

    https://www.jianshu.com/p/7291c9a1ec1e

    相关文章

      网友评论

        本文标题:《极客时间---快速上手Kotlin开发》学习笔记(一)

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