在java中咱们须要扩展一个类的新功能时,通常是继承该类或者使用像装饰者这样的设计模式来实现的。
以下:java
public class Animal {
protected String name;
Animal(String name){
this.name = name;
}
public void showName(){
System.out.print(name);
}
}
复制代码
咱们想要给这个 类加一个吃东西的功能,这时使用Java继承来实现
实现代码以下:git
public class Cat extends Animal {
Cat(String name) {
super(name);
}
//新增长吃东西的功能
public void eat(String food){
System.out.print(name+":吃了 "+food);
}
}
复制代码
这样咱们就实现了 吃东西的功能。
而在kotlin咱们不用这样实现了,能够经过叫作 ++扩展++ 的特殊声明来完成。Kotlin 支持 ++扩展函数++ 和 ++扩展属性++。github
声明一个扩展函数咱们须要用一个 被扩展的类来做为它的前缀。
公式以下:设计模式
fun 被扩展类名.扩展函数名( 参数 ){app
//实现代码函数
}ui
咱们来实现上面java实现的功能,代码以下:this
fun Animal.eat(food:String){
print("$name 吃了 $food")
}
复制代码
上面kotlin代码就实现了咱们用java继承实现的新功能,那要怎么调用呢 咱们能够在kotlin中像调用普通的函数来调用这个扩展函数,代码以下:spa
val animal = Animal("cat")
animal.eat("apple")
复制代码
上面介绍了kotlin中怎么调用扩展函数,那在Java中怎么调用了,代码以下:设计
Animal animal = new Animal("cat");
//java 中调用kotlin 扩展函数 Aaa 为扩展函数文件名
AaaKt.eat(animal,"apple");
复制代码
这样咱们就在不用继承该类的状况下增长了 吃东西的新功能。
注意: 咱们能够从上面的java调用中能够看出,扩展并非真正的修改了被扩展类。而只是在kotlin中的调用像是修改了被扩展类。
在kotlin中扩展是静态分发的,不是根据接收者类型的虚方法。也就是说调用扩展函数是由调用所在的表达式类型来决定的,而不是由表达式运行时求值结果决定的。例如:
//扩展了 Animal 和Cat Cat 继承 Animal
fun Animal.getFood() = "苹果"
fun Cat.getFood() = "猫粮"
//在这个方法中 传入类型是 Animal 因此获取到的是"苹果",无论是传入的是Animal 仍是 Animal 的子类 如Cat
fun printFood(food:Animal){
print(food.getFood())
}
fun main(args: Array<String>) {
val cat = Cat("cat")
//如我在这传入的是 Cat 可是 输出出来的仍是 苹果
printFood(cat)
}
复制代码
在这个例子会输出“苹果”,由于咱们在调用扩展函数时只取决于参数 food 的声明类型,该类型是 Animal 类。
若是扩展函数和被扩展类中的成员函数有相同的接收类型、名字和参数,那么这种状况下 ** 老是取成员**。例如:
class Dog {
fun showName(){
print("Dog")
}
}
fun Dog.showName(){
print("Cat")
}
fun main(args: Array<String>) {
Dog().showName()
}
复制代码
若是咱们调用 Dog 类的 showName(),它将输出“Dog”,而不是“Cat”.
这样是否是很不方便,因此扩展函数能够重载相同名字可是不一样签名成员函数。例如:
class Dog {
fun showName(){
print("Dog")
}
}
fun Dog.showName(name:String){
print("Cat")
}
fun main(args: Array<String>) {
Dog().showName("")
}
复制代码
这样咱们调用 showName("")函数,就会输出 “Cat”了。
扩展函数能够为可空的接收者类型定义扩展。这样的扩展能够在对象变量上调用,即便其值为 null,而且能够在函数体内检测 this == null ,这样就能够在没有检测 null 的时候调用成员函数了,列如:
fun Dog?.toString():String{
if (this == null) return "null \n"
return toString()
}
fun main(args: Array<String>) {
var dog:Dog? = null
print(dog.toString())
dog = Dog()
print(dog.toString())
}
复制代码
这段代码 第一次打印输出的是 "null \n" 第二次输入的是改对象的地址。
与函数相似,Kotlin也支持扩展属性。 例如:
class Snake{
var aaa = 1
}
var Snake.size:Int
set(value) {aaa = value}
get() = aaa +1
fun main(args: Array<String>) {
val snake = Snake()
print(snake.size)
snake.size = 3
print(snake.size)
}
复制代码
如上例子所示。
**注意:**因为扩展是没有实际将变量成员插入类中,所以对扩展属性来讲幕后字段是无效的。因此扩展属性不能有初始化器,只能显示的提供 getters/setters 定义。
例如:
//错误:扩展属性不能有初始化
val Snake.bbb = 1
复制代码
如上例子是错误的。
咱们知道在kotlin中是没有 static 这个关键字的,那咱们要怎么实现静态变量呢,那就用到了伴生对象,例如:
class Snake{
var aaa = 1
companion object {
var Bbb = 1
}
}
fun main(args: Array<String>) {
//这样就达到了Java中静态变量同样的效果了
Snake.Bbb
}
复制代码
那咱们怎么对伴生对象进行扩展呢,其实也很简单只是比其余扩展中间加了一个 Companion 。如例:
fun Snake.Companion.foo(){...}
复制代码
如上例,我就就定义了一个名为 foo() 的扩展函数,那咱们这调用这个扩展函数了,其实和普通的扩展函数调用方法是同样的,以下例:
Snake.foo()
复制代码