類和對象

Kotlin 類和對象
類定義
Kotlin 類可以包含:構造函數和初始化代碼塊、函數、屬性、內部類、對象聲明。
Kotlin 中使用關鍵字 class 聲明類,后面緊跟類名:
class Runoob { // 類名為 Runoob
// 大括號內是類體構成
}
我們也可以定義一個空類:
class Empty
可以在類中定義成員函數:
class Runoob() {
fun foo() { print("Foo") } // 成員函數
}
類的屬性
屬性定義
類的屬性可以用關鍵字 var 聲明為可變的,否則使用只讀關鍵字 val 聲明為不可變。
class Runoob {
var name: String = ……
var url: String = ……
var city: String = ……
}
我們可以像使用普通函數那樣使用構造函數創建類實例:
val site = Runoob() // Kotlin 中沒有 new 關鍵字
要使用一個屬性,只要用名稱引用它即可
site.name // 使用 . 號來引用
site.url
Koltin 中的類可以有一個 主構造器,以及一個或多個次構造器,主構造器是類頭部的一部分,位于類名稱之后:
class Person constructor(firstName: String) {}
如果主構造器沒有任何注解,也沒有任何可見度修飾符,那么constructor關鍵字可以省略。
class Person(firstName: String) {
}
getter 和 setter
屬性聲明的完整語法:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]

getter 和 setter 都是可選
如果屬性類型可以從初始化語句或者類的成員函數中推斷出來,那就可以省去類型,val不允許設置setter函數,以為它是只讀的。
var allByDefault: Int? // 錯誤: 需要一個初始化語句, 默認實現了 getter 和 setter 方法
var initialized = 1 // 類型為 Int, 默認實現了 getter 和 setter
val simple: Int? // 類型為 Int ,默認實現 getter ,但必須在構造函數中初始化
val inferredType = 1 // 類型為 Int 類型,默認實現 getter
實例
以下實例定義了一個 Person 類,包含兩個可變變量 lastName 和 no,lastName 修改了 getter 方法,no 修改了 setter 方法。
class Person {

var lastName: String = "zhang"
    get() = field.toUpperCase()   // 將變量賦值后轉換為大寫
    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}")

}
輸出結果為:
lastName:WANG
no:9
no:-1
Kotlin 中類不能有字段。提供了 Backing Fields(后端變量) 機制,備用字段使用field關鍵字聲明,field 關鍵詞只能用于屬性的訪問器,如以上實例:
var no: Int = 100
get() = field // 后端變量
set(value) {
if (value < 10) { // 如果傳入的值小于 10 返回該值
field = value
} else {
field = -1 // 如果傳入的值大于等于 10 返回 -1
}
}
非空屬性必須在定義的時候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關鍵字描述屬性:
class LazyProperty(val initializer: () -> Int) {
var value: Int? = null
val lazy: Int
get() {
if (value == null) {
value = initializer()
}
return value!!
}
}
主構造器
主構造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中,初始化代碼段使用 init 關鍵字作為前綴。
class Person constructor(firstName: String) {
init {
System.out.print("FirstName is $firstName")
}
}
注意:主構造器的參數可以在初始化代碼段中使用,也可以在類主體n定義的屬性初始化代碼中使用。 一種簡潔語法,可以通過主構造器來定義屬性并初始化屬性值(可以是var或val):
class People(val firstName: String, val lastName: String) {
//...
}
如果構造器有注解,或者有可見度修飾符,這時constructor關鍵字是必須的,注解和修飾符要放在它之前。
實例
創建一個 Runoob類,并通過構造函數傳入網站名:
class Runoob constructor(name: String) { // 類名為 Runoob
// 大括號內是類體構成
var url: String = "http://www.runoob.com"
var country: String = "CN"
var siteName = name

init {
    println("初始化網站名: ${name}")
}

fun printTest() {
    println("我是類的函數")
}

}

fun main(args: Array<String>) {
val runoob = Runoob("菜鳥教程")
println(runoob.siteName)
println(runoob.url)
println(runoob.country)
runoob.printTest()
}
輸出結果為:
初始化網站名: 菜鳥教程
菜鳥教程
http://www.runoob.com
CN
我是類的函數
次構造函數
類也可以有二級構造函數,需要加前綴 constructor:
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
如果類有主構造函數,每個次構造函數都要,或直接或間接通過另一個次構造函數代理主構造函數。在同一個類中代理另一個構造函數使用 this 關鍵字:
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}
如果一個非抽象類沒有聲明構造函數(主構造函數或次構造函數),它會產生一個沒有參數的構造函數。構造函數是 public 。如果你不想你的類有公共的構造函數,你就得聲明一個空的主構造函數:
class DontCreateMe private constructor () {
}
注意:在 JVM 虛擬機中,如果主構造函數的所有參數都有默認值,編譯器會生成一個附加的無參的構造函數,這個構造函數會直接使用默認值。這使得 Kotlin 可以更簡單的使用像 Jackson 或者 JPA 這樣使用無參構造函數來創建類實例的庫。
class Customer(val customerName: String = "")
實例
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 // 同一個模塊中可見
實例
// 文件名:example.kt
package foo

private fun foo() {} // 在 example.kt 內可見

public var bar: Int = 5 // 該屬性隨處可見

internal val baz = 6 // 相同模塊內可見

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容

  • 類和對象 類和繼承 類 Kotlin中使用關鍵字class聲明類 類的聲明由類名、類頭(指定類的類型參數、主構造函...
    Mobile_Joy閱讀 306評論 0 0
  • 類的屬性可以使用 var 聲明變量,可以使用 val 聲明常量。屬性的引用可以用 (.)符號來實現。屬性取值和賦值...
    厚土火焱閱讀 546評論 0 2
  • 1、面向對象程序設計的基本概念 過程是編程語言:程序=算法+數據面向對象編程語言:程序=對象+消息 對象 對象的特...
    夏沫xx閱讀 533評論 0 0
  • 說到《無極》,第一個反應就是爛片。導演陳凱歌卻說:你現在看不懂,十年后就能看懂了。 現在距2005年,已經有12年...
    宿哎呀閱讀 1,213評論 0 2
  • 畫畫就是能讓你稍稍游離于你自己有時都會有些厭倦的生活。
    木咸閱讀 234評論 0 1