1、面向对象-抽象类与接口
1)什么是接口
接口,直观理解就是一种约定
kotlin的接口与Objcet-C的Protocal比较类似
举例:
interface InputDevice{
fun input(event:Any)
}
2}接口
a.接口不能有状态
b.必须由类对其进行实现后使用
3)抽象类
a.实现了一部分协议的半成品
b.可以有状态,可以有方法实现
c.必须由子类继承后使用
4)抽象类和接口的共性
a.比较抽象,不能直接实例化
b.有需要子类(实现类)实现的方法
c.父类(接口)变量可以接受子类(实现类)的实例赋值
d.抽象类反映本质,接口体现能力
5)抽象类和接口的区别
a.抽象类有状态,接口没有状态
b.抽象类有方法实现,接口只能有无状态的默认实现
c.抽象类只能单继承,接口可以多实现
2、继承
1)父类需要open才可以被继承
2)父类方法、属性需要open才可以被复写
3)接口、接口方法、抽象类默认为open
4)复写父类(实现接口)的方法需要override关键字
5)class D:A(),B,C
6)继承类时实际上是调用了父类构造方法
7)类只能单继承,接口可以多实现
接口代理
class Leader(val dr:Drive,val pp:PPT):D by dr,P by pp
接口方法实现交给代理类实现
事例:
interface D{
fun drive()
}
interface P{
fun write()
}
class Drive:D{
override fun drive(){
println("开车")
}
}
class PPT:P{
override fun write(){
println("写ppt...")
}
}
//接口代理
class Leader(val dr:Drive,val pp:PPT):D by dr,P by pp
fun main(args: Array) {
val lead = Leader(pp=PPT(),dr=Drive())
//接口代理调用
lead.drive()
lead.write()
}
接口方法冲突
1)接口方法可以有默认实现
2)方法名、方法参数以及返回值相同,否则会有冲突
3)子类(实现类)必须复写冲突方法
4)super<[父类(接口)名]>.[方法名]([参数列表])
事例:
open class A {
open fun x(): Int = 'A'.toInt()
}
interface B {
fun x(): Int = 'B'.toInt()
}
interface C {
fun x(): Int = 'C'.toInt()
}
class F(var y: Int) : B, C, A() {
override fun x(): Int {
return when {
y > 0 -> super.x()
y < 0 -> super.x()
else -> super.x()
}
}
}
fun main(args: Array) {
println(F(-1).x())//B
println(F(0).x())//C
println(F(1).x())//A
}
运行结果:66,67,65
3、类及其成员的可见性(private,protected,internal,public)
注:internal在和java兼容方面依旧存在问题,暂不建议使用
4、object
1)只有一个实例的类
2)不能自定义构造方法
3)可以实现接口、继承父类
4)本质上就是单例模式最基本的实现
注:如果不考虑懒加载等因素,Kotlin中写单例,使用的是object。
5、伴生对象与静态成员
1)每个类可以对应一个伴生对象
2)伴生对象的成员全局独一份
3)伴生对象的成员类似Java中的静态成员
4)静态成员考虑用包级函数、变量替代
5)JvmField和JvmStatic的使用
事例:
无论加不加@JvmStatic和@JvmField在kotlin都可正常调用,而Java若想调用,则必须添加这两个注解。
class Latitude private constructor(val d:Double){
companion object {
@JvmStatic
fun la(d: Double):Latitude{
return Latitude(d)
}
@JvmStatic
fun getD(latitude: Latitude):Latitude{
return Latitude(latitude.d);
}
@JvmField
val TAG = "TAG"
}
}
kotlin中调用
fun main(args: Array) {
var latitude = Latitude.la(6.66)
val latitude2 = Latitude.getD(latitude)
val tag = Latitude.TAG
}
java中调用
Latitude latitude = Latitude.la(3.234);
Latitude latitude2 = Latitude.getD(latitude);
String tag = Latitude.TAG;
6、方法重载与默认参数
1)方法重载
a.Overloads
b.名称相同、参数不同的方法
c.Jvm函数签名的概念:函数名、参数列表
d.跟返回值无关
2)默认参数
a.为函数参数设定一个默认值
b.可以为任意位置的参数设置默认值
c.函数调用产生混淆时用具名参数
3)方法重载和默认参数
a.二者的相关性以及@JvmOverloads(给java中调用kotin中的默认参数时使用)
事例:
class Overloads {
// fun a(): Int {
// return 0
// }
// @JvmOverloads
fun a(int: Int = 0): Int {
return int
}
fun a(str: String): Int {
return str.toInt()
}
}
fun main(args: Array) {
val ovarLoads = Overloads()
ovarLoads.a(1)
ovarLoads.a("2")
//kotlin中调用
println(ovarLoads.a())
}
b.避免定义关系不大的重载
c.不好的设计
List.remove(Int)
List.remove(Object)
事例:
7、扩展成员
为现有类添加方法属性
fun X.y():Z{...}
val X.m 注:扩展属性不能初始化,类似接口属性
Java调用扩展成员类似调用静态方法
事例:
fun main(args: Array) {
println("abc".times(6))
println("a" * 6)
println("a".a )
println("b".b)
}
operator fun String.times(num: Int): String {
val sb = StringBuffer()
if (num > 0) {
for (i in 0 until num) {
sb.append(this)
}
}
return sb.toString()
}
val String.a
get() = 5
var String.b
set(value){}
get() = 6
运行结果:
8、属性代理
1)定义方法
val/var
: by
2)代理者需要实现相应的setValue/getValue方法
事例:
class Delegate {
val x1 by lazy {
"Hello X"
}
var x2 by X()
var x3 by X()
}
class X {
private var value: String? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("getValue---------$thisRef--------------------${property.name}")
return value ?: ""
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("setValue------------$thisRef----------------${property.name}-----------$value")
this.value = value
}
}
fun main(args: Array) {
val delegate = Delegate()
println(delegate.x1)
println(delegate.x2)
println(delegate.x3)
delegate.x3 = "666666666666666666666"
println(delegate.x3)
}
输出结果:
9、数据类(allOpen,noArg插件,再见,javaBean)
1)data class默认实现了copy、toString、hashCode、equals等方法
2)componentN方法
3)allOpen和noArg插件
10、内部类(this@Outter,this@Inner)
内部类
a.定义在类内部的类
b.与类成员有相似的访问控制
c.默认是静态内部类,非静态用inner关键字
d.this@Outter,this@Inner的用法
匿名内部类
a.没有定义名字的内部类
b.类名编译时生成,类似Outter$1.class这样的类名
c.可继承父类、实现多个接口,与Java注意区别
11、枚举(enum)
实例可数的类,注意枚举也是类
可以修改构造,添加成员
可以提升代码的表现力,也有一定的性能开销
12、密封类(sealed Class)
1)子类可数
kotlin版本<1.1,子类必须定义为封闭类的内部类
v1.1,子类只需要与密封类在同一文件中
2)与枚举类似却又不同