做网站费是多少,生活在线线下6家实体店地址,织梦做双语网站,网络营销怎么做网站Kotlin的接口与扩展
接口
与Java类似#xff0c;Kotlin使用interface关键字定义接口#xff0c;同时允许方法有默认实现#xff1a;
interface KtInterfaceTest {fun method()fun methodGo(){println(上面方法未实现#xff0c;此方法已实现)}
}
接口实现 …Kotlin的接口与扩展
接口
与Java类似Kotlin使用interface关键字定义接口同时允许方法有默认实现
interface KtInterfaceTest {fun method()fun methodGo(){println(上面方法未实现此方法已实现)}
}
接口实现
一个类或者对象可以实现一个或多个接口。
class Demo : KtInterfaceTest{override fun method() {println(在类Demo中实现KtInterfaceTest接口的method())}
}
我们在主函数中调用一下
fun main(args: ArrayString) {val demo Demo()demo.method()demo.methodGo()
}
对应控制台输出为 接口中的属性
接口中的属性只能是抽象的不允许初始化值接口不会保存属性值。在实现接口时必须重写属性。
interface KtInterfaceTest {var urlString : String //抽象属性不允许实例化具体值
}class Demo : KtInterfaceTest{override var urlString: String www.google.com
}
函数重写冲突
接口的重写跟类的重写类似如果父类中声明了许多类型有可能出现一个方法的多种实现则必须重写这个成员并且提供自己的实现而要使用父类中提供的方法则需要用superBase类来表示。
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() {superA.foo()superB.foo()}
}
如上代码接口A,B都声明了foo()、bar()函数接口B两个方法都有实现接口A只实现了foo()而bar()在A接口中并没有声明是抽象函数所以C类要重写并实现bar()。而D类同时继承AB两个接口不用重写bar()方法因为继承的B接口已经实现同名方法。但由于继承了两个接口的foo()实现所以需要用superbase类关键字来区分。
扩展
kotlin同C#和Gson类似能够扩展一个类的新的属性或函数(方法)而无需继承该类且无需使用装饰模式在内的任何类型的设计模式。扩展是一种静态行为对被扩展的类代码本身不会造成任何影响。
扩展函数
扩展函数可以在已有类中添加新的方法不会对原类做修改扩展函数的定义形式
fun receiverType.functionName(params){body
}
· receiverType表示函数扩展的对象(接收者)
· functionName扩展函数的名称
· params扩展函数的参数可以为null
下面是一个对User类的扩展
class User(var number:Int)fun User.Printf(){println( 用户号 $number)
}fun main(args: ArrayString) {var user User(123)user.Printf()
}
对应输出结果为 同时这个扩展函数还可改为
fun User.Printf(){println( 用户号 this.number)
}
运行结果也是一致的。这里要说明下这里的this关键字指代的是函数扩展对象(receiver object)(也就是调用扩展函数时, 在点号之前指定的对象实例)。
扩展是静态解析的 扩展不能真正的修改他们的(扩展)类。扩展方法并没有在类中插入新的成员仅仅是可以通过该类型的变量使用点的表达式调用这个函数。
扩展函数一直强调是静态解析的并不是接受者类型的虚拟成员。在调用扩展函数的时候具体被调用的是哪一个函数这一点由调用函数的对象表达式来决定而不是动态的类型来决定的如下示例
open class Fruitclass Apple: Fruit()fun Apple.foo() is apple // 扩展函数 foofun Fruit.foo() is fruit // 扩展函数 foofun printFoo(f: Fruit) {println(f.foo()) // 类型是 Fruit 类
}fun main(arg:ArrayString){printFoo(Apple())
}
对应的输出结果是 若扩展函数和成员函数一致则使用该函数时会优先使用成员函数。
class Apple{fun foo(){println( is apple in class ) // 成员函数 foo}
}fun Apple.foo() println( is apple in extend ) // 扩展函数 foofun main(arg:ArrayString){var apple Apple()apple.foo()
}
对应的控制台输出结果为 扩展一个空对象
在扩展函数内可通过this关键字来判断接收者(receiverType)是否为null。这样即使接收者为null也可以调用扩展函数。如下
fun Any?.toString(): String {if (this null) return null// 空检测之后“this”会自动转换为非空类型所以下面的 toString()解析为 Any 类的函数toString()return toString()
}fun main(arg:ArrayString){var demo nullprintln(demo.toString())
}
对应的控制台输出结果为 扩展属性
除了扩展函数kotlin也支持扩展属性。扩展属性允许定义在类或者kotlin文件中不允许定义在函数中。初始化属性因为属性没有后端字段backing field所以不允许被初始化只能由显式提供的 getter/setter 定义。
val User.foo 1 // 错误扩展属性不能有初始化器val T ListT.lastIndex: Intget() size - 1 //正确
值得注意的是扩展属性只能被声明为 val。
伴生对象的扩展
如果一个类有一个伴生对象 你也可以为伴生对象定义扩展函数和属性。伴生对象通过类名.形式调用伴生对象伴生对象声明的扩展函数通过用类名限定符来调用
class NormalClass {companion object { } // 将被称为 Companion
}fun NormalClass.Companion.foo() {println( 伴生对象Companion的扩展函数 )
}val NormalClass.Companion.no: Intget() 10fun main(args: ArrayString) {println( no:${NormalClass.no} )NormalClass.foo()
}
在控制台对应的输出结果为 补充伴生对象内的成员相当于 Java 中的静态成员其生命周期伴随类始终在伴生对象内部可以定义变量和函数这些变量和函数可以直接用类名引用。
对于伴生对象扩展函数有两种形式一种是在类内扩展一种是在类外扩展这两种形式扩展后的函数互不影响甚至名称都可以相同即使名称相同它们也完全是两个不同的函数并且有以下特点 1类内扩展的伴随对象函数和类外扩展的伴随对象可以同名它们是两个独立的函数互不影响 2当类内扩展的伴随对象函数和类外扩展的伴随对象同名时类内的其它函数优先引用类内扩展的伴随对象函数即对于类内其它成员函数来说类内扩展屏蔽类外扩展 3类内扩展的伴随对象函数只能被类内的函数引用不能被类外的函数和伴随对象内的函数引用 4类外扩展的伴随对象函数可以被伴随对象内的函数引用。
示例代码如下
class RunProgram {companion object {val mFieldNum: Int 1var mFieldString this is mFieldStringfun companionFun1() {println(this is 1st companion function.)foo()}fun companionFun2() {println(this is 2st companion function.)companionFun1()}}fun RunProgram.Companion.foo() {println(伴随对象的扩展函数内部)}fun test2() {RunProgram.foo()}init {test2()}
}
val RunProgram.Companion.no: Intget() 10
fun RunProgram.Companion.foo() {println(foo 伴随对象外部扩展函数)
}
fun main(args: ArrayString) {println(no:${RunProgram.no})println(field1:${RunProgram.mFieldNum})println(field2:${RunProgram.mFieldString})RunProgram.foo()RunProgram.companionFun2()
}
对应控制台输出结果为 扩展的作用域
通常扩展函数或扩展属性就定义在顶级包下:
package ktfoo.programfun Ktz.goo() { …… }
如果要使用所定义包之外的一个扩展, 可通过import导入扩展的函数名进行使用:
package com.example.demoimport ktfoo.program.goo // 导入所有名为 goo 的扩展
// 或者
import ktfoo.program.* // 从 ktfoo.program 导入一切fun usage(baz: Ktz) {baz.goo()
}
扩展声明为成员
在kotlin中一个类内部你可以为另一个类声明扩展。在这个扩展中有个多个隐含的接受者其中扩展方法定义所在类的实例称为分发接受者而扩展方法的目标类型的实例称为扩展接受者。
class Car {fun bar() { println(Car bar) }
}class Plane {fun baz() { println(Plane baz) }fun Car.foo() {bar() // 调用 Car.barbaz() // 调用 Plane.baz}fun caller(car: Car) {car.foo() // 调用扩展函数}
}fun main(args: ArrayString) {val Plane: Plane Plane()val car: Car Car()Plane.caller(car)
}
可以推算出控制台输出为 在上段代码中 Plane 类内创建了Car类的扩展。此时Plane被成为分发接受者而Car为扩展接受者。从上例中可以清楚的看到在扩展函数中可以调用派发接收者的成员函数。
假如在调用某一个函数而该函数在分发接受者和扩展接受者均存在则以扩展接收者优先要引用分发接收者的成员你可以使用限定的 this 语法。示例如下
class Car {fun bar() { println(Car bar) }
}class Plane {fun bar() { println(Plane bar) } //注意fun Car.foo() {bar() // 调用 Car.barthisPlane.bar() // 调用 Plane.baz}fun caller(car: Car) {car.foo() // 调用扩展函数}
}fun main(args: ArrayString) {val Plane: Plane Plane()val car: Car Car()Plane.caller(car)
}
对应的控制台输出 值得一提的是以成员的形式定义的扩展函数, 可以声明为 open , 而且可以在子类中覆盖。也可以说在这类扩展函数的派发过程中, 针对分发接受者是虚拟的(virtual), 但针对扩展接受者仍然是静态的。
open class Car {
}class SUV : Car(){}open class Plane {open fun Car.drive() {println( Car driving in the Plane )}open fun SUV.drive() {println( SUV driving in the Plane )}fun caller(car: Car){car.drive() //调用扩展函数}
}class FighterPlane : Plane(){override fun Car.drive() {println( Car driving in the FighterPlane )}override fun SUV.drive() {println( SUV driving in the FighterPlane )}
}fun main(args: ArrayString) {Plane().caller(Car())FighterPlane().caller(Car()) //分发接收者虚拟解析Plane().caller(SUV()) //扩展接收者静态解析
}
对应控制台输出为 End如有问题请留言讨论。