Kotlin学习记录(二) 2022/3/22

Kotlin学习记录(一) 2022/3/22

1.5 类和对象

Kotlin语言是支持面向对象编程的,即要先将事物封装成具体的类,然后将事物所拥有的属性以及能力定义为类的字段和函数,然后再适当时候创建类的对象,调用对象中的字段和函数来满足实际编程的需求,这是面向对象编程的基本思想。

创建一个Person类:

class Person {
    var name = ""
    var age = 0
    fun eat() {
        println("$name is eating.He is $age years old.")
    }
}

使用var关键字创建,因为需要在创建对象之后在指定具体的名字和年龄,需要它是一个可变值。代码中 $ 是一个转义符。

对类进行实例化,即创建一个类的对象,代码如下:

fun main() {
    val p1 = Person()
    p1.name = "Rose"
    p1.age = 21
    p1.eat()
}

直接使用Pearson() 来创建对象。

1.6 继承与构造函数

创建一个Student类,继承于Person,因为Student同样具有名字和年龄,不需要在重新赋予这些属性,会显得冗余,因此可以直接继承Student。

在Kotlin中,任何一个非抽象类都是不可继承的,相当于java中的对类赋予final声明,禁止继承。这样做的原因同val关键字,如果一个类不是专门为了继承而实现的,就应该赋予final关键字,因此Kotlin默认所有非抽象类是不可继承的。

tips:强调是非抽象类的原因是,抽象类不能创建实例,一定要由子类继承它才能创建实例,因此抽象类必须可以被继承,要不然就没有意义了。

要想使一个类被继承需要做两件事:

第一件事:需要在类前加 open 关键字。告诉编译器,这是专门为继承而创建的类,这样Person就可以被继承了。

open class Person {
    ...
}

第二件事:在创建继承类时加冒号 : 继承父类(),代码如下:

class Student : Person() {
    var sno = ""
    var grade = 0
}

父类后必须要有 () ,因为Kotlin涉及到主构造函数、次构造函数等方面的知识。

1.7 接口

接口是用于实现多态编程的重要组成部分。Kotlin是单继承结构的语言,只能继承一个父类,但可以实现多个接口。

我们可以在接口中定义一系列抽象行为,然后用具体的类去实现。使用interface关键字定义接口。

可以对接口中的函数进行默认实现!

interface Study {
    fun readBooks()
    fun doHomeWork(){
        println("do homework default implementation!")
    }
}

Kotlin实现接口统一使用 冒号: 来实现,不同于java中的implements,实现接口代码如下:

class Student(name: String, age: Int) : Person(name, age), Study {
    override fun readBooks() {
        println("$name is reading!")
    }

    override fun doHomeWork() {
        println("$name is doing homework!")
    }
}

必须要实现接口中的所有函数!重写override。当接口中函数有默认实现时,这个函数可以自由选择实现或者不实现,不实现即为默认实现,可以删掉Student类中的override fun doHomeWork() 函数体。

可见性修饰符:

Kotlin中有四种:private 、protected 、public 和 internal, 需要哪种修饰符时,直接写在fun前即可。与java修饰符的区别如下:

 Kotlin默认是public 所有类可见,java默认是default,同一包路径下的类可见。

1.8  数据类和单例类

数据类,用于将服务器端或数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持。MVC、MVP、MVVM等架构模式,M指的是数据类。不同于java,Kotlin提供了data关键字,可自动实现数据类功能。

data class Cellphone(val brand: String, val price: Double)

class前加data自动重写了equals()、hashCode()、toString()等函数方法。

单例类,它可以用于避免创建重复的对象。比如我们希望某个类在全局仅拥有一个实例,这时可以用单例模式,创建一个单例类。同样不同于java创建单例类的方法,在Kotlin中仅需将class转化为Object即可。

object Singleton {
    fun singletonTest() {
        println("singleton is called.")
    }
}

不同于java,不需要在类中定义getSingleton()的私有方法,也不需要私有定义构造函数等,只需要Object关键字即可。

调用方式,类似于java调用方式:

fun main() {
    Singleton.singletonTest()
}

看上去像静态方法的调用,但是Kotlin自动帮我们创建了一个Singleton的实例,并保证只有一个。

1.9  Lambda编程

1.9.1 集合的创建与遍历

集合主要有List、Set、Map等。

不同于java,Kotlin提供了更简单的创建集合的方式,使用内置的listOf() 函数来创建集合。不需要再像java一点点像list中add元素,可直接一步创建。

fun main() {
    val list = listOf("Apple","orange","StrawBerry")
    for (fruit in list) {
        println(fruit)
    }
}

但是,使用listOf创建的集合是不可变集合,即不可以对集合中的元素进行增删改,同样是为了保证不可变性。

创建可变集合有另一种创建函数,mutableListOf()来创建,创建出来的集合自带增删改等函数进行操作。

fun main() {
    val list2 = mutableListOf("Apple","orange","StrawBerry")
    list2.add("watermelon")
    list2.remove("orange")
    for (fruit in list2) {
        println(fruit)
    }
}

同理,Set集合的用法基本一致,函数变为 setOf() 和 mutableSetOf()。

注意Set集合中不可以存放重复元素,如果存放重复元素只会保留一份。

fun main(){
    val set = mutableSetOf(1, 2, 3, 4, 5, 5, 4)
    println(set)
}

打印结果为: 去掉了重复元素。

Map集合,是一种键值对形式的数据结构 ,构建Map集合,以及向Map添加一条数据代码如下:

val map = HashMap<String, Int>()
map["java"] = 89
map["Kotlin"] = 92

 这不是最简单的写法,因为Kotlin提供了mapOf() 和 mutableMapOf() 来创建集合,可直接传入初始化键值对来完成对Map集合的创建。

val map1 = mutableMapOf("java" to 80, "Kotlin" to 92, "C++" to 94)

这里的to并不是一个关键字,而是一个函数,现在还不会!

遍历map:

fun main(){
    for ((language, score) in map1) {
    println("$language 's score: $score")
    }
}

1.9.2  集合的函数式API

Lambda表达式的语法结构:

{  参数名1 : 参数类型 , 参数名2 : 参数类型 -> 函数体  }

-> 后表示参数列表的结束以及函数体的开始,函数体中可以编写任意行代码,并且最后一行代码会自动作为Lambda表达式的返回值。

首先定义一个Lambda表达式,然后lambda作为maxByOrNull的参数。

val list = mutableListOf("Apple","orange","StrawBerry")
val lambda = { fruit:String -> fruit.length }
val maxLengthFruit = list.maxByOrNull{ fruit: String -> fruit.length }

不能理解如何工作,可以看maxByOrNull的源码:

public inline fun <T, R : Comparable<R>> Iterable<T>.maxByOrNull(selector: (T) -> R): T? {
    val iterator = iterator()
    if (!iterator.hasNext()) return null
    var maxElem = iterator.next()
    if (!iterator.hasNext()) return maxElem
    var maxValue = selector(maxElem)
    do {
        val e = iterator.next()
        val v = selector(e)
        if (maxValue < v) {
            maxElem = e
            maxValue = v
        }
    } while (iterator.hasNext())
    return maxElem
}

其中   selector: (T) -> R   为Lambda表达式,此时我们输入的表达式为lambda,然后根据lambda来判断出最长的元素,直到遍历完整个list。

进一步简化代码,我们不需要额外定义一个lambda,可直接传递表达式作为参数。

val maxLengthFruit = list.maxByOrNull({ fruit: String -> fruit.length })

Kotlin有规定,当Lambda参数作为函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面,如下:

val maxLengthFruit = list.maxByOrNull() { fruit: String -> fruit.length }

如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略:

val maxLengthFruit = list.maxByOrNull { fruit: String -> fruit.length }

Kotlin有出色的类型推导机制,一般不需要声明参数类型,因此可简化为:

val maxLengthFruit = list.maxByOrNull { fruit -> fruit.length }

最后,当Lambda表达式的参数列表中只有一个参数时,也可以不必声明参数名,直接使用it关键字代替:

val maxLengthFruit = list.maxByOrNull { it.length }

集合中的map函数是一种最常用的函数式API,可以将集合中的每个元素映射成另外的值,映射规则在Lambda表达式中指定。

list.map { it.uppercase() }

map的源码为:

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值