暂时跳过昨天那几个坑,继续跟着官方文档懵逼。
坑1、使用interface定义接口,与java8类似,可以有抽象方法的声明,也可以有实现。
interfaceMyInterface {
funbar()
funfoo() {
// 可选的方法体
}
}
悲剧了,java8不熟悉,又来恶补一下。
1、java8之前,接口中只能有全局静态常量和全局抽象方法。java8中允许有方法的实现,即默认方法,用default修饰。(类似地,已经有Connection集合,同时又有Connections工具类并且Connections中均为操作集合的方法,因此应该全放入Connection中)
public interfaceMyIF {
defaultString getName() {
return"小猴子";
}
}
2、类优先原则。(1)、若一个接口中定义了一个默认方法,而另外一个父类中又定义了一个同名的方法时,接口中同名同参的默认方法会被忽略。(2)两接口方法冲突时子类会报错,需要在子类中重写该方法,并调用“接口名.super.方法”。
3、Java8接口中可以有静态方法,调用方法为“接口名.方法”
言归正传,回到kotlin。
Kotlin接口与抽象类不同的是接口无法保存状态。。。没懂,求解释!
坑2、它可以有属性但必须声明为抽象或提供访问器实现。在接口中声明的属性不能有幕后字段。。。自始至终就没懂幕后字段是啥
interfaceMyInterface {
abstract val prop: Int // 抽象的,这里可以省略abstract关键字
valpropertyWithImplementation: String
get() = "foo"
funfoo() {
print(prop)
}
}
classChild : MyInterface {
override val prop: Int = 29
}
坑3、类似与java8,接口冲突时需要在子类中重写该方法,并调用“super<接口名>.方法名”
坑4、kotlin中有四个可见性修饰符,默认为public。类、对象、接口、构造函数、方法、属性和它们的setter都可以有可见性修饰符。
(1)函数、属性和类、对象和接口可以在顶层声明,即直接在包内:
如果你不指定任何可见性修饰符,默认为 public ,这意味着你的声明 将随处可见;
如果你声明为 private ,它只会在声明它的文件内可见;
如果你声明为 internal ,它会在相同模块内随处可见;
protected 不适用于顶层声明。
// 文件名:example.kt
packagefoo
private funfoo() {}// 在 example.kt 内可见
public varbar: Int = 5// 该属性随处可见
private set // setter 只在 example.kt 内可见
internal valbaz=6// 相同模块内可见
(2)对于类内部声明的成员:
private ——意味着只在当前类内部(包含其所有成员)可见;
protected ——在类中及其子类中可见。
internal —— 能见到类声明的本模块内的任何客户端都可见其 internal 成员;
public —— 能见到类声明的任何客户端都可见其 public 成员。
open classOuter {
private val a=1
protected open val b=2
internal val c=3
vald=4// 默认 public
protected class Nested {
public val e: Int = 5
}
}
classSubclass : Outer() {
// a 不可见
// b、c、d 可见
// Nested 和 e 可见
override val b=5// “b”为 protected
}
classUnrelated(o: Outer) {
// o.a、o.b 不可见
// o.c 和 o.d 可见(相同模块)
// Outer.Nested 不可见,Nested::e 也不可见
}
坑5、构造函数的可见性必须有显示的constructor关键字。并在前加修饰符。默认情况下为public类型,故取决于类的可见性。
坑6、局部变量、函数和类不能有可见性修饰符。瞬间懵逼了,前面不还说“类和方法可以有可见性修饰符”?因为这里强调的是局部。。。通俗地说是函数中的局部变量、函数和类不能有可见性修饰符。。。原来函数中还能包含函数,醉了。
坑7、前面提到了internal表示模块内可见,那模块是啥呢,模块是编译在一起的一套kotlin文件:
一个 IntelliJ IDEA 模块;
一个 Maven 或者 Gradle 项目;
一次<kotlinc> Ant 任务执行所编译的一套文件。
其实我仍然没懂模块是啥。。。
坑8、kotlin支持扩展函数和扩展属性,用于扩展一个类的功能而无需继承或使用类似装饰者模式类似的设计模式。
例如给MutableList<Int>添加swap函数
funMutableList<Int>.swap(index1: Int, index2: Int) {
valtmp =this[index1]// “this”对应该列表
this[index1] = this[index2]
this[index2] = tmp
}
funmain(args: Array<String>) {
vall =mutableListOf(1,2,3,4)
l.swap(1,3)
l.forEach{
println(it)
}
}
当然,该方法也可以被泛化。为了在接收者类型表达式中使用泛型,需要在函数名前面声明泛型参数。。。没懂,照葫芦画瓢吧。。。
fun<T> MutableList<T>.swap(index1: Int, index2: Int) {
valtmp =this[index1]// “this”对应该列表
this[index1] = this[index2]
this[index2] = tmp
}
坑9、扩展函数是静态分发的。如下,调用的扩展函数只取决于参数声明的类型
open classC
classD: C()
funC.foo() ="c"
funD.foo() ="d"
funprintFoo(c:C) {
println(c.foo())
}
funmain(args: Array<String>) {
printFoo(D())
}
成员函数和扩展函数冲突(函数名和参数均一致)时,取成员函数。
classC {
funfoo() {println("member") }
}
funC.foo() {println("extension") }
为可空接收者类型定义扩展:
坑10、扩展属性不能有初始化器,他们的行为只能由显式提供的getter是/setters定义。
val<T> List<T>.lastIndex: Int
get() = size-1
坑11、伴生对象也能定义扩展函数和属性,伴生对象是啥?。。。后面慢慢了解。
坑12、我们通常直接在包里定义扩展,如果需要使用包外的扩展,需要导入包。
坑13、扩展声明为成员这个又没看懂,悲剧了。。。
今天就到此为止吧。。。