Kotlin汇总3-接口,可见作用域,扩展,数据类,密封类

1.接口

kotlin的接口比较像Java8,可以有实现的方法

interface MyInterface {
    fun bar()
    fun foo() {
      // optional body
    }
}

接口中的属性可以是抽象的,也可以是提供实现的。

interface MyInterface {
    val prop: Int // abstract

    val propertyWithImplementation: String //实现的属性
        get() = "foo"

    fun foo() {
        print(prop)
    }
}

另外需要注意如果一个类同时实现两个接口,恰好这两个接口都有同一个同样的方法,那么这个类,必须有自己的实现方式,这是Kotlin为了避免冲突的解决方法。

interface A {
    fun foo() { print("A") }
    fun bar()
}

interface B {
    fun foo() { print("B") }
    fun bar() { print("bar") }
}

class C : A {
    override fun bar() { print("bar") }
}

class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super<B>.bar()
    }
}

2.可见作用域修饰符

kotlin有四种可见作用域修饰符:public,private,internal,protected,其中public是默认的,这和java的package可见作用域是默认的不一样。

  • private 是 class类内可见
  • public 是任何地方可见
  • protected是private+子类可见
  • internal 是 module可以见,这个module包括:intellij module, maven/gradle project, 一个ant task的文件集

3. 扩展

扩展就像装饰者模式,不需要继承,给类增加新功能。

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

一般写法是类名<泛型>.方法,所以你可以理解为static调用的方式。

open class C

class D: C()

fun C.foo() = "c"

fun D.foo() = "d"

fun printFoo(c: C) {
    println(c.foo())
}

printFoo(D())

上面的结果是打印c,因为扩展,它依赖于函数定义时传递的类型(如上是C),而不是运行时传递的类型(如上是D)

class C {
    fun foo() { println("member") }
}

fun C.foo() { println("extension") }

如果执行c.foo(),那么结果会是member,就是说如果扩展了同样的方法(包括返回类型,方法名,参数名),那么实际上这个扩展是没有意义的。

但是如果增加了一个覆载的方法就不一养

class C {
    fun foo() { println("member") }
}

fun C.foo(i: Int) { println("extension") }

如果执行c.foo(1), 结果会打印extension,因为扩展了C类中没有的方法,因而这个方法是有效地。

而且还有扩展属性

val <T> List<T>.lastIndex: Int
    get() = size - 1

但是需要注意属性扩展只能使用set/get,而不能直接初始化,比如下面代码是错误的

val Foo.bar = 1 // error: initializers are not allowed for extension properties

一般情况下扩展会应用到top-level

package foo.bar

fun Baz.goo() { ... } 

也可以定义到类里作为成员函数

class D {
    fun bar() { ... }
}

class C {
    fun baz() { ... }

    fun D.foo() {
        bar()   // calls D.bar
        baz()   // calls C.baz
    }

    fun caller(d: D) {
        d.foo()   // call the extension function
    }
}

在扩展里调用它所在类的方法需要如下(this@C)

class C {
    fun D.foo() {
        toString()         // calls D.toString()
        this@C.toString()  // calls C.toString()
    }

扩展的目的是为了简化代码如下:

// Java
Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list))

//kotlin扩展简化后,代码可阅读性也提高了
// Java
list.swap(list.binarySearch(otherList.max()), list.max())

3.数据类

有时候定义一个类仅仅是为了使用它的数据,那么可以定义数据类

data class User(val name: String, val age: Int) // 使用data关键字

然后编译器会帮我们创建好equals/hashcode, toString(),copy方法

fun copy(name: String = this.name, age: Int = this.age) = User(name, age) 

val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)

4.密封类

密封类是为了维护严格的类层次关系。使用sealed关键字修饰,密封类可以有子类,但是它和它的子类都必须在一个kotlin文件中声明.

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值