Kotlin面向对象 (1)✔️类、及属性
Kotlin语言目前还是以面向对象编程为主,函数式编程为辅。
什么是面向对象?面向对象的三大基本特征,封装性、继承性、多态性的定义?吧啦吧啦,百度一大坨。
一、类声明
class 类型 {
声明类的成员
}
kotlin中的类成员包括:构造函数、初始化代码块、成员函数、属性、内部类和嵌套类、以及对象表达式声明。
class Animal {
var age = 1
private val weight = 0.0
private fun eat() {
// 函数体
}
fun run(): Int {
// 函数体
return 10
}
fun getMaxNumber(n1: Int, n2: Int) = if (n1 > n2) n1 else n2
}
二、属性
var|val 属性名[: 数据类型] [=属性初始化]
[getter访问器]
[setter访问器]
- 约定:中括号 ([]) 部分标示可以忽略;竖线 (|) 标示“或”关系,例如 var|val 说明可以使用 var 或 val 关键字,但两个关键字不能同时出现。
- 注意:属性本身并不真正的保存数据,数据被保存在支持字段中,支持自动一般是不可见的,支持字段只能应用在属性访问器中,通过系统定义好的 field 变量访问。
class Animal {
// 名字
var name: String = "动物"
get() = "名称: $field"
set(value) {
field = "小$field"
}
var age = 2 // 年龄
get() = if (field > 0) field else 0
private val color = "yellow" // 颜色
}
-
延迟初始化属性
延时初始化属性声明,使用关键字lateinit
;延时初始化属性要求: 不能是可空类型;只能使用var声明;lateinit关键字要方法到var之前。
class Employee(val name: String) {
var age: Int = 0
get() = if (field > 0) field else 0
lateinit var dept: Department
}
class Department {
var no: Int = 0
var name: String = ""
override fun toString(): String {
return "no=$no name=$name"
}
}
fun main(args: Array<String>) {
val emp = Employee("小三")
emp.dept = Department()
emp.dept.no = 1
emp.dept.name = emp.name
println(emp.dept)
emp.dept = Department()
emp.dept.no = 2
emp.dept.name = "${emp.name} 2"
println(emp.dept)
}
// 输出结果
// no=1 name=小三
// no=2 name=小三 2
- 委托属性
class User {
var name: String by Delegate() // 1️⃣
}
class Delegate {
operator fun getValue(thisRef: Any, property: KProperty<*>): String = property.name // 2️⃣
operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) { // 3️⃣
println(value)
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "小三" // 4️⃣
println(user.name) // 5️⃣
}
// 输出结果
// 小三
// name
讲解:上述代码第1️⃣行是声明委托属性,by是委托运算符,他后面的Delegate()
就是属性name
的委托对象,通过by运算符属性name
的setter
访问器被委托给Delegate
对象的setValue
函数,属性name
的getter
访问器被委托给Delegate
对象的getValue
函数。Delegate
对象不必实现任何借口,只需实现getValue
和setValue
函数即可,即见代码第2️⃣和第3️⃣行。注意这两个函数前面都有operator
关键字修饰,operator
所修饰的函数是运算符重载函数,本例中说明了setValue
和getValue
函数重载by运算符。代码第4️⃣行给name
属性赋值,这会调用委托对象的setValue
函数,代码第5️⃣行是读取name
值,这会调用委托对象的getValue
函数。
-
惰性加载属性
惰性加载属性与延时加载属性类似,只是第一次访问该属性时才进行初始化。不同的是惰性加载属性使用 lazy 函数声明委托属性,而延时初始化属性使用 lateinit 关键字修饰属性。还有惰性加载属性必须是 val 的,而延迟初始化属性必须是 var 的。
open class Employee {
var no: Int = 0
var firstName = "Tony"
var lastName: String = "Guan"
val fullName by lazy { "$firstName.$lastName" } // 1️⃣
lateinit var dept: Department:
}
class Department {
var no: Int = 0
var name: String = ""
override fun toString(): String {
return "no=$no name=$name"
}
}
fun main(args: Array<String>) {
val emp = Employee()
println(emp.fullName) // Tony.Guan
val dept = Department()
dept.no = 20
emp.dept = dept
println(emp.dept)
}
讲解:代码第1️⃣行声明了惰性加载属性fullName
,by 后面是 lazy 函数,注意 lazy 不是关键字,而是函数。lazy 函数后面跟着的是尾随 Lambda 表达式。惰性加载属性使用 val 声明。
- 可观察属性
class Department {
var no = 0
var name: String by Delegates.observable("无") { property, oldValue, newValue -> // 1️⃣
println("$oldValue -> $newValue")
}
}
fun main(args: Array<String>) {
val dept = Department()
dept.no = 20
dept.name = "技术部" // 输出 无 -> 技术部
dept.name = "市场部" // 输出 技术部 -> 市场部
}
讲解:代码第1️⃣行是声明 name
委托属性,by 关键字后面的Delegates.observable()
函数有两个参数:第一个参数是委托属性的初始化值,第二个参数是属性变化事件的响应器,响应器是函数类型,具体调用时可使用 Lambda 表达式作为实际参数。在 Lambda 表达式中有三个参数,其中property
是属性,oldValue
是属性的旧值,newValue
是属性的新值。