直白一点就是动态为类增加方法(而java是不支持的,java是静态语言,当一个类定义完成后,程序无法为该类增加、删除属性、方法,除非重写编辑该类的源代码(.java文件),重新编译),*当为父类添加了扩展方法,其子类也将继承到该方法;可以为任何类无论是形同定义的类还是自定义的类添加扩展方法
*
扩展方法其实就是定义一个函数,只是需要在函数名前是增加被扩展的类或者接口名
fun 类名(或者接口).方法名(){
}
如:定义了两个具有继承关系的类
open class SuperCalss{
var loc:Int=1;
fun test(){
}
}
class SubClass:SuperClass(){
fun sub(){
}
}
扩展父类SuperClass方法
fun SuperClass.info(){
println("这是扩展方法"+this.loc)
}
我们可以通过子类对象来调用从父类继承到扩展方法:
var sub=SubClass();
sub.info()
var sub:SuperClass=SubClass()
Kotlin支持直接使用泛型类扩展:
如:
fun List.shuffle():List{}
扩展方法只对List有效,List就不能直接调用该方法
Kotlin完全支持直接进行泛型类扩展,只不过需要在扩展方法上使用泛型
fun List.shuffle():List{}
该方式定义的扩展方法:任何泛型List类都可以使用;
当为类添加了扩展方法,被扩展的类并没有被修改,还是原来的类。
扩展方法本质:定义一个函数,当调用扩展方法是,在编译时期执行静态解析(根据调用对象、方法名找到扩展方法,转为函数调用)比如:list.shuffle()
步骤:
成员方法是动态解析(由运行时类型决定),扩展方法是静态解析(由编译时类型决定)不存在多态
例如:以上面代码为例,在***为子类SubClass为添加一个和父类相同签名的扩展方法(不需要声明为方法重写,因为扩展方法不支持多态,所以当调用相同签名的扩展方法时,调用的是编译时类型的扩展方法)***:
fun SubClass.info(){
println("子类扩展方法")
}
var sub:SuperClass=SubClass();
sub.info();
将调用的是父类的info()方法;
当类存在相同签名的成员方法和扩展方法时,成员方法优先级高于扩展方法,即系统总是调用成员方法而不是扩展方法
当成员方法和扩展方法只是相同方法名,形参列表不同,不会出现成员方法遮挡扩展方法的情况,系统是可以区分调用成员方法还是扩展方法
如:
class A{
fun bar()=println("A的Bar()")
}
class B{
fun foo()=println("B的foo()")
fun bar()=println("B的bar()")
fun A.info(){
foo()
[email protected]()//将调用B的bar()
bar()//将调用A的bar()
}
}
定义在类中的扩展方法,即使被扩展类成员,有是定义所在类成员,所以可以访问两者的成员(属性、方法),可以省略"this"
但是可能出现这种情况:定义类和被扩展类中有相同签名的方法,如果在扩展方法中调用相同签名的方法,系统优先调用被扩展类中的那个方法被,这时如果要调用定义所在类的那个方法就必须借助"this@定义所在类名"。
Kotlin中的this支持用"this@类名"形式,限制this代表哪个类
首先需要明白一点的是:
Kotlin编译器本身支持静态解析(根据调用对象、方法名找到对应的扩展方法,转为函数调用);java编译器本身不支持静态解析,需要程序员手动做好静态解析;
Kotlin:将List.info()扩展方法定义在Test.kt文件中
fun List.info(){
.......
}
调用:list.info()既可
java中调用:
1.首先创建List对象
ArrayList list=new ArrayList();
2.前面我们说了定义的顶级函数会变成函数"所在文件+Kt"(TestKt.class)类的静态方法,所以调用扩展方法就是"文件对应类.扩展方法(扩展类对象,参数)“
TestKt.info(list)
可空类型允许为null,因此在定义扩展方法时,需要在扩展方法中判断处理为null时的情况
如:
fun Any?.equals(other:Any?):Boolean{
if(this==null){
return if(other==null) true else false
}
return other.equals(others)
}
匿名函数顾明思意:没有函数名.所谓匿名扩展方法其实就是带接受者的匿名函数;接受者就是".()"前面的类型
var info=fun Int.():Int{
}
匿名扩展函数类型是:Int.()->Int,这里Int就是被扩展类类型即在普通函数类型前添加了一个接受者类型限定
(自己)匿名扩展方法和扩展方法最大的区别:
定义时无论在文件中定义还是在类体中定义,都必须将函数赋值给函数类型变量,否则将无法调用该匿名扩展函数;
调用匿名括扩展函数,通过“匿名扩展函数所属类.函数的变量(实参)”
//Int匿名扩展方法
var f=fun Int.():Int{
return 1
}
//当匿名扩展函数作为形参时
fun test(fc:Int.(str:String)->Int):Unit{
println(1.fc(“leslie”))
}
fun main(args: Array) {
test(fun Int.(str:String):Int{
return 12
})
1.f()
}
扩展属性不能有幕后字段,因此对扩展属性的限制要求即没有幕后字段属性要求:
和扩展方法一样,扩展属性本质是重写getter、setter方法也可以使用泛型函数的形式来定义扩展属性:
val List.lastIndex:Int
get()=size-1