本节主要介绍kotlin的可见性与kotlin中的扩展功能的使用,包括:扩展类、扩展方法、扩展伴生对象、扩展属性等。
1、kotlin可见性
关键字:
public: 在不低kotlin进行修饰时,默认为 public。
protected : 不能用在顶层函数或者类上面,用在修饰属性上面,子类和同一个类可以使用。
internal : 只能在同一个模块下使用,即:整个工程(一个模块)。
private : 私有的,只能在该文件上可用。
可见性的用法和Java类似:
open class Class {
private val b = 3
protected open val c = 4
internal val d = 5
}
2、kotlin 扩展
如果要对一个类进行扩展,在Java中,我们可以使用 interface,装饰模式来达到目的,但是在kotlin专门提供了扩展的功能。
2.1、扩展类 :
class ExtensionTest {
fun add(a: Int, b: Int): Int = a + b
fun subtract(a: Int, b: Int): Int = a - b
}
现在有个需求要对上面的类添加,乘法和除法功能,在kotlin我们可以直接对该类的方法进行扩展:
/**
* 扩展类:
*/
class ExtensionTest {
fun add(a: Int, b: Int): Int = a + b
fun subtract(a: Int, b: Int): Int = a - b
}
/**
* 扩展上面类的功能,扩展机制
*/
fun ExtensionTest.multiply(a: Int, b: Int): Int = a * b
fun main() {
val extensionTest = ExtensionTest()
println(extensionTest.add(4,5))
println(extensionTest.subtract(4,5))
println(extensionTest.multiply(4,5))
}
以上代码的运行结果如下:
我们可以看到该类中确实多了乘法的功能。
注意 :
- 1、扩展函数的解析是静态的,该类添加了一方法,并没有插入到原来的类中,本质上没有对原有的类插入任何属性(可以使用javap工具 反编译看结果)
- 2、扩展函数的解析是静态分发的,而不是动态的,即扩展不支持多态,调用只取决于对象的谁能ing类型
多态:通过父类型的引用去指向一个对象,当在调用该对象时,到底是父类,还是子类,取决于真正运行期对象的方法
- 3、调用是由对象的声明类型决定的,而不是由对象的实际类型决定
open class AA
class BB : AA()
// 扩展 AA
fun AA.a() = "a"
// 扩展 BB
fun BB.a() = "b"
fun myPrint(aa: AA) {
println(aa.a())
}
fun main() {
myPrint(AA()) // a
myPrint(BB()) // a
}
我们可以发现上面的结果都是 定义方法中传入参数的类型。
2.2、扩展方法
- 扩展类的方法和扩展类的方法完全一样
- 在扩展方法时原来函数的优先级比较高
/**
* 扩展类的方法和扩展类的方法完全一样
* 在扩展方法时原来函数的优先级比较高
*/
class CC {
fun foo() {
println("CCC")
}
}
fun CC.foo() {
println("CC.foo")
}
// 扩展方法时支持方法重载
fun CC.foo(i: Int) {
println("CC.Int $i")
}
fun main() {
CC().foo() // CCC
CC().foo(5) // CC.Int 5
}
注意: 重载可以对空类型进行扩展, 提供可空类型后就不用再次做检查。
/**
* 重载可以对可空类型进行扩展
* 提供可空类型后就不用再次做检查
*/
fun Any?.toString(): String {
if (null == this) {
return "null"
}
return toString()
}
2.3、扩展属性
/**
* 扩展属性
*/
class MyExtensionProperty {
}
val MyExtensionProperty.name : String
get() = "hello"
fun main() {
val myExtensionProperty = MyExtensionProperty()
println(myExtensionProperty.name) // hello
}
扩展属性后的结果如下图:
2.4、扩展伴生对象
/**
* 扩展伴生对象
*
*/
class ExtensionCompanionObj {
// 伴生对象
companion object MyObject {
}
}
fun ExtensionCompanionObj.MyObject.method() {
println("hello world")
}
fun main() {
ExtensionCompanionObj.method() // hello world
}
代码结果如下图 :
代码执行结果2.5、扩展作用域
先给出结论:
- 1、扩展函数所定义在的类实例叫 分发接受者
- 2、扩展函数所扩展的类的示例叫 扩展接受者
- 3、当以上名字出现冲突时,扩展接受者的优先级比较高
示例如下:
/**
* 扩展作用域
*
* 1、扩展函数所定义在的类实例叫 分发接受者
* 2、扩展函数所扩展的类的示例叫 扩展接受者
* 3、当以上名字出现冲突时,扩展接受者的优先级比较高
*/
class ExtendedScope {
fun method() {
println("ExtendedScope")
}
}
/**
* 扩展上面的类
*/
class ExtendedScope2 {
fun method2() {
println("")
}
// 在类中扩展另一个类
fun ExtendedScope.hello() {
// 可以使用扩展类中的内容,也可以调用这个类的方法
method()
method2()
}
fun world(extendedScope: ExtendedScope) {
extendedScope.method()
}
// 扩展的作用域,只能在该类中使用
fun ExtendedScope.output() {
println(toString())
println(this@ExtendedScope2.toString())
}
fun test() {
var extendedScope = ExtendedScope()
extendedScope.output()
}
}
fun main() {
// 通过扩展可以解决Java中充斥的各种辅助类问题
val extendedScope2 = ExtendedScope2()
extendedScope2.test()
// 运行结果
// com.liang.kotlin.basic.advanced.spread.ExtendedScope@3cd1a2f1
// com.liang.kotlin.basic.advanced.spread.ExtendedScope2@2f0e140b
}
注意:
ExtendedScope并不能调用ExtendedScope2中对它扩展的方法,受到作用域限制
上面的图,我们可以看到,ExtendedScope2中对ExtendedScope扩展的output方法,并不能被ExtendScope调用。
网友评论