運(yùn)算符重載
kotlin中每一個(gè)運(yùn)算符對應(yīng)一個(gè)方法。比如我們想把兩個(gè)對象加起來的話掺涛,只需要把“+”對應(yīng)的方法復(fù)寫就可以實(shí)現(xiàn)了。運(yùn)算符對應(yīng)的方法可以通過kotlin官網(wǎng)http://kotlinlang.org/docs/reference查詢。
fun main(args: Array<String>) {
val p1 = Person()
val p2 = Person()
p1.age = 10
p2.age = 20
//求p1和p2的年齡和
var plus = p1.plus(p2)
println(plus)
}
//重寫“+”方法
class Person {
var name = "張三"
var age = 0
fun plus(person: Person): Int {
return age + person.age
}
}
類的成員
類成員可以訪問并且修改岗仑,kotlin的類成員變量默認(rèn)已經(jīng)實(shí)現(xiàn)了get以及set方法。
成員的訪問與修改
由于kotlin的類成員變量默認(rèn)實(shí)現(xiàn)get以及set方法聚请,所以類中的成員可以直接調(diào)用:
fun main(args: Array<String>) {
val stu = Student()
println(stu.age)
println(stu.name)
}
class Student {
val name = "張三"
val age = 15
}
修改類成員的可見性
在Kotlin中荠雕,若是想要類成員對于外界只能訪問不能修改,則在類成員后中寫入 private set。若想類成員對外界既不能訪問也不能修改炸卑,則在類成員前寫入private:
class Student {
var name = "張三"
private set//外界無法修改name
private var age = 15//外界無法訪問既鞠、修改age
}
自定義訪問器
在我們的例子中,學(xué)生的年齡不可能隨意設(shè)置盖文,比如學(xué)生是-1歲损趋,所以需要對設(shè)置的數(shù)據(jù)進(jìn)行判定,符合一定要求后才能修改椅寺。對于此類要求浑槽,我們可以用自定義訪問器field:
fun main(args: Array<String>) {
var person = Student()
println(person.age)//20
person.age = 35//由于35>30,所以設(shè)置失敗
println(person.age)//20
}
class Student {
var name = "張三"
var age = 20
set(value) {//value對應(yīng)傳遞的age值
if (value > 18 && value < 30) {
//可以通過field表示這個(gè)字段
field = value
}
}
}
主構(gòu)函數(shù)和次構(gòu)函數(shù)
主構(gòu)函數(shù)
kotlin中主構(gòu)函數(shù)即構(gòu)造函數(shù)返帕,但是無法直接訪問構(gòu)造函數(shù)中的元素桐玻。如果想要在構(gòu)造函數(shù)里面實(shí)現(xiàn)一些操作,需要把代碼寫在init里:
fun main(args: Array<String>) {
val p1 = Person("張三", 23)
val p2 = Person("李四", 25)
val p3 = Person("王五", 40)
println(p1.age)//23
println(p2.age)//25
println(p3.age)//40
}
class Person(name: String, age: Int) {
var name = ""
var age = 0
init {
this.age = age
this.name = name
}
}
var和val在主構(gòu)函數(shù)參數(shù)中的作用
主構(gòu)函數(shù)參數(shù)使用var和val荆萤,相當(dāng)于幫我們定義了字段镊靴,參數(shù)可以直接使用。參數(shù)沒有var和val修飾链韭,參數(shù)在其他地方不能使用 偏竟。參數(shù)有var修飾,可以使用敞峭,也可以修改 踊谋。參數(shù)有val修飾,只能使用旋讹,不能修改 :
fun main(args: Array<String>) {
val p1 = Person("張三", 23)
val p2 = Person("李四", 25)
val p3 = Person("王五", 40)
println(p1.age)
println(p2.age)
println(p3.age)
}
class Person(val name: String,val age: Int)
次構(gòu)函數(shù)
次構(gòu)函數(shù)必須要調(diào)用主構(gòu)函數(shù)殖蚕,必須要把參數(shù)傳遞給主構(gòu)函數(shù),且需要用constructor關(guān)鍵字:
class Person2(val name: String,val age: Int){
constructor(name: String, age: Int,phone:String):this (name,age)//調(diào)用主構(gòu)函數(shù)將參數(shù)傳遞給主構(gòu)函數(shù)
}
次構(gòu)函數(shù)間調(diào)用
次構(gòu)函數(shù)可以直接調(diào)用主構(gòu)函數(shù)沉迹,也可以通過調(diào)用次構(gòu)函數(shù)來間接調(diào)用主構(gòu)函數(shù):
class Person3(name:String,age: Int){
//調(diào)用主構(gòu)函數(shù)
constructor(name:String,age: Int,phone: String):this(name,age)
//通過調(diào)用次構(gòu)函數(shù)來間接調(diào)用主構(gòu)函數(shù)
constructor(name:String,age: Int,phone: String,qq:String):this(name,age,phone)
}
次構(gòu)函數(shù)參數(shù)使用
構(gòu)造函數(shù)加var和val只能在主構(gòu)函數(shù)里面加睦疫,次構(gòu)函數(shù)中不能加。主構(gòu)函數(shù)參數(shù)可以直接加上var和val使用鞭呕,次構(gòu)函數(shù)只能夠自己定義變量進(jìn)行保存蛤育。
class Person3(val name:String,val age: Int){
var phone = ""
var qq = ""
constructor(name:String,age: Int,phone: String):this(name,age)
constructor(name:String,age: Int,phone: String,qq:String):this(name,age,phone){
this.phone = phone
this.qq = qq
}
}
繼承
繼承是指一個(gè)對象直接使用另一對象的屬性和方法。kotlin的繼承和java中的繼承大體相同葫松,但需要注意以下幾點(diǎn):
1.需要將父類加上open關(guān)鍵字
2.需要加上():
kotlin的成員函數(shù)和成員變量對應(yīng)的get以及set方法都有final修飾瓦糕,不能進(jìn)行繼承,所以要在成員函數(shù)和成員變量前加上open關(guān)鍵字才能進(jìn)行復(fù)寫:
open class father() {
open var name = "小頭爸爸"
open var age = 40
open fun sayHello() {
println("老哥 早上好")
}
}
class son : father() {
override var name: String = "大頭兒子"
override var age: Int = 14
override fun sayHello() {
println("同學(xué) 早上好")
}
}
構(gòu)造函數(shù)的繼承
構(gòu)造函數(shù)的繼承除了通常的操作外进宝,子類也需要構(gòu)造函數(shù)刻坊,并且應(yīng)能在父類中找到對應(yīng)的字段,還需將函數(shù)傳給父類党晋。子類也可以用父類的字段:
fun main(args: Array<String>) {
var p = Person("張三", 30)
var s = Student("李四", 20, "男")
println(p.age)//30
println(s.sex)//男
println(s.name)//李四
}
open class Person(var name: String, var age: Int) {
open fun morning() {
println("早上好")
}
}
class Student(name: String, age: Int, var sex: String) : Person(name, age) {
override fun morning() {
println("晚上好")
}
}
抽象類和抽象方法
父類中的方法,被它的子類們重寫,子類各自的實(shí)現(xiàn)都不盡相同未玻。那么父類的方法聲明和方法主體灾而,只有聲明還有意義,而方法主體則沒有存在的意義了扳剿。我們把沒有方法主體的方法稱為抽象方法旁趟。包含抽象方法的類就是抽象類。抽象類不需要open關(guān)鍵字就可以被調(diào)用庇绽。
//人類 (抽象類)
abstract class Human {
abstract var color: String
abstract var language: String
abstract fun eat()
}
//具體實(shí)現(xiàn)類
class Chinese : Human() {
override var color: String = "yellow"
override var language: String = "chinese"
override fun eat() {
println("用筷子吃飯")
}
}
class USHuman : Human() {
override var color: String = "white"
override var language: String = "english"
override fun eat() {
println("用刀叉吃飯")
}
}
class AfHuman : Human() {
override var color: String = "black"
override var language: String = "葡萄牙語"
override fun eat() {
println("用手吃飯")
}
}
接口
接口的實(shí)現(xiàn)是在括號(hào)后面加個(gè)冒號(hào)锡搜,然后寫上要實(shí)現(xiàn)的接口,不需要寫interface瞧掺。若是多個(gè)接口耕餐,就用逗號(hào)“,”隔開辟狈。
class men() : bike {
override fun rideBike() {
println("人騎車")
}
}
interface bike {
fun rideBike()
}
注意事項(xiàng)
1.java中接口中的字段一定要被賦值肠缔,但是Kotlin接口里的字段不能被賦值
2.java接口里面方法不能實(shí)現(xiàn),kotlin可以實(shí)現(xiàn)
class men() : Bike, Drive {
override val license: String = "123456"
override fun drive() {
println("人開車")
}
override fun rideBike() {
println("人騎車")
}
}
interface Bike {
fun rideBike()
}
interface Drive {
val license: String
fun drive() {
println("放手剎,踩油門,走")
}
}
多態(tài)
同種功能的不同表現(xiàn)形式哼转。kotlin中的多態(tài)原理同java:
abstract class Animal {
abstract var name: String
open fun bark() {
println("動(dòng)物叫")
}
}
class Dog : Animal() {
override var name: String = "旺財(cái)"
override fun bark() {
println("旺財(cái) 汪汪叫")
}
}
class Cat : Animal() {
override var name: String = "湯姆"
override fun bark() {
println("湯姆 喵喵叫")
}
}
智能類型轉(zhuǎn)換
在多態(tài)中明未,多個(gè)子類可能均與父類有差別。kotlin中可以通過智能類型推斷來判斷調(diào)用的字段所屬于的子類壹蔓,最終調(diào)用所屬子類的方法趟妥。將父類引用轉(zhuǎn)為子類引用,轉(zhuǎn)換之前還需要判斷是否是當(dāng)前子類類型佣蓉。一旦判斷出是這個(gè)類型之后煮纵,編譯器就把類型轉(zhuǎn)換過去了,不需要手動(dòng)轉(zhuǎn)換偏螺。
fun main(args: Array<String>) {
val shepHerdDog: Dog = ShepHerdDog()//將父類引用轉(zhuǎn)為子類引用
//判斷是否是當(dāng)前子類類型
if (!(shepHerdDog is ShepHerdDog)) return
//編譯器自動(dòng)轉(zhuǎn)換
shepHerdDog.shepHerd()
}
abstract class Dog
class ShepHerdDog : Dog() {
fun shepHerd() {
println("牧羊犬開始放羊了...")
}
}
嵌套類行疏、內(nèi)部類
嵌套類默認(rèn)都是static修飾的,屬于靜態(tài)類套像,不依賴于外部的環(huán)境酿联,即和外部類沒有關(guān)系:
fun main(args: Array<String>) {
val inClass = outClass()
}
class outClass {
var name: String = "李四"
class inClass {
fun say() {
println(name)
}
}
}
內(nèi)部類需要通過Inner修飾,且需要先創(chuàng)建出來外部環(huán)境:
fun main(args: Array<String>) {
val inClass = outClass.inClass()
}
class outClass {
var name: String = "李四"
inner class inClass {
fun say() {
println(name)
}
}
}
內(nèi)部類中使用this
如上例夺巩,若內(nèi)部類中也有一個(gè)var name = "張三"贞让,則默認(rèn)情況下會(huì)打印張三,即從最近開始找柳譬。如果我們想訪問外部類中的name喳张,也就是李四。這時(shí)候就需要把打印內(nèi)容改為外部類名.this.name或this@outClass.name:
class OutClass {
var name = "李四"
inner class InClass {
var name = "張三"
fun sayHello() {
println(this@OutClass.name)
//或
println(OutClass.this.name)
}
}
}