Kotlin 類可以包含:構(gòu)造函數(shù)和初始化代碼塊、函數(shù)、屬性、內(nèi)部類、對象聲明。
Kotlin 中使用關(guān)鍵字 class 聲明類,后面緊跟類名:
class W3cschool{ // 類名為 W3cschool
// 大括號內(nèi)是類體構(gòu)成
}
我們也可以定義一個(gè)空類:
class Empty
可以在類中定義成員函數(shù):
class W3cschool() {
fun foo() { print("Foo") } // 成員函數(shù)
}
類的屬性可以用關(guān)鍵字 var 聲明為可變的,否則使用只讀關(guān)鍵字 val 聲明為不可變。
class W3cschool{
var name: String = ……
var url: String = ……
var city: String = ……
}
我們可以像使用普通函數(shù)那樣使用構(gòu)造函數(shù)創(chuàng)建類實(shí)例:
val site = W3cschool() // Kotlin 中沒有 new 關(guān)鍵字
要使用一個(gè)屬性,只要用名稱引用它即可
site.name // 使用 . 號來引用
site.url
Koltin 中的類可以有一個(gè) 主構(gòu)造器,以及一個(gè)或多個(gè)次構(gòu)造器,主構(gòu)造器是類頭部的一部分,位于類名稱之后:
class Person constructor(firstName: String) {}
如果主構(gòu)造器沒有任何注解,也沒有任何可見度修飾符,那么constructor關(guān)鍵字可以省略。
class Person(firstName: String) {
}
屬性聲明的完整語法:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
getter 和 setter 都是可選
如果屬性類型可以從初始化語句或者類的成員函數(shù)中推斷出來,那就可以省去類型,val不允許設(shè)置setter函數(shù),因?yàn)樗侵蛔x的。
var allByDefault: Int? // 錯(cuò)誤: 需要一個(gè)初始化語句, 默認(rèn)實(shí)現(xiàn)了 getter 和 setter 方法
var initialized = 1 // 類型為 Int, 默認(rèn)實(shí)現(xiàn)了 getter 和 setter
val simple: Int? // 類型為 Int ,默認(rèn)實(shí)現(xiàn) getter ,但必須在構(gòu)造函數(shù)中初始化
val inferredType = 1 // 類型為 Int 類型,默認(rèn)實(shí)現(xiàn) getter
以下實(shí)例定義了一個(gè) Person 類,包含兩個(gè)可變變量 lastName 和 no,lastName 修改了 getter 方法,no 修改了 setter 方法。
class Person {
var lastName: String = "zhang"
get() = field.toUpperCase() // 將變量賦值后轉(zhuǎn)換為大寫
set
var no: Int = 100
get() = field // 后端變量
set(value) {
if (value < 10) { // 如果傳入的值小于 10 返回該值
field = value
} else {
field = -1 // 如果傳入的值大于等于 10 返回 -1
}
}
var heiht: Float = 145.4f
private set
}
// 測試
fun main(args: Array<String>) {
var person: Person = Person()
person.lastName = "wang"
println("lastName:${person.lastName}")
person.no = 9
println("no:${person.no}")
person.no = 20
println("no:${person.no}")
}
輸出結(jié)果為:
lastName:WANG
no:9
no:-1
Kotlin 中類不能有字段。提供了 Backing Fields(后端變量) 機(jī)制,備用字段使用field關(guān)鍵字聲明,field 關(guān)鍵詞只能用于屬性的訪問器,如以上實(shí)例:
var no: Int = 100
get() = field // 后端變量
set(value) {
if (value < 10) { // 如果傳入的值小于 10 返回該值
field = value
} else {
field = -1 // 如果傳入的值大于等于 10 返回 -1
}
}
非空屬性必須在定義的時(shí)候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關(guān)鍵字描述屬性:
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // dereference directly
}
}
主構(gòu)造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中,初始化代碼段使用 init 關(guān)鍵字作為前綴。
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
注意:主構(gòu)造器的參數(shù)可以在初始化代碼段中使用,也可以在類主體n定義的屬性初始化代碼中使用。 一種簡潔語法,可以通過主構(gòu)造器來定義屬性并初始化屬性值(可以是var或val):
class People(val firstName: String, val lastName: String) {
//...
}
如果構(gòu)造器有注解,或者有可見度修飾符,這時(shí)constructor關(guān)鍵字是必須的,注解和修飾符要放在它之前。
創(chuàng)建一個(gè) W3cschool類,并通過構(gòu)造函數(shù)傳入網(wǎng)站名:
class W3cschool constructor(name: String) { // 類名為 W3cschool
// 大括號內(nèi)是類體構(gòu)成
var url: String = "http://www.w3cschool.com"
var country: String = "CN"
var siteName = name
init {
println("初始化網(wǎng)站名: ${name}")
}
fun printTest() {
println("我是類的函數(shù)")
}
}
fun main(args: Array<String>) {
val w3cschool= W3cschool("編程獅")
println(w3cschool.siteName)
println(w3cschool.url)
println(w3cschool.country)
w3cschool.printTest()
}
輸出結(jié)果為:
初始化網(wǎng)站名: 編程獅
編程獅
http://www.w3cschool.com
CN
我是類的函數(shù)
類也可以有二級構(gòu)造函數(shù),需要加前綴 constructor:
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
如果類有主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)都要,或直接或間接通過另一個(gè)次構(gòu)造函數(shù)代理主構(gòu)造函數(shù)。在同一個(gè)類中代理另一個(gè)構(gòu)造函數(shù)使用 this 關(guān)鍵字:
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}
如果一個(gè)非抽象類沒有聲明構(gòu)造函數(shù)(主構(gòu)造函數(shù)或次構(gòu)造函數(shù)),它會產(chǎn)生一個(gè)沒有參數(shù)的構(gòu)造函數(shù)。構(gòu)造函數(shù)是 public 。如果你不想你的類有公共的構(gòu)造函數(shù),你就得聲明一個(gè)空的主構(gòu)造函數(shù):
class DontCreateMe private constructor () {
}
注意:在 JVM 虛擬機(jī)中,如果主構(gòu)造函數(shù)的所有參數(shù)都有默認(rèn)值,編譯器會生成一個(gè)附加的無參的構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)會直接使用默認(rèn)值。這使得 Kotlin 可以更簡單的使用像 Jackson 或者 JPA 這樣使用無參構(gòu)造函數(shù)來創(chuàng)建類實(shí)例的庫。class Customer(val customerName: String = "")
class W3cschool constructor(name: String) { // 類名為 W3cschool
// 大括號內(nèi)是類體構(gòu)成
var url: String = "http://www.w3cschool .com"
var country: String = "CN"
var siteName = name
init {
println("初始化網(wǎng)站名: ${name}")
}
// 次構(gòu)造函數(shù)
constructor (name: String, alexa: Int) : this(name) {
println("Alexa 排名 $alexa")
}
fun printTest() {
println("我是類的函數(shù)")
}
}
fun main(args: Array<String>) {
val w3cschool = W3cschool ("編程獅", 10000)
println(w3cschool .siteName)
println(w3cschool .url)
println(w3cschool .country)
w3cschool .printTest()
}
輸出結(jié)果為:
初始化網(wǎng)站名: 編程獅
Alexa 排名 10000
編程獅
http://www.w3cschool.com
CN
我是類的函數(shù)
抽象是面向?qū)ο缶幊痰奶卣髦?,類本身,或類中的部分成員,都可以聲明為abstract的。抽象成員在類中不存在具體的實(shí)現(xiàn)。
注意:無需對抽象類或抽象成員標(biāo)注open注解。
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
我們可以把類嵌套在其他類中,看以下實(shí)例:
class Outer { // 外部類
private val bar: Int = 1
class Nested { // 嵌套類
fun foo() = 2
}
}
fun main(args: Array<String>) {
val demo = Outer.Nested().foo() // 調(diào)用格式:外部類.嵌套類.嵌套類方法/屬性
println(demo) // == 2
}
內(nèi)部類使用 inner 關(guān)鍵字來表示。
內(nèi)部類會帶有一個(gè)對外部類的對象的引用,所以內(nèi)部類可以訪問外部類成員屬性和成員函數(shù)。
class Outer {
private val bar: Int = 1
var v = "成員屬性"
/**嵌套內(nèi)部類**/
inner class Inner {
fun foo() = bar // 訪問外部類成員
fun innerTest() {
var o = this@Outer //獲取外部類的成員變量
println("內(nèi)部類可以引用外部類的成員,例如:" + o.v)
}
}
}
fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo) // 1
val demo2 = Outer().Inner().innerTest()
println(demo2) // 內(nèi)部類可以引用外部類的成員,例如:成員屬性
}
為了消除歧義,要訪問來自外部作用域的 this,我們使用this@label,其中 @label 是一個(gè) 代指 this 來源的標(biāo)簽。
使用對象表達(dá)式來創(chuàng)建匿名內(nèi)部類:
class Test {
var v = "成員屬性"
fun setInterFace(test: TestInterFace) {
test.test()
}
}
/**
* 定義接口
*/
interface TestInterFace {
fun test()
}
fun main(args: Array<String>) {
var test = Test()
/**
* 采用對象表達(dá)式來創(chuàng)建接口對象,即匿名內(nèi)部類的實(shí)例。
*/
test.setInterFace(object : TestInterFace {
override fun test() {
println("對象表達(dá)式創(chuàng)建匿名內(nèi)部類的實(shí)例")
}
})
}
類的修飾符包括 classModifier 和_accessModifier_:
// 文件名:example.kt
package foo
private fun foo() {} // 在 example.kt 內(nèi)可見
public var bar: Int = 5 // 該屬性隨處可見
internal val baz = 6 // 相同模塊內(nèi)可見
更多建議: