Kotlin编程权威指南学习知识点预览

news2025/3/10 18:31:53

一、变量、常量和类型:

        变量、常量以及 Kotlin 基本数据类型。变量常量在 应用程序中可用来储值和传递数据。类型则用来描述常量或变量中保存的是什么样的数据。    

        1、声明变量:

// 变量定义关键字 —— 变量名 —— 类型定义 —— 赋值运算符 —— 赋值
    var name : Int = 5

        2 、Kotlin的内置数据类型:

        3、只读变量:

                Kotlin 提供了一种语法来声明只读变量,也就是说,变量一旦赋值就不能更改。

                要声明可修改变量,使用 var 关键字。要声明只读变量,使用 val 关键字。

         4、类型推断:

                Kotlin 有个语言特性叫类型推断,对 于已声明并赋值的变量,它允许你省略类型定义。

var age = 5
val fristName = "Everbrilliant89"

          5、编译时常量: 

               编译时常量只能在函数(指包括 main 在内的所有函数)之外定义。这是因为,编译时常量必须在编译时(程序编译时)赋值,而 main 和其他函数都是在运行时(程序运行时)才调用, 函数内的变量也是在那时赋值。编译时常量要在这些变量赋值前就已存在。

const val MAX_VALUE = 5000

          

二、条件语句:

        1、if/else语句:

        2、range :

                在 in 1..5 中,..是一种操作符,表示某个范围(range)。范围包括从..操作符左侧的值到..操作符右侧值的一系列值。所以,1..5 包括 12345。除了数字,范围也可以是一 系列字符。

        3、when表达式:

                when 表达式是 Kotlin 的另一个控制流工具。类似于 if/else 语句,when 表达式允许你编写条件式,在某个条件满足时,就执行对应的代码。它的语法比较简洁,非常适合有三到四个分支 的情况。

 fun demoFunc() {
        val faction = when(race) {
            "dwarf" -> "Keepers of the Mines"
            "gnome" -> "Keepers of the Mines"
            "orc" -> "Free People of the Rolling Hills"
            "human" -> "Free People of the Rolling Hills"
            else -> "noName"
        }
    }

三、函数:

        函数是能完成某项特定任务的可复用代码块,是编程非常重要的一部分。

        1、函数结构的剖析:

                一个函数的两个主要部分:函数头和函数体。

 

        2、函数头:

       

  • 修饰符:private、public、protected
  • 函数声明关键字:fun
  • 函数名:
  • 函数参数:函数参数总是只读的,你不能在函数体内再给它们赋值。
  • 函数返回类型

         3、函数的作用域:

         4、默认值参数: 

                参数列表中可以给参数赋值默认的值。

 private fun castFirebal(numFireballs: Int = 2) {
      println("A glass of Fireball springs into existence. (x$numFireballs)")
    }

          5、 单表达式函数:

                 函数都只有一个表达式语句,或者说都只有一条求 值语句。Kotlin 提供了更简单的方式来定义这类函数,对于这类单表达式函 数,返回类型、花括号、返回语句都可以省掉。

   

private fun castFirebal(numFireballs: Int = 2) 
    = println("A glass of Fireball springs into existence. (x$numFireballs)")

             6、具名函数参数:   

        castFirebal(5)
        //具名函数
        castFirebal(numFireballs = 6)

             7、Unit函数:

                Kotlin 使用 Unit 返回类型表明这样一件事:函数没有返回值。函数定义 中如果没使用 return 关键字,那暗含的意思就是,Unit 就是这个函数的返回类型。

             8、Nothing类型: 

                Kotlin 还有一种叫作 Nothing 的类型。类似于 UnitNothing 类型的函数也不返回任何东 西。但这是它们唯一相同的地方。在编译器看来,Nothing 就意味着函数不可能成功执行完成, 它要么抛出异常,要么因某个原因再也返不回调用处。

             9、Java中的文件级函数:

                 Java 中,函数和变量都只能定义在类里,但 Kotlin 没有这样 的要求。

            10、函数重载:

                如果一个函数有多种实现,就可以说它被重载了。默认值参并 不是重载的唯一方式。你可以用相同的函数名定义多个实现。

             11、反引号中的函数名:

                定义或调用以空格和其他特殊字符命名的函数,不过,函数名要用一对反引号括起来。首先是支持 Java 互操作。Kotlin 提供了很多便利的工具,支持在 Kotlin 文件中调用现有 Java 代码的方法(Kotlin Java 的互操作详见第 20 章)。Kotlin Java 各自有不同的保留关键字,不 能用作函数名。使用反引号括住函数名就能避免任何潜在冲突。

                在 Kotlin 中,is 是个保留关键字(你会在第 14 章中看到,Kotlin 的标准库有个 is 操作符, 可以用来检查实例类型)。而在 Java 中,is 不是关键字,所以是有效的方法名。有了反引号,就 可以在 Kotlin 中调用 Java is 方法了。

          

四、匿名函数与函数类型:

                定义时不取名字的函数,我们称之为匿名函数。匿名 函数和具名函数既相似又不同。明显的不同之处有两个:匿名函数的定义中没有名字;和其他代码交互的方式有点特别。匿名函数通常整体传递给其他函数,或者从其他函数返回。这种交互主 要靠函数类型函数参数实现。

            1、匿名函数:

                    把一个匿名函数作为参数传递给 count 函数: 

    val numLetters = "guangdongshenzhen".count({
        letters -> letters == 's'
    })
    //匿名函数作为参数传入函数count
    val numLetters1 = "guangdongshenzhen".count { letters ->
        letters == 's'
    }

    //count函数在源码中的定义
    public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int {
        var count = 0
        for (element in this) if (predicate(element)) ++count
        return count
    }

  • 函数类型:匿名函数也有类型,我们称其为函数类型(function type)。匿名函数可以当作变量值赋给函数类型变量。然后,就像其他量一 样,匿名函数就可以在代码里传递了      
    //匿名函数赋值给变量
    //: () -> String 表示变量存储的是哪种类型的函数
    // () -> String 是你给 greetingFunction 变量指定的函数类型定义
    val greetingFunction :() -> String = {
        val currentYear = 2018
        "Welcome to SimVillage, Mayor! (copyright $currentYear)"
    }
  • 隐式返回:和具名函数不一样,除了极少数的情况外,匿名函数不需要 return 关键字来返回数据。没有 return 关键字,为了返回数据,匿名函数会隐式或自动返回函数体最后一行语句的结果。
  • 函数参数:需要带参数时,参数的类型放在匿名函数的类型定义中,参数名则放在函数定义中。
    val greetingFunction :(String) -> String = { youName ->
        "你好,我的名字叫: $youName)"
    }
  • it关键字:定义只有一个参数的匿名函数时,可以使用 it 关键字来表示参数名。当你有一个只有一个参数的匿名函数时,it和命名参数都有效。 
    val greetingFunction :(String) -> String = { 
        "你好我的名字叫: $it)"
    }
  •  多个参数:it 关键字语法只适用于一个参数的情况。匿名函数支持多个参数。如果有多个参数,需要使用命名参数。   
     val greetingFunction :(String,Int) -> String = {myName,age ->
        "你好我的名字叫: $myName" + ",今年:$age 岁了"
    }

        2.类型推断:

        定义一个变量 时,如果已把匿名函数作为变量值赋给它,就不需要显式指明变量类型了。类型推断也支持带参数的匿名函数,但为了帮助编译器更准确地推断变量类型,匿名函数的 参数名和参数类型必须有。    

    val greetingFunction = {
        myName:String,age:Int ->
        "你好我的名字叫: $myName" + ",今年:$age 岁了"
    }

       3、定义参数是函数的函数:

         函数支持包括函数在内的任何类型的参数。一个函数类型的参数定义起来和其他类型的参数 一样:在函数名后的一对圆括号内列出,再加上类型。

    val greetingFunction = {
        myName:String,age:Int ->
        "你好我的名字叫: $myName" + ",今年:$age 岁了"
    }

    fun runSimulation(name :String ,greegreetingFunction :(String,Int) -> String) {
        var age = 18
        println(greetingFunction(name, age))
    }

        4、函数内联:

                Kotlin 有一种优化机制叫内联,可以解决 lambda 引起的内存开销问题。有了内联,JVM 就不需要使用 lambda 对象实例了,因而避免了变量内存分配。为了使用内联方法优化 lambda,以 inline 关键字标记使用 lambda 的函数即可。

    inline fun runSimulation(name :String 
            ,greegreetingFunction :(String,Int) -> String) {
        var age = 18
        println(greetingFunction(name, age))
    }

         5、函数引用:

           函数引用可以把一个具名函数(使用 fun 关键字定义的函数)转换成一个值参。要获得函数引用,使用::操作符,后跟要引用的函数名。     

    protected fun demoFunc() {
        runSimulation("WY",::costPrinter)
    }
    private fun runSimulation(name: String, costPrinter: KFunction1<Int, Unit>) {
    }
    fun costPrinter(num :Int) {
        val cost = 400
        println("construction cost: ${cost * num}")
    }

        6、函数类型作为返回类型:

        和其他数据类型一样,函数类型也是有效的返回类型,也就是说,你可以定义一个能返回函 数的函数。

       

五、null安全与异常:

        null 是个特殊值,用来表明 var val 变量的值不存在。包括 Java 在内的许多编程语言中, null 常常会导致应用崩溃,因为让不存在的东西做事情是不可能的。如果一个 var val 变量能 接受 null 值,Kotlin 需要你做个特别声明。这有助于避免 null 相关的应用崩溃。

        1、可空性:

         对于 null 值问题,Kotlin 反其道而行之。除非另有规定,变量不可为 null 值。

        2、Kotlin的null类型:

    protected fun demoFunc() {
        var beverage = readLine()
        beverage = null // 如返回值不是String?而是String则赋值为null则报错
    }
    //String?表示可空String的类型
    private fun readLine(): String? {
        return "nihao"
    }

        3、null安全:

         Kotlin 区分可空类型和非可空类型,所以,你要一个可空类型变量做事,而它又可能不存在,对于这种潜在危险,编译器时刻警惕着。为了应对这种风险,Kotlin 不允许你在可空类型值上调用函数,除非你主动接手安全管理。

  • 安全调用操作符(?.):不确定会不会返回null,此时可选择使用安全调用操作符;
    var beverage = readLine()?.capitalize()
  • 使用带let的安全调用:主要作用是在指定的作用域内定义一个或多个变量。
      var beverage = readLine()?.let { 
            if (it.isNotBlank()) {
                it.capitalize()
            } else {
                "isBlank"
            }
        }
  • 使用!!.操作符:!!.操作符也能用来在可空类型上调用函数。但我要给你个警告:相比安全调用操作符,!!.操作符太激进,一般应该避免使用。视觉上看,代码中的!!.操作符也给人语气很重的感觉,因为它真的很危险。如果你用了!!.,就是在向编译器宣布:“万一我使唤干活的东不存在,我要求你立刻抛出空指针异常!!”(顺便提一下,!!.的官方名字是非空断言操作符但开发人员更喜欢叫它“感叹号操作符”。)
    var beverage = readLine()!!.length
  • 使用if判断null值情况;
  • 使用空合并操作符号:另一种检查 null 值的方式是使用 Kotlin 空合并操作符?:
        var beverage = readLine()
        val beverageServed:String = beverage ?: "Buttered Ale"

        4、异常:

  • 抛出异常:Kotlin 允许你主动示意有异常发生。这种行为又叫抛出一个异常,由throw 操作符触发。
  • 自定义异常:
  • 异常处理:try/catch 语句,Kotlin 可以让你决定如何来处理异常。

         5、先决条件函数:

  

六、字符串:

        1、字符串截取:

  • substring:   
  • split:  

        2、字符串操作:

  • replace函数:

        3、字符串比较:

        引用相等比较很少用于比较字符串。一般来说,相比关心两个字符串是不是同一实例,我们
更关心它们是不是相等字符,以及顺序是否一致(或者说两个不同的类实例是否结构相同)。
        就比较字符串来说,== 操作符的行为方式和 Kotlin 不 一样,Java 用== 做引用比较。要在 Java 中做结构相等比较,要用 equals 函数。

        4、遍历字符:

  •   forEach函数

七、数:

        1、数字类型:

        

         2、整数(Int):

         3、小数数字(Float或Double):

         4、字符串转数值类型:

  • toFloat:
  • toDouble:
  • toDoubleOrNull:安全转换函数
  • toIntOrNull:
  • toLong:
  • toBigDecimal

       5、Double类型格式化:

    "%.2f".format("2.6666666")

        6、位运算:

八、标准库函数:

        1、apply标准函数:

        apply 函数可看作一个配置函数:你可以传入一个接收者,然后调用一系列函数来配置它以便使用。如果提供 lambda apply 函数执行,它会返回配置好的接收者。

    val menuFile = File("1.txt")
        menuFile.setReadable(true)
        menuFile.setWritable(true)
        menuFile.setExecutable(true)
        
        val menuFile2 = File("2.txt").apply { 
            setReadable(true)
            setWritable(true)
            setExecutable(true)
        }

        2、let函数:

        let 函数能使某个变量作用于其 lambda 表 达式里,让 it 关键字能引用它。

        3、run函数:

        run 和 apply 差不多。但与 apply 不同,run 函数不返回接收者。

        val menuFile3 = File("3.txt")
        menuFile3.run { 
            readText().contains("ss")
        }

         4、with函数:

        with函数是run的变体。它们的功能行为是一样的,但 with 的调用方式不同。调用 with 时需要值参作为其第一个参数传入。 

        val nameTooLong = with("Polarcubis, Supreme Master of NyetHack") { 
             length >= 20 
            }

         5、also函数:

            also 函数和 let 函数功能相似。和 let 一样,also 也是把接收者作为值参传给 lambda。但 有一点不同;also 返回接收者对象,而 let 返回 lambda 结果。

        6、takeIf函数:

        takeIf 函数需要判断 lambda 中提供的条件表达式(叫 predicate),给出 true false 结果。如果判断结果是 true,从 takeIf 函数返回接收者对象;如果是 false,则返回 null

        val menuFile4 = File("4.txt")
            .takeIf { 
                it.canRead() && it.canWrite() 
            } ?.readText()

九、List与set:

        1、List:

  •  获取列表元素:用元素的索引(index)和[]操作符可以获取列表中的任意元素。列表中的元素基于零索引(zero-indexed存放。
    private fun printList() {
        val patronList = listOf<String>("wangwu","lisan")
        var name =patronList[0];
        val contains = patronList.contains("zhangsan")
    }
  • 更改列表内容:列表可变性是由列表的类型决定的,指的是列表元素是否可修改。支持内容修改的列表叫可变列表(mutable list)。要创建可变列表,可以使用 mutableListOf 函数。
    private fun printMutableList() {
        val mutableList = mutableListOf("wangwu","lisan")
        mutableList.add("张三")
        mutableList.remove("lisan")
    }

        2、遍历:

        在 for 循环里,in 指定将要被遍历的对象。也可以forEach和forEachIndexed,,或Iterable去遍历。

      private fun forList() {
        val mutableList = mutableListOf("wangwu","lisan")
        for (forList in mutableList) {

        }

        mutableList.forEach { name ->
            print("名字是 $name")
        }

        mutableList.forEachIndexed { index, name ->
            print("序列号为:$index ===名字是 $name")
        }
    }

        3、解构:

        通过使用_符号过滤不想要的元素,你还可以有选择地从 List 集合里解构元素。

        4、set:

       Set 集合里的所有元素都具有唯一性;Set 集合不支持基于索引的存取值函数,因为它里面的元素顺序不固定。

  • 创建Set集合:
    private fun showSet() {
        val nameSet = setOf<String>("wangwu","lisan")
        nameSet.contains("zhangsan")
        //索引值读取 Set 集合的元素虽然可行,但因为 elementAt 函数内部实现机制的问题,
        //相比按索引读取 List 集合的元素,读取速度要慢上一个数量级
        nameSet.elementAt(2)   
        
    }
  •  向Set集合中添加元素:

      5、while循环:

        当某个条件满足时,就执行循环体里的代码。

      6、break表达式:

      7、数组类型:

    val playerAges:IntArray = intArrayOf(25,23,5,9,48)

      

十、Map:

        与 List Set 类型不同的是,Map 里的元素是由你定义的键值对组成的,获取元素的方式 是基于键,而不是基于索引。在 Map 里,键具有唯一性,它对应一个具体的值。值则可以重复, 没有唯一性要求。从这个角度看,Map Set 有了另一个共同点:就像 Set 里的元素一样,Map里的键都是唯一的。

        1、创建map

        Map 集合里,键必须是同一类型,值也必须是同一类型,而键和值可以是不同类型。

        to 函数将它左边和右边的值转化成一个对(Pair)——一种表示两个元素一组(键和值)的特 殊类型。

    private fun showMap() {
        val patronGold = mapOf(
            Pair("wangwu",15),
            Pair("lisi",18),
            Pair("wangmuzi",16)
        )
        val patronGold1 = mapOf("wangwu" to 15,"lisi" to 18)
    }

        2、读取Map集合的值:

    private fun printMap() {
        val patronGold = mapOf("wangwu" to 15,"lisi" to 18)
        val gold = patronGold["wangwu"]
        val lisiGold = patronGold.getValue("lisi")
    }

        3、向Map集合添加项:

     private fun putMutableMap() {
        val mutableMap = mutableMapOf("wangwu" to 15,"lisi" to 18)
        mutableMap.put("wangyi",88)
    }

        4、修改Map集合值:

    private fun modifyMutableMap() {
        val mutableMap = mutableMapOf("wangwu" to 15,"lisi" to 18)
        mutableMap["wangwu"] = 66
    }

              

十一、定义类:

        在面向对象编程的世界里,类是核心,是一类独特“事 物”的代码形式的定义。具体来讲,类定义的是事物包含哪一类数据,能做什么样的工作。

        1、定义类:

        类可以定义在一个独立的文件中,也可以和函数或变量定义在一起。类定义在单独一个文件 里,可以给应用程序未来的规模升级预留扩展空间。

        2、构造实例:

        构造函数的工作就是构造,说得再具体一点,就是构造一个实例以备后用。调用构造函数和调用一般函数在语法上很像:使用一对圆括号接收值参。

        3、类函数:

       定义类行为就是在类结构体里添加函数定义。定义在类里的函数叫类函数

        4、可见性与封装:

        

        5、类属性:

        类数据定义,又叫作类属性,用来描述类的特有状态和特征。

  • 属性getter与setter;
  • 属性可见性;
  • 计算属性。

        

十二、初始化:

        调用一个类的构造函数,创建了该类的一个实例。这个过程叫实例化。给对象分配内存就是实例化对象,给对象赋值就是初始化对象。

        1、构造函数:

var name: String = ""
var heealthPoints: Int = 0
var isBlessed: Boolean = false
var isImmortal: Boolean = false
class Player (_name: String,
                 _healthPoints: Int,
                 _isBlessed: Boolean,
                 _isImmortal: Boolean){
        var name = _name
            get() = field.capitalize()
            private set(value) {
                field = value.trim()
            }
        var healthPoints = _healthPoints
        val isBlessed = _isBlessed
        private val isImmortal = _isImmortal
}

//调用
val player = Player("Madrigal", 89, true, false)

        2、次构造函数:

        有主就有次,对应主构造函数的是次构造函数。如果你为某个类指定了主构造函数,那么该 类的所有实例都要用它构造。如果你指定了一个次构造函数,那只是多了一种构造类实例的方式 (主构造函数的要求仍要满足)。 

class Player (_name: String){
        var name = _name
        var age :Int = 0
    //这里 this 关键字指的是构造函数所在的类实例。
    constructor(_name :String ,_age :Int) :this(_name) {
        name = _name
        age = _age
    }
}

        3、默认参数:

class Player (_name: String,_age :Int =18){
        var name = _name
        var age :Int = 0
        lateinit var adrr :String
    //age为默认参数可实现
    constructor(_name :String ,_age :Int, _adrr :String) :this(_name,_age) {
        name = _name
        age = _age
        adrr = _adrr
    }
    //age为默认参数也不可实现
    constructor(_name :String , _adrr :String) :this(_name) {
        name = _name
        adrr = _adrr
    }
}

         4、初始化块:

        初始化块代码会在构造类实例时执行,类似于Java中的static初始化块。用关键字init定义一个初始化块。

        5、初始化顺序:

  • 主构造函数里声明的属性;
  • 类级别的属性赋值;
  • init 初始化块里的属性赋值和函数调用;
  • 次构造函数里的属性赋值和函数调用;

        6、延迟初始化:

  • 延迟初始化:对于任何 var 属性声明,你都可以加上 lateinit 关键字。这样, Kotlin 编译器会允许你延后初始化属性。
  • 惰性初始化:可以暂时不初始化某个变量,直到首次使用它。使用代理要用到 by 关键字。Kotlin 标准库里有一些预先配置好的代理可用,lazy 就是其中一个。惰性初始化会用到 lambda 表达式,你可以在表达式里定义属性初始化需要执行的代码。

十三、继承:

        1、创建子类

        子类继承哪个类,就会共享哪个类的全部属性。让子类继承的类通常叫作父类或超类

        事实上,类默认都是封闭的,也就是说不允许其他类来继承自己。要让某个类开放继承,必须使用 open 关键字修饰它。

/该类可被继承必须加上open
open class Player (_name: String,_age :Int =18){
        var name = _name
        var age :Int = 0
        lateinit var adrr :String
    //age为默认参数可实现
    constructor(_name :String ,_age :Int, _adrr :String) :this(_name,_age) {
        name = _name
        age = _age
        adrr = _adrr
    }
    //age为默认参数也不可实现
    constructor(_name :String , _adrr :String) :this(_name) {
        name = _name
        adrr = _adrr
    }

    //可重新函数必须加上open
    open fun showName() {

    }
    //要想某个函数不被子类覆盖,就使用 final 关键字修饰它
    final fun showPassdWord() {

    }

}


class MyPlayer(_name: String, _age: Int) : Player(_name) {


    override fun showName() {

    }
}

         2、类型检查:

        Kotlin 的 is 运算符是个不错的工具,可以用来检查某个对象的类型。

        3、Kotlin类层次:

        每一个类都会继承一个共同的叫作 Any 的超类。

        

package kotlin

public open class Any {
    
    public open operator fun equals(other: Any?): Boolean

    public open fun hashCode(): Int

    public open fun toString(): String
}

十四、对象:

        1、object:

        如果只想用一个实例来管理整个应用运行时间内的一致性状态的话,可以考虑定义一个单例
singleton )。使用 object 关键字,你可以定义一个只能产生一个实例的类——单例。单例类一
旦实例化,在整个应用的运行周期内,只会存在一个实例。即使你再次实例化它,你得到的还是
最初产生的实例。

        使用 object 关键字有三种方式:对象声明object declaration)、对象表达式object expression和伴生对象companion object)。

  • 对象声明:
object open class MyPlayer(_name: String, _age: Int) : Player(_name) {
    
    init {
        
    }
    override fun showName() {


    }
}
  • 对象表达式:这个匿名类依然遵循 object 关键字的一个规则,即一旦实例化,该匿名类只能有唯一一个实例存在。
  val signalPlayer = object : MyPlayer("",5) {
            override fun showName() {
                super.showName()
            }
        }

伴生对象:将某个对象的初始化和一个类实例捆绑在一起,可以考虑使用伴生对象。使用 companion 修饰符,你可以在一个类定义里声明一个伴生对象。一个类里只能有一个伴生对象。第一种,包含伴生对象的类初始化时,伴生对象就会被初始

化。由于这种相伴关系,伴生对象就适合用来存放和类定义有上下文关系的单例数据。第二种,只要直接访问伴生对象的某个属性或函数,就会触发伴生对象的初始化。
open class MyPlayer(_name: String, _age: Int) : Player(_name) {

    //类似于Java中的static方法
     companion object {
         private const val MAPS_FILEPATH = "nyethack.maps"
         fun load() = File(MAPS_FILEPATH).readBytes()
     }
}
//直接调用
 MyPlayer.load()

        2、嵌套类:

        可以使用 class 关键字定义一个嵌套在另一个类里的命名类。

        3、数据类:

  • 数据类必须有至少带一个参数的主构造函数;
  • 数据类主构造函数的参数必须是 val var

    数据类不能使用 abstractopensealed inner 修饰符。

    4、枚举类:

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

    5、运算符重载:

    data class Coordinate(val x: Int, val y: Int) { 
     val isInBounds = x >= 0 && y >= 0 
     operator fun plus(other: Coordinate) = Coordinate(x + other.x, y + other.y) 
    }

十五、接口与抽象类:

       接口可以用来定义一组未实现的公共属性和行为。具体如何实现,开发者不用管,实现接口 的类会负责处理。类之间想要共享属性或函数,但又无法建立继承关系时,就非常适合使用这种 只定义而不实现的接口特性。也就是说,通过使用接口,无须继承或被继承,一组类就可以拥有 共同的属性和函数。

        1、定义接口:

interface Fightable { 
 var healthPoints: Int 
 val diceCount: Int 
 val diceSides: Int 
 val damageRoll: Int 
 fun attack(opponent: Fightable): Int 
}

        2、实现接口:

open class MyPlayer(_name: String, _age: Int,
                    override var healthPoints: Int,
                    override val diceCount: Int,
                    override val diceSides: Int,
                    override val damageRoll: Int
)  : Fightable{
    override fun attack(opponent: Fightable): Int {
        TODO("Not yet implemented")
    }


}

         3、默认实现:

        不是每个属性和函数都需要在接口实现类里提供不同的具体实现。所以,接口里提供默认实
现可以减少重复代码。

         4、抽象类:

        在类定义之前加上 abstract 关键字。除了具体的函数实现,抽象类也可以包含抽象函数——只有定义,没有函数实现。

abstract class MyPlayer(_name: String, _age: Int,
                    override var healthPoints: Int,
                    override val diceCount: Int,
                    override val diceSides: Int,
                    override val damageRoll: Int
)  : Fightable{
   
    
}

       不管超类是哪种类型的类(一般类、抽象类或接口),子类默认都会共享其超类的所有属性 和函数。如果一个类实现了一个接口,那么它的子类也必须满足这个接口的所有实现需求。

      首先,接口里不能定义构造函数。其次,一个类只能继承一个抽象类,但可以实现多个接口。  

open class MyPlayer(
    _name: String, _age: Int,
    override var healthPoints: Int,
    override val diceCount: Int,
    override val diceSides: Int,
    override val damageRoll: Int
) : Player(_name), Fightable {
     override fun attack(opponent: Fightable): Int {
         TODO("Not yet implemented")
     }
     
 }

十六、泛型:

        泛型系统允许函数和其他类型接受 你或编译器当前无法预知的类型,大大提高了代码的复用率。

        1、泛型类:   

class LootBox<T>(item: T) { 
 private var loot: T = item 
}

        2、泛型函数:

class LootBox<T>(item: T) { 
 var open = false 
 private var loot: T = item 

//定义的名为 fetch 的泛型函数会返回 T,这是 LootBox 类指定的泛型参数,
//也是代表 item类型的占位符。
 fun fetch(): T? { 
 return loot.takeIf { open } 
 } 
}

         3、多泛型参数: 

class LootBox<T>(item: T) { 
 var open = false 
 private var loot: T = item 
 fun fetch(): T? { 
 return loot.takeIf { open } 
 } 
//R这个泛型参数将用作 fetch 函数的返回类型
//定义时,这个 R 泛型参数要放在尖括号里,置于函数名之前:fun <R> fetch。
//fetch 返回的是一个 R?,即一个可空的 R 类型。
//由于函数类型声明(T) -> R,lootModFunction 函数能接受 T 类型的值参,返回一
//个 R 类型的结果值
 fun <R> fetch(lootModFunction: (T) -> R): R? { 
 return lootModFunction(loot).takeIf { open } 
 } 
}

         4、vararg关键字与get函数:

        这个 vararg 关键字,初始化 泛型类时,就能把它的 item 变量看作元素数组, 而非单个元素了。

        5、in与out:

        泛型参数可以扮演两种角色:生产者producer)或消费者consumer)。生产者 角色就意味着泛型参数可读而不可写;消费者角色则相反,可写而不可读。

        out 关键字表明,泛型参数将扮演可读而不可写的生产者角色。

        6、reified关键字:

        reified关键字能帮你检查泛型参数类型。Kotlin 提供了 reified 关键字,它允许你在运行时保留类型信息。

        

十七、扩展:

        扩展可以在不直接修改类定义的情况下增加类功能。扩展可以用于自定义类。

       1、定义扩展函数:

         定义扩展函数和定义一般函数差不多,但有一点大不一样:除了函数定义,你还需要指定接
受功能扩展的 接收者类型 receiver type )。
        
//this 的内容加上传入值参决定
//的一个或多个感叹号(默认值是 1)。this 关键字指接收者实例
fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount)

        2、超类上定义在扩展函数:

//在 Any 类上定义一个叫 easyPrint 的扩展函数。因为是定义在 Any 超类上的
//,所以 easyPrint支持在任何类上调用。
fun Any.easyPrint() = println(this)

        3、泛型扩展函数:     

//let 函数被定义成了泛型扩展函数,所以能支持任何类型。它接受一个 lambda 表达式,这个
//lambda 表达式以接收者 T 作为值参,返回的是 R——lambda 表达式返回的任何新类型。
public inline fun <T, R> T.let(block: (T) -> R): R { 
 return block(this) 
}

        4、扩展属性:

        

        5、可空类扩展:

        

        6、定义扩展文件:

        7、重命名扩展:

          

十八、函数式编程基础:

        函数式编程范式主要依赖于高阶函数(以函数为参数或返回函数)返回的数据。这些高阶函 数专用于处理各种集合,可方便地联合多个同类函数构建链式操作以创建复杂的计算行为。

        1、函数类别:

  • 变换:变换函数会遍历集合内容,用一个以值参形式传入的变换器函数变换每一个元素,然后返回包含已修改元素的集合给链上的其他函数。
        val animal = listOf("zebra", "giaffe", "elephant", "rat")
        val babies = animal
            .map { animal -> "A baby $animal" }
            .map { baby -> "$baby, with the cutest little tail ever!" }
        println(babies)
  •  过滤:过滤函数接受一个 predicate 函数,用它按给定条件检查接收者集合里的元素并给出 true 或 false 的判定。如果 predicate 函数返回 true,受检元素就会添加到过滤函数返回的新集合里。如果 predicate 函数返回 false,那么受检元素就被移出新集合。
        val itemsOfManyColors = listOf(listOf("red apple", "green apple", "blue apple"),
            listOf("red fish", "blue fish"), listOf("yellow banana", "teal banana"))

        val redItem = itemsOfManyColors.flatMap {
            it.filter {
                it.contains("rea")
            }
        }
        println(redItem)
  • 合并: 合并函数能将不同的集合合并成一个新集合:
        val employees = listOf("Denny", "Claudette", "Peter")
        val shirtSize = listOf("large", "x-large", "medium")
        val employeeShirtSizes = employees.zip(shirtSize).toMap()
        println(employeeShirtSizes["Denny"])
        
        val foldedValue = listOf(1, 2, 3, 4).fold(0) { accumulator, number ->
            println("Accumulated value: $accumulator")
            accumulator + (number * 3)
        }
        println("Final value: $foldedValue")

        2、序列:

       Kotlin 有个内置惰性集合类型叫序列Sequence)。序列不会索引排序它的内容,也不记录 元素数目。事实上,在使用一个序列时,序列里的值可能有无限多,因为某个数据源能产生无限 多个元素。

        针对某个序列,你可能会定义一个只要序列有新值产生就被调用一下的函数,这样的函数叫 迭代器函数(iterator function)。要定义一个序列和它的迭代器,你可以使用 Kotlin 的序列构造函 数 generateSequencegenerateSequence 函数接受一个初始种子值作为序列的起步值。在用 generateSequence 定义的序列上调用一个函数时,generateSequence 函数会调用你指定的迭 代器函数,决定下一个要产生的值。

        fun Int.isPrime(): Boolean {
            (2 until this).map {
                if (this % it == 0) {
                    return false // Not a prime! 
                }
            }
            return true
        }

        val oneThousandPrimes = generateSequence(3) { value ->
            value + 1
        }.filter { it.isPrime() }
            .take(1000)

​​​​​​​​​​​​​​

十九、Konlin与Java互操作:

        与 Java 的无缝式互操作性表明,Kotlin 文件可以和 Java 文件共存于同一项目。无论是从 Kotlin 里调用 Java 方法,还是反过来, 都不是问题。当然,在 Kotlin 里使用现有的 Java 库,包括 Android 框架库也没有任何问题。

        1、与Java类互操作:

        2、互相操作性与可空性:

        3、类型映射:

             对应 Kotlin中的基本数据类型,Java 用的是原始数据类型。Java 里的原始类型不是对象,但在 Kotlin 中,包 括基本数据类型在内的所有类型都是对象。不过,Kotlin 编译器会将 Java 原始数据类型和最相似 的 Kotlin 类型做映射。

        4、getter和setter方法与互操作性:

        5、类之外:

                对于开发者写的代码格式,Kotlin 几乎没什么限制。类、函数以及变量都可以一股脑地放入 一个 Kotlin 文件里。而在 Java 里,一个文件就对应一个类。

        6、异常与互操作性:

        7、Java中的函数类型:

​​​​​​​     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1519616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Kafka面试演练】那Kafka消费者手动提交、自动提交有什么区别?

面试官&#xff1a;听说你精通Kafka&#xff0c;那我就考考你吧 面试官&#xff1a;不用慌尽管说&#xff0c;错了也没关系&#x1f60a;。。。 每日分享【大厂面试演练】&#xff0c;本期是《Kafka系列》&#xff0c;感兴趣就关注我吧❤️ 面试官&#xff1a;你先说说Kafka由什…

cuda cudnn安装

安装 cudnn是否安装成功 注意 cudnn对应的cuda的10.0版本无win11版本 下载win10 即可

linux系统关闭防火墙和SELINUX及配置网络

一&#xff0c;关闭防火墙和SELINUX 当我们进入界面后&#xff0c;输入用户名root&#xff0c;以及密码&#xff0c;密码我们是看不见的 然后输入指令cat -n /etc/sysconfig/selinux &#xff08;注意空格&#xff09; 输入指令 vi /etc/sysconfig/selinux &#xf…

杂七杂八111

MQ 用处 一、异步。可提高性能和吞吐量 二、解耦 三、削峰 四、可靠。常用消息队列可以保证消息不丢失、不重复消费、消息顺序、消息幂等 选型 一Kafak:吞吐量最大&#xff0c;性能最好&#xff0c;集群高可用。缺点&#xff1a;会丢数据&#xff0c;功能较单一。 二Ra…

第十五届蓝桥杯模拟考试III_物联网设计与开发官方代码分析

目录 前言&#xff1a;显示界面部分&#xff1a; 前言&#xff1a; 这次模拟的效果很不好。85分&#xff0c;4h的限时我花了两天完成&#xff0c;这个时间是远远超出要求的&#xff0c;而且最后还只拿到56分&#xff0c;抛开分数高低不提&#xff0c;就这个用时属实蜗牛一样的速…

2024年【危险化学品经营单位安全管理人员】考试及危险化学品经营单位安全管理人员考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位安全管理人员考试根据新危险化学品经营单位安全管理人员考试大纲要求&#xff0c;安全生产模拟考试一点通将危险化学品经营单位安全管理人员模拟考试试题进行汇编&#xff0c;组成一套危险化学品经…

安装nginx

Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器&#xff0c;特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力确实在同类型的网页服务器中表现较好&#xff0c;中国大陆使用nginx网站用户有&#xff1a;百度、京东、新浪、网易、腾…

2024/3/14打卡k倍区间(8届蓝桥杯)——前缀和+优化***

题目 给定一个长度为 N 的数列&#xff0c;A1,A2,…AN&#xff0c;如果其中一段连续的子序列 Ai,Ai1,…Aj 之和是 K 的倍数&#xff0c;我们就称这个区间 [i,j] 是 K 倍区间。 你能求出数列中总共有多少个 K 倍区间吗&#xff1f; 输入格式 第一行包含两个整数 N 和 K。 以下 N…

DeePhage:预测噬菌体的生活方式

GitHub - shufangwu/DeePhage: A tool for distinguish temperate phage-derived and virulent phage-derived sequence in metavirome data using deep learning 安装 conda create -n deephage conda activate deephage pip install numpy pip install h5py pip install ten…

淘宝联盟高级API - 超级搜索api接口, 淘宝联盟商品搜索接口

淘宝联盟商品库超级搜索api接口&#xff0c;支持搜索商品链接、商品id&#xff0c;商品标题搜索&#xff0c;还有更多强大搜索选项。 注意&#xff1a;接口默认只查【含有优惠券】的商品&#xff0c;如果需要精确搜索&#xff0c;请将 has_coupon 参数设置为 false 获取接口秘…

深入理解JMM

一、什么是JMM JMM&#xff08;java memory model&#xff09;Java内存模型&#xff1a;是java虚拟机规范中定义的一组规范&#xff0c;用于屏蔽掉各种硬件和操作系统的内存访问差异&#xff0c;以实现让JAVA程序在各平台都能达到一致的并发结果。其主要规定了线程和内存之间的…

苍穹外卖问题记录(持续更新)

Day01_3.2.4前后端联调 1. 前端无法登录 &#xff08;1&#xff09;确保nginx服务器已经启动 &#xff08;2&#xff09;查看自己数据库的用户名和密码是否和老师的一样&#xff0c;不一样的话需要在application-dev.yml文件中把老师的用户名密码修改成自己的 老师的用户名…

面试常问,ADC,PWM

一 PWM介绍 pwm全名&#xff08;Pulse Width Modulation&#xff09;&#xff1a;脉冲宽度调制 在具有惯性的系统中&#xff0c;可以通过对一系列脉冲的宽度进行调制&#xff0c;来等效地获得所需要的模拟参量&#xff0c;常应用于电机控速等领域。PWM一定程度上是数字到模拟…

植物神经功能紊乱患者每天从5片黛力新减少至2片,只因找对了治疗方法!

植物神经功能紊乱是一种常见的心理疾病&#xff0c;其症状包括焦虑、失眠、疲劳、头痛、胃肠不适等&#xff0c;给患者带来很大的困扰。然而&#xff0c;这种疾病是可以治疗的。本文将介绍一位植物神经功能紊乱患者的治疗经历&#xff0c;希望能够帮助更多的人了解和治疗此病。…

【机器学习300问】38、什么是K-means算法?

在实际工作中&#xff0c;我们经常会遇到这样一类问题&#xff1a;给机器输入大量的特征数据&#xff0c;并期望机器通过学习找出数据存在的某种共性特征、结构或关联。这类问题被称为“非监督学习”问题。这篇文章我就来聚焦非监督学习中的其中一个任务——聚类 例如在数字营销…

F-logic DataCube3 任意文件上传漏洞复现(CVE-2024-25832)

0x01 产品简介 F-logic DataCube3是一款用于光伏发电系统的紧凑型终端测量系统。 0x02 漏洞概述 F-logic DataCube3 /admin/setting_photo.php接口处存在任意文件上传漏洞 ,未经身份验证的攻击者可通过该漏洞在服务器端写入后门,获取服务器权限,进而控制整个web服务器。 …

【计算机视觉】二、图像形成:2、几何基元和几何变换:2D变换

文章目录 一、向量和矩阵的基本运算二、几何基元和变换1、几何基元(Geometric Primitives)2、几何变换(Geometric Transformations)1. 各种变换的关系2. 变换公式3. 2D变换的层次4. python实现 一、向量和矩阵的基本运算 【计算机视觉】二、图像形成&#xff1a;1、向量和矩阵…

【研发日记】Matlab/Simulink技能解锁(五)——Simulink布线技巧

前言 见《【研发日记】Matlab/Simulink技能解锁(一)——在Simulink编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(二)——在Function编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(三)——在Stateflow编辑窗口Debug》 见《【研发日记】Matlab/Simulink…

HarmonyOS ArkUI入门—HarmonyOS ArkUI来开发一个健康饮食应用

本文演示如果在DevEco Studio 3里面&#xff0c;用HarmonyOS的ArkUI来开发一个健康饮食应用。体验HarmonyOS 3最新API 9&#xff01; 获取HarmonyOS应用 HarmonyOS的ArkUI来开发一个健康饮食的ArkUI程序“ArkUIHealthyDiet”&#xff0c;基础代码已经有了[1]&#xff0c;个人…

DHCP-SNOOPING-嗅探/窥探

DHCP-SNOOPING 私接设备了&#xff0c;非终端收到了报文 所有接口设置为非信任&#xff0c;然后单独配置其中一个接口为信任