Kotlin 類能夠包含:構造函數和初始化代碼塊、函數、屬性、內部類、對象聲明。java
Kotlin 中使用關鍵字 class 聲明類,後面緊跟類名。編程
類的屬性能夠用關鍵字 var 聲明爲可變的,不然使用只讀關鍵字 val 聲明爲不可變。swift
咱們能夠像使用普通函數那樣使用構造函數建立類實例:後端
val site = Runoob() // Kotlin 中沒有 new 關鍵字
Kotlin 中類不能有字段。提供了 Backing Fields(後端變量) 機制,備用字段使用field關鍵字聲明,field 關鍵詞只能用於屬性的訪問器ide
class ClassA { var name: String = "zhangsan" get() = field.toUpperCase() set var age: Int = 0 get() = field set(value) { if (value < 10) { field = value } else { field = -1 } } var city: String = "jx" fun foo() { print("foo") } }
fun main(args:Array<String>) { val site = ClassA(); site.foo() site.name = "lisi" println("name = ${site.name}")//LISI site.age = 30 println("age = ${site.age}") //-1 }
非空屬性必須在定義的時候初始化,kotlin提供了一種能夠延遲初始化的方案,使用 lateinit 關鍵字描述屬性:函數
public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() // dereference directly } }
主構造器中不能包含任何代碼,初始化代碼能夠放在初始化代碼段中,初始化代碼段使用 init 關鍵字做爲前綴。測試
class Person constructor(firstName: String) { init { println("FirstName is $firstName") } }
注意:主構造器的參數能夠在初始化代碼段中使用,也能夠在類主體n定義的屬性初始化代碼中使用。 一種簡潔語法,能夠經過主構造器來定義屬性並初始化屬性值(能夠是var或val):網站
class People(val firstName: String, val lastName: String) { //... }
若是構造器有註解,或者有可見度修飾符,這時constructor關鍵字是必須的,註解和修飾符要放在它以前。this
類也能夠有二級構造函數,須要加前綴 constructor:url
class Person { constructor(parent: Person) { parent.children.add(this) } }
若是類有主構造函數,每一個次構造函數都要,或直接或間接經過另外一個次構造函數代理主構造函數。在同一個類中代理另外一個構造函數使用 this 關鍵字:
class ClassB(val name:String)
{
constructor(name:String,age:Int):this(name)
init {
}
}
若是一個非抽象類沒有聲明構造函數(主構造函數或次構造函數),它會產生一個沒有參數的構造函數。構造函數是 public 。若是你不想你的類有公共的構造函數,你就得聲明一個空的主構造函數:
class DontCreateMe private constructor () { }
注意:在 JVM 虛擬機中,若是主構造函數的全部參數都有默認值,編譯器會生成一個附加的無參的構造函數,這個構造函數會直接使用默認值。這使得 Kotlin 能夠更簡單的使用像 Jackson 或者 JPA 這樣使用無參構造函數來建立類實例的庫。
實例
class Runoob constructor(name: String) { // 類名爲 Runoob // 大括號內是類體構成 var url: String = "http://www.runoob.com" var country: String = "CN" var siteName = name init { println("初始化網站名: ${name}") } // 次構造函數 constructor (name: String, alexa: Int) : this(name) { println("Alexa 排名 $alexa") } fun printTest() { println("我是類的函數") } } fun main(args: Array<String>) { val runoob = Runoob("菜鳥教程", 10000) println(runoob.siteName) println(runoob.url) println(runoob.country) runoob.printTest() }
輸出結果:
初始化網站名: 菜鳥教程 Alexa 排名 10000 菜鳥教程 http://www.runoob.com CN 我是類的函數
抽象是面向對象編程的特徵之一,類自己,或類中的部分紅員,均可以聲明爲abstract的。抽象成員在類中不存在具體的實現。
注意:無需對抽象類或抽象成員標註open註解。
open class Base { open fun f() {} } abstract class Derived : Base() { override abstract fun f() }
咱們能夠把類嵌套在其餘類中,看如下實例:
class Outer { // 外部類 private val bar: Int = 1 class Nested { // 嵌套類 fun foo() = 2 } } fun main(args: Array<String>) { val demo = Outer.Nested().foo() // 調用格式:外部類.嵌套類.嵌套類方法/屬性 println(demo) // == 2 }
內部類使用 inner 關鍵字來表示。
內部類會帶有一個對外部類的對象的引用,因此內部類能夠訪問外部類成員屬性和成員函數。
class Outer { private val bar: Int = 1 var v = "成員屬性" /**嵌套內部類**/ inner class Inner { fun foo() = bar // 訪問外部類成員 fun innerTest() { var o = this@Outer //獲取外部類的成員變量 println("內部類能夠引用外部類的成員,例如:" + o.v) } } } fun main(args: Array<String>) { val demo = Outer().Inner().foo() println(demo) // 1 val demo2 = Outer().Inner().innerTest() println(demo2) // 內部類能夠引用外部類的成員,例如:成員屬性 }
爲了消除歧義,要訪問來自外部做用域的 this,咱們使用this@label,其中 @label 是一個 代指 this 來源的標籤。
使用對象表達式來建立匿名內部類:
class Test { var v = "成員屬性" fun setInterFace(test: TestInterFace) { test.test() } } /** * 定義接口 */ interface TestInterFace { fun test() } fun main(args: Array<String>) { var test = Test() /** * 採用對象表達式來建立接口對象,即匿名內部類的實例。 */ test.setInterFace(object : TestInterFace { override fun test() { println("對象表達式建立匿名內部類的實例") } }) }
類的修飾符包括 classModifier 和_accessModifier_:
classModifier: 類屬性修飾符,標示類自己特性。
abstract // 抽象類 final // 類不可繼承,默認屬性 enum // 枚舉類 open // 類可繼承,類默認是final的 annotation // 註解類
accessModifier: 訪問權限修飾符
private // 僅在同一個文件中可見 protected // 同一個文件中或子類可見 public // 全部調用的地方均可見 internal // 同一個模塊中可見
Kotlin 中全部類都繼承該 Any 類,它是全部類的超類,對於沒有超類型聲明的類是默認超類:
class Example // 從 Any 隱式繼承
Any 默認提供了三個函數:
equals() hashCode() toString()
注意:Any 不是 java.lang.Object。
若是一個類要被繼承,能夠使用 open 關鍵字進行修飾。
open class Base(p: Int) // 定義基類 class Derived(p: Int) : Base(p)
若是子類有主構造函數, 則基類必須在主構造函數中當即初始化
open class Person(var name : String, var age : Int){// 基類 } class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) { } // 測試 fun main(args: Array<String>) { val s = Student("Runoob", 18, "S12346", 89) println("學生名: ${s.name}") println("年齡: ${s.age}") println("學生號: ${s.no}") println("成績: ${s.score}") }
若是子類沒有主構造函數,則必須在每個二級構造函數中用 super 關鍵字初始化基類,或者在代理另外一個構造函數。初始化基類時,能夠調用基類的不一樣構造方法。
/**用戶基類**/ open class Person(name:String){ /**次級構造函數**/ constructor(name:String,age:Int):this(name){ //初始化 println("-------基類次級構造函數---------") } } /**子類繼承 Person 類**/ class Student:Person{ /**次級構造函數**/ constructor(name:String,age:Int,no:String,score:Int):super(name,age){ println("-------繼承類次級構造函數---------") println("學生名: ${name}") println("年齡: ${age}") println("學生號: ${no}") println("成績: ${score}") } } fun main(args: Array<String>) { var s = Student("Runoob", 18, "S12345", 89) }
在基類中,使用fun聲明函數時,此函數默認爲final修飾,不能被子類重寫。若是容許子類重寫該函數,那麼就要手動添加 open 修飾它, 子類重寫方法使用 override 關鍵詞:
/**用戶基類**/ open class Person{ open fun study(){ // 容許子類重寫 println("我畢業了") } } /**子類繼承 Person 類**/ class Student : Person() { override fun study(){ // 重寫方法 println("我在讀大學") } } fun main(args: Array<String>) { val s = Student() s.study(); }
若是有多個相同的方法(繼承或者實現自其餘類,如A、B類),則必需要重寫該方法,使用super範型去選擇性地調用父類的實現。
open class A { open fun f () { print("A") } fun a() { print("a") } } interface B { fun f() { print("B") } //接口的成員變量默認是 open 的 fun b() { print("b") } } class C() : A() , B{ override fun f() { super<A>.f()//調用 A.f() super<B>.f()//調用 B.f() } } fun main(args: Array<String>) { val c = C() c.f(); }
C 繼承自 a() 或 b(), C 不只能夠從 A 或則 B 中繼承函數,並且 C 能夠繼承 A()、B() 中共有的函數。此時該函數在中只有一個實現,爲了消除歧義,該函數必須調用A()和B()中該函數的實現,並提供本身的實現。
屬性重寫使用 override 關鍵字,屬性必須具備兼容類型,每個聲明的屬性均可以經過初始化程序或者getter方法被重寫。
你能夠用一個var屬性重寫一個val屬性,可是反過來不行。由於val屬性自己定義了getter方法,重寫爲var屬性會在衍生類中額外聲明一個setter方法
你能夠在主構造函數中使用 override 關鍵字做爲屬性聲明的一部分:
interface Foo { val count: Int } class Bar1(override val count: Int) : Foo class Bar2 : Foo { override var count: Int = 0 }