接口
kotlin中的接口定义跟java8有点类似,它既可以包含一些抽象的方法,也可以有一些默认的实现方法。但和java8不同的是kotlin的接口不会保存状态(???)。还可以有一些属性,但这些属性没有初始化值,也是抽象的。
interface MyInterface {
val prop: Int //abstract
val propWithImp: String
get() = "foo"
fun bar()
fun foo() {
println("it is a implementations")
// optional body
}
}
实现接口
一个class或者object可以实现一个或多个接口,如下:
class Child : MyInterface {
override val prop: Int = 29
override fun bar() {
// body
}
}
可见修饰符
kotlin有四种可见修饰符,分别是private、protected、internal和public。
(1)private 只能在当前文件中可见
(2)protected 在其子类中可见
(3)internal 在同一个module中可见,就是android studio中的module
(4)public 对任何部分都可见
扩展方法
要声明一个扩展方法,我们需要在扩展方法名前面以被扩展的类为前缀,下面是一个例子,给MutableList添加一个扩展方法swap:
fun MutableList<Int>.swap(index1: Int, index2: Int){
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
这样我们就可以在任何MutableList的实例对象中调用swap方法了,如下:
val intList = mutableListOf(1, 3, 5)
intList.swap(0, 2) //list就成为了5, 3, 1
当然我们可以通过通配符给每个MutableList,添加一个扩展方法:
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
扩展方法是被静态决定的,这句话听起来有点拗口。意思就是说调用哪个类的扩展方法是根据当前被定义的是什么类而不是在运行时的具体类型,这个主要说的是class的多态。比如class person 是一个父类,class student是person的子类。他们都有一个扩展方法为printName(),在我们实际应用中往往会利用面向对象的多态特性(父类引用指向具体的子类)。这时调用的扩展方法是父类的而不是具体子类的,如下:
class Person
class Student
fun Person.printName(){
println("person class name is ...")
}
fun Student.printName(){
println("studentclass name is ...")
}
//有一个方法,参数是person
fun printPerson(person: Person ){
person.printName()
}
//调用上面的方法
printPerson(Student())
打印结果为=======
person class name is ...
如果给一个类写一个扩展方法,这个扩展方法名及参数类型和个数 跟这个类的成员方法完全一样,在调用这个方法的时候会优先调用成员方法,也就是说这个扩展方法在任何情况下都不会调用。
但是我们可以写一个扩展方法作为这个类某个成员方法的重载方法使用。如下:
class C {
fun foo() { println("member") }
}
fun C.foo(i: Int) { println("extension") }
fun print(){
val c = C()
c.foo(2) //实际调用的是它的扩展方法foo(i: Int)
}
扩展属性
跟扩展方法类似,kotlin也支持扩展属性,但扩展属性不能直接初始化。如下:
val <T> List<T>.lastIndex: Int
get() = size - 1
扩展Companion Object
如果一个类中定义了companion object,我们也可以给companion object定义扩展方法,如下:
class MyClass {
companion object { } // will be called "Companion"
}
fun MyClass.Companion.foo() {
// ...
}
扩展方法的作用域
大部分情况我们将扩展方法定义在top-level,也就是直接在package 包名下进行定义,如下
package com.test
fun Person.printName() { ... }
我们在上面的文件外使用时,只需要引入这个包即可。如下:
package com.test1
import com.test.*
//或者我们可以单独应用具体的扩展方法
//import com.test.printName
fun usage(person: Person){
person.printName()
}