首先申明下,本文为笔者学习《Kotlin 程序开发入门精要》的笔记,并加入笔者自己的理解和归纳总结。
1. 类
在kotlin中,类的声明使用class
关键字。
class Shape {
}
1.1 构造器
类允许定义一个主构造器和若干个第二构造器。
主构造器是类头的一部分,紧跟在类名的后面,构造器参数是可选的。在init
块中进行初始化,init
块可直接使用主构造器的参数。
class Shape constructor(w: Int, h: Int) {
var width: Int = w
var height = h
init {
println("Shape init width = $width, height = $height")
}
}
如果主构造器没有任何的注释(annotation)
或修饰符(modifier)
,constructor
关键字可以省略。
class Shape(w: Int, h: Int) {
... ...
}
第二构造器需要在类中声明,前面必须加constructor
关键字,并且都需要在声明后面调用主构造器或通过另一个第二构造器间接地调用主构造器。
class Shape(w: Int, h: Int) {
var width: Int = w
var height = h
init {
println("Shape init width = $width, height = $height")
}
constructor(w: Int): this(w, 10) {
println("Shape constructor(w)")
}
constructor(): this(20) {
println("Shape constructor()")
}
}
1.2 类属性
属性语法,只有var/val
和propertyName
是必须的,其他都是可选的。
var/val <propertyName>[: PropertyType] [= property_initializer]
[<getter>]
[<setter>]
属性的getter
和setter
形式 ,可以拦截属性读写。如果属性是只读的,需要将属性声明为val
,并只添加一个getter
形式。如果属性是读写的,需要使用var
声明,并添加getter
和setter
形式。如果getter
只有一行实现代码,直接用等号(=)
分割。
class Property {
private var value = 4
var prop: Int
get() {
println("get prop")
return value
}
set(v) {
println("set prop")
value = v
}
var prop2: Int = 20
get() = field
set(v) {
field = v
}
}
上面的例子里prop
属性用value
来保存属性的值,kotlin为我们提供了更好的解决方式,filed
属性。不能对直接对prop
进行赋值,否则会报"Initializer is not allowed here because this property has no backing field"
,详见Kotlin 的 Backing Fields 和 Backing Properties。
1.3 类函数
kotlin函数支持默认参数,但带默认参数的必须是最后几个参数。调用时,可以按顺序传入参数值,也可以通过指定函数的形参名传值。
class Function {
fun show(i: Int = 5, d: Double = 10.0, flag: Boolean = false) {
println("i = $i, d = $d, flag = $flag")
}
}
fun main(args: Array<String>) {
var f = Function()
f.show(1, 2.0, true) // i = 1, d = 2.0, flag = true
f.show(15, 25.0) // i = 15, d = 25.0, flag = false
f.show(6, flag = true) // i = 6, d = 10.0, flag = true
}
可变参数使用vararg
声明
fun addFunction(vararg functions: Function): List<Function> {
var list = ArrayList<Function>()
for (f in functions) {
list.add(f)
}
return list
}
1.4 嵌套类
所谓嵌套类,就是在类中定义的类。如果用inner
关键字声明,需要通过外部类的实例引用嵌套类。
class Outer {
class Nested {
fun show() {
println("Outer.Nested")
}
}
inner class Inner {
fun show() {
println("Outer.Inner")
}
}
}
fun main(args: Array<String>) {
Outer.Nested().show() // Outer.Nested
Outer().Inner().show() // Outer.Inner
}
2. 修饰符
在Kotlin中,修饰符有4个,private
、protected
、internal
和public
。如果不指定,默认是public
private
,仅仅在类的内部可以访问。protected
,除了类内部,子类中也可以访问internal
,在模块内部类都可以访问public
,任何类都可以访问
3. 类的继承
Kotlin使用冒号(:)
实现继承,冒号后面需要调用父类的构造器。Kotlin是单继承,默认是final
,需要显式使用open
关键字来继承类。
open class Shape(w: Int, h: Int) {
var width: Int = w
var height = h
... ...
}
class Rectangle(w: Int, h: Int): Shape(w, h) {
}
类方法默认是不可重写的,如果需要重写方法,先需要在父类的方法前加上open
关键字,同时在子类的方法前加上override
关键字。
open class Rectangle(w: Int, h: Int): Shape(w, h) {
override fun toString(): String {
return "rectangle width = $width, height = $height"
}
}
重写方法可以被再次重写,如要阻止可添加final
关键字。
class Square(l: Int): Rectangle(l, l) {
final override fun toString(): String {
return "Square width = $width, height = $height"
}
}
重写属性必须使用open
声明,子类中重写的属性必须用override
声明。val
属性可以被重写为var
属性,反之不可以。
open class Shape(w: Int, h: Int) {
var width: Int = w
open val height: Int = h
get() {
println("Shape getHeight")
return field
}
... ...
}
open class Rectangle(w: Int, h: Int) : Shape(w, h) {
override var height: Int = h
get() {
println("Rectangle getHeight")
return field
}
set(height) {
println("Rectangle setHeight")
field = height
}
... ...
}
fun main(args: Array<String>) {
var r = Rectangle(10, 15)
println(r.height)
r.height = 20
println(r.height)
println(r)
}
输出
Rectangle getHeight
Shape init width = 10, height = 0
Rectangle getHeight
15
Rectangle setHeight
Rectangle getHeight
20
4. 接口
接口使用interface
声明,接口中的属性和方法都是open
的。kotlin允许在接口方法中包含默认的方法体。
interface IShape {
fun getArea(): Int
fun getName() = ""
}
open class Shape(w: Int, h: Int): IShape {
var width: Int = w
val height = h
override fun getArea(): Int {
return width * height
}
}
5. 抽象类
抽象类与接口类似,需要abstract
关键字声明。
abstract class Base {
abstract fun f()
}
class Super : Base() {
override fun f() {}
}