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

来源:互联网 发布:滁州学院网络电视台 编辑:程序博客网 时间:2024/05/01 06:30

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 Cclass 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.barfun 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()    }

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

// JavaCollections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list))//kotlin扩展简化后,代码可阅读性也提高了// Javalist.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 Exprdata 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}