// 類聲明 class Invoice { } // 空的類 class Empty // 主體構造器(primary constructor) class Person constructor(firstName: String) { } // 省略了關鍵字的主體構造器 class Person(firstName: String) { } // 主體構造器的代碼必須寫在init(初始化)代碼塊裏面 class Customer(name: String) { init { logger.info("Customer initialized with value ${name}") } } // 屬性 class Customer(name: String) { val customerKey = name.toUpperCase() } // 主體構造器裏包含多個屬性 class Person(val firstName: String, val lastName: String, var age: Int) { // ... } // 帶註解和訪問權限的主體構造器 class Customer public @Inject constructor(name: String) { ... } // 從屬構造器(secondary constructor) class Person { constructor(parent: Person) { parent.children.add(this) } } // 從屬構造器調用主體構造器 class Person(val name: String) { constructor(name: String, parent: Person) : this(name) { parent.children.add(this) } } // 沒法建立實例的類,由於主體構造器被聲明爲私有訪問權限 class DontCreateMe private constructor () { } // 具備缺省值參數的主體構造器 class Customer(val customerName: String = "") // 生成類的實例不須要new val invoice = Invoice() val customer = Customer("Joe Smith")
注意類和類中的方法在Kotlin語言中缺省不可繼承,須要被繼承的類和方法必須使用open關鍵字。
而接口和接口中的方法缺省可繼承,不須要open關鍵字。maven
// 隱式繼承自Any class Example // open表示可繼承 // 子類主體構造器調用基類主體構造器 open class Base(p: Int) class Derived(p: Int) : Base(p) // 子類從屬構造器調用基類的構造器 class MyView : View { constructor(ctx: Context) : super(ctx) constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) } // 覆蓋基類的方法 open class Base { open fun v() {} fun nv() {} } class Derived() : Base() { override fun v() {} } // 覆蓋基類的方法但子類不可繼承 open class AnotherDerived() : Base() { final override fun v() {} } // 覆蓋基類的屬性 open class Foo { open val x: Int get { ... } } class Bar1 : Foo() { override val x: Int = ... } // 在主體構造器中覆蓋接口中的屬性 interface Foo { val count: Int } class Bar1(override val count: Int) : Foo class Bar2 : Foo { override var count: Int = 0 } // 使用特殊語法解決接口的多重繼承問題 // 接口中的方法都是open,便可繼承的 open class A { open fun f() { print("A") } fun a() { print("a") } } interface B { fun f() { print("B") } fun b() { print("b") } } class C() : A(), B { override fun f() { super<A>.f() // 調用 A.f() super<B>.f() // 調用 B.f() } } // 繼承基類的方法但不提供實現,子類仍然能夠是抽象類 open class Base { open fun f() {} } abstract class Derived : Base() { override abstract fun f() }
// 屬性聲明 class Address { var name: String = ... var street: String = ... var city: String = ... var state: String? = ... var zip: String = ... } // 屬性訪問 fun copyAddress(address: Address): Address { val result = Address() result.name = address.name result.street = address.street // ... return result } // 可讀可寫屬性 var allByDefault: Int? var initialized = 1 // 只讀屬性 val simple: Int? val inferredType = 1 // 只讀屬性 自定義getter val isEmpty: Boolean get() = this.size == 0 // 可讀可寫屬性 自定義getter setter var stringRepresentation: String get() = this.toString() set(value) { setDataFromString(value) } // 屬性類型自動推導 val isEmpty get() = this.size == 0 // setter爲公有但getter爲私有 var setterVisibility: String = "abc" private set // setter帶註解 var setterWithAnnotation: Any? = null @Inject set // 經過field標識符訪問屬性背後的字段(backing fields) var counter = 0 set(value) { if (value >= 0) field = value } // 公有屬性以及背後的私有屬性(backing properties) private var _table: Map<String, Int>? = null public val table: Map<String, Int> get() { if (_table == null) { _table = HashMap() } return _table ?: throw AssertionError("Set to null by another thread") } // 編譯期常量 const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated" @Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... } // 須要延遲初始化的屬性使用 lateinit 來修飾 public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } }
// 接口中的方法能夠有缺省實現 interface MyInterface { fun bar() fun foo() { // ... } } // 在類中實現接口的方法 class Child : MyInterface { override fun bar() { // ... } } // 在類中實現接口的屬性 interface MyInterface { val prop: Int val propertyWithImplementation: String get() = "foo" fun foo() { print(prop) } } class Child : MyInterface { override val prop: Int = 29 } // 使用特殊語法解決接口的多重繼承問題 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() } }
這個術語太怪癖,其實就是其餘語言中的訪問權限。
一共四種可見性(訪問權限):ide
局部的變量,類以及函數沒有可見性。
模塊是指物理上的模塊(IntelliJ IDEA模塊,maven和gradle工程等)函數
// 文件示例 // file name: example.kt package foo private fun foo() {} // visible inside example.kt public var bar: Int = 5 // property is visible everywhere private set // setter is visible only in example.kt internal val baz = 6 // visible inside the same module
// 類的示例 open class Outer { private val a = 1 protected open val b = 2 internal val c = 3 val d = 4 // public by default protected class Nested { public val e: Int = 5 } } class Subclass : Outer() { // a is not visible // b, c and d are visible // Nested and e are visible override val b = 5 // 'b' is protected } class Unrelated(o: Outer) { // o.a, o.b are not visible // o.c and o.d are visible (same module) // Outer.Nested is not visible, and Nested::e is not visible either }
// 主體構造器的可見性 class C private constructor(a: Int) { ... }
包括擴展函數,擴展屬性
擴展函數能夠是全局的,也能夠聲明在某個類或伴生對象之中gradle
// 擴展函數(extension functions),內部使用 this 指代調用方對象 fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp } val l = mutableListOf(1, 2, 3) l.swap(0, 2) // 靜態分發(dispatched statically) open class C class D: C() fun C.foo() = "c" fun D.foo() = "d" fun printFoo(c: C) { println(c.foo()) } printFoo(D()) // 輸出 c // 同名時成員函數優先 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 // 擴展可空類型 fun Any?.toString(): String { if (this == null) return "null" return toString() } // 擴展屬性(extension properties) val <T> List<T>.lastIndex: Int get() = size - 1 // 擴展伴生對象(companion object) class MyClass { companion object { } // will be called "Companion" } fun MyClass.Companion.foo() { // ... } // 擴展與包的關係 package foo.bar fun Baz.goo() { ... } // package com.example.usage import foo.bar.goo import foo.bar.* fun usage(baz: Baz) { baz.goo() } // 分發接收者(dispatch receiver)及擴展接收者(extension receiver) 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 } } // 擴展接收者優先於分發接收者 class C { fun D.foo() { toString() // calls D.toString() this@C.toString() // calls C.toString() } } // 分發接收者有多態,擴展接收者沒有多態 open class D { } class D1 : D() { } open class C { open fun D.foo() { println("D.foo in C") } open fun D1.foo() { println("D1.foo in C") } fun caller(d: D) { d.foo() } } class C1 : C() { override fun D.foo() { println("D.foo in C1") } override fun D1.foo() { println("D1.foo in C1") } } C().caller(D()) // prints "D.foo in C" C1().caller(D()) // prints "D.foo in C1" - dispatch receiver is resolved virtually C().caller(D1()) // prints "D.foo in C" - extension receiver is resolved statically