目录
一、 类
1. 类的定义
2. 类的构造函数
3. 类的继承和方法、属性的复写
4. Interfaces接口
通常如下所示:
class Invoice { ... }
可以省略参数和函数体,最简单形式如 : class Empty 但是目前还不知道这样定义的类有什么应用场景。
其中主构造函数primary constructor 可以直接包含在类的header(即参数列表)中,如果主构造函数没有任何注解或者可见性修饰符(private
, protected
, internal
and public
)时,可以直接省略constructor关键字
class Person constructor(firstName: String) { ... }
class Person(firstName: String) { ... }
主构造函数基本可以解决常用的场景,还可以使用init来定义初始化块,或者定义多个次构造函数secondary constructors,
主构造函数中的参数可以在初始化块或者类的成员变量初始化时引用
//类的初始化块执行顺序,就是混合属性后,从上到下的顺序
class InitOrderDemo(name: String) {
val firstProperty = "First property: $name".also(::println)
init {
println("First initializer block that prints ${name}")
}
val secondProperty = "Second property: ${name.length}".also(::println)
init {
println("Second initializer block that prints ${name.length}")
}
}
fun main(args: Array) {
InitOrderDemo("hello")
}
/*以上代码打印顺序
First property: hello
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5
*/
//可以在类的初始化块或者属性的中引用主构造的参数
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
主构造函数中的参数可以指定为可变的(var)或者只读的 (val)
class Person(val firstName: String, val lastName: String, var age: Int) { ... }
次构造函数不能有声明val var, 次构造函数必须代理给主构造函数,直接或者间接通过其他的次构造函数,使用this关键字
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
Kotlin中所有类的最终父类是Any, 如果要使得该类可以被继承,必须使用open修饰,默认都是不可继承的,官网的文档介绍说:
By default, all classes in Kotlin are final, which corresponds to Effective Java, 3rd Edition, Item 19: Design and document for inheritance or else prohibit it
看来Kotlin不鼓励使用继承,即不鼓励使用面向对象的编程思想,其推荐函数式编程
open class Base(p: Int)
class Derived(p: Int) : Base(p)
重写父类的方法,前提是父类的方法必须要是open修饰的,使用override来申明该方法是重写父类的(这时该方法就是默认open修饰了),如果不想子类再复写该方法,可以使用final override修饰
open class Base {
open fun v() { ... }
fun nv() { ... }
}
class Derived() : Base() {
override fun v() { ... }
}
open class AnotherDerived() : Base() {
final override fun v() { ... }
}
类的属性,var修饰的有默认的setter和getter方法,val修饰的不允许有setter方法
自己定制的setter和getter方法,可以使用field引用当前值,非基本属性可以使用lateinit 修饰,然后后面可以通过.isInitialized来检查是否被初始化过了
class Person(private val name: String, var age: Int) {
var nameWrapper: String = "kotlin"
get() {
return "Hi, $name, $field"
}
var ageWrapper = 0
get() = field - 10
set(value) {
field = value + 20
}
}
fun main(args: Array) {
val person = Person("cyc", 28)
person.ageWrapper = 30
person.nameWrapper = "java"
println(person.nameWrapper)
println(person.ageWrapper)
}
/*
输出如下
Hi, cyc, java
40
*/
和Java8的接口类似,可以有实现了的方法,可以有属性properties,除了抽象的之外,在定义了getter方法后,可以变成非抽象的,接口可以继承,一个类继承的多个接口发生复写方法冲突时,可以使用super<接口名>.fun()来制定调用哪一个接口里的方法。
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// implementing 'name' is not required
override val firstName: String,
override val lastName: String,
val position: Position
) : Person
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super.foo()
super.foo()
}
override fun bar() {
super.bar()
}
}