Kotlin實戰(五)
一、面向物件基礎知識
1.1、面向物件案例
Kotlin的類申明,預設是final和public的,Kotlin類、介面修飾符:
- public:預設修飾符,被其修飾的在任何位置都能訪問
- private:表示只在這個類(以及它的所有成員)之內可以訪問
- protected:在當前類及其子類內訪問
- internal:在同一模組內使用
val a = Rect()
println(a.height)//100
println(a.width)//100
val b = Girl()
println(b.name)//張三
println(b.age)//18
b.shopping ()//去購物
// 矩形
class Rect {
//靜態屬性
var height: Int = 100
var width: Int = 100
}
// 妹子
class Girl {
//靜態屬性
var name: String = "張三"
var age: Int = 18
//動態行為
fun shopping() {
println("去購物")
}
}
1.2、get和set
val修飾的變數是沒有set方法的, 也不允許重寫set方法。
fun main(args: Array<String> ) {
val person = Person()
//person.age=20 //val修飾的變數是沒有set方法的, 也不允許重寫set方法
println("姓名:${person.name},年齡:${person.age}")//姓名:張三,年齡:18
}
//koltin欄位是私有的 會自動生成get和set方法 可以直接訪問
class Person{
var name:String="張三"
val age:Int=18 //val修飾的變數是沒有set方法的, 也不允許重寫set方法
}
1.3、訪問器
fun main(args: Array< String>) {
val person = Person2()
// person.name="11"//私有了set方法 不可修改
println("姓名:${person.name},年齡:${person.age}")//姓名:張三,年齡:18
}
//private set 私有了set方法 只能訪問 不可修改
class Person2 {
var name: String = "張三"
private set //私有了set方法
var age: Int = 18
}
1.4、自定義訪問器
fun main(args: Array<String>) {
val person = Person3()
person.age=120
println("姓名:${person.name},年齡:${person.age}")//姓名:張三,年齡:120
person.age=160
println("姓名:${person.name},年齡:${person.age}")//姓名:張三,年齡:120
}
class Person3 {
var name: String = "張三"
private set //私有了set方法
var age: Int = 18
//自定義訪問器
set(value) {
if (value < 150) {
//使用field 修改 age 此時的field相當於this.age
field = value
}
}
}
field的用法,field被大神們翻譯成Backing Fields(後端變數),它的作用就類似於java裡的this.屬性名,例如上面程式碼中field = value, 就相當於java裡的 this.age = value,但是不能直接使用this.age,會造成遞迴呼叫記憶體溢位的, 因為在set和get中是不允許有本身的區域性變數的(例如如果你屬性名是age, 在set/get裡是不能有這個變數的), 因為屬性的呼叫也涉及到了set/get會造成遞迴呼叫, 所以要解決引用自身的問題, kotlin發明了field(後端變數)來解決這個問題。注意不是set/get裡不允許有區域性變數,是不允許有和屬性本身相同名字的區域性變數。
1.5、建構函式
Kotlin的建構函式,分為主建構函式和次建構函式。
fun main(args: Array<String>) {
val person4 = Person4("張三", 18)
}
//建立的時候就需要修改裡面的name和age
//class Person4 constructor(name: String, age: Int) {
//}
//主建構函式沒有註解或可見性修飾符,constructor可去除
class Person4 (name: String, age: Int) {
}
1.6、建構函式引數的使用
因為kotlin中的類定義同時也是建構函式,這個時候是不能進行操作的,所以kotlin增加了一個新的關鍵字init
用來處理類的初始化問題,init模組中的內容可以直接使用建構函式的引數。
fun main(args: Array<String>) {
val person5 = Person5("張三", 99)
println("姓名:${person5.name},年齡:${person5.age}")//姓名:張三,年齡:99
}
//建立的時候就需要修改裡面的name和age
class Person5(name: String, age: Int) {
var name:String?=null
var age:Int=0
init {
//建構函式中寫的程式碼可以放到init中執行
this.name=name
this.age=age
}
}
1.7、建構函式引數使用var和val
沒有使用var
和val
宣告的主建構函式需要手動賦值才可使用
//var add = Add("11", "22")
//println(add.value2)//訪問報錯
//class Add(value1: String, value2: String)
var add = Add("11", "22")
println(add.value2)//22
class Add(value1: String, value2: String){
var value1:String
var value2:String
init {
this.value1=value1
this.value2=value2
}
}
使用了var
和val
宣告的主建構函式中引數,外部可以直接通過 物件.引數
來訪問
fun main(args: Array<String>) {
val person6 = Person6("張三", 99)
// person6.age=1//不可修改
println("姓名:${person6.name},年齡:${person6.age}")//姓名:張三,年齡:99
val person7 = Person7("張三", 91)
person7.age=1//可修改
println("姓名:${person7.name},年齡:${person7.age}")//姓名:張三,年齡:1
}
//建立的時候就需要修改裡面的name和age, val 相當於final 修飾 不可修改屬性
class Person6(val name: String, val age: Int)
//建立的時候就需要修改裡面的name和age,var 可修改屬性
class Person7(var name: String, var age: Int)
1.8、次構函式
次級建構函式用constructor
加上引數,後面用this
賦值給主建構函式的引數,同時次級建構函式中可以進行程式碼操作,所以沒有init
模組
fun main(args: Array<String>) {
val per = Per("張三", 18, 1)
println("姓名:${per.name},年齡:${per.age},性別:${if (per.sax == 1) "男" else "女"}")//姓名:張三,年齡:18,性別:男
val per2 = Per("李四", 18)
println("姓名:${per2.name},年齡:${per2.age},性別:${if (per2.sax == 1) "男" else "女"}")//姓名:李四,年齡:18,性別:女
}
class Per(var name: String, var age: Int) {
var sax: Int = 0
//constructor次構函式 :this 賦值給主建構函式的引數
constructor(name: String, age: Int, sax: Int) : this(name, age) {
this.sax = sax
}
}
1.9、init和次構執行順序
類被初始化時,先執行 init
方法後執行主建構函式方法。
fun main(args: Array<String>) {
val per2 = Per2("張三", 18, 1)
//列印結果:呼叫了init方法 呼叫了constructor方法
}
class Per2(name: String, age: Int) {
var name: String = ""
var age: Int = 0
var sax: Int = 0
init {
println("呼叫了init方法")
this.name = name
this.age = age
}
constructor(name: String, age: Int, sax: Int) : this(name, age) {
println("呼叫了constructor方法")
this.sax = sax
}
}
二、封裝
封裝:將相應的屬性、行為裝到一個類中,然後將所有屬性私有化。
fun main(args: Array<String>) {
//買一個洗衣機
val machine = WashMachine("海爾",12)
//開啟洗衣機門
machine.openDoor()
//放入衣服
println("放入牛仔褲")
//關閉洗洗衣機門
machine.closeDoor()
//設定模式
machine.mode = 1
//點選開始洗衣服按鈕
machine.start()
// machine.setMotorSpeed(10000)//轉速調節歸洗衣機自生所有,不提供給外部呼叫
}
// 洗衣機
class WashMachine(var brand: String, var l: Int) {
var mode= 0//預設模式 1 輕柔 2 狂揉
//開門動作
fun openDoor(){
println("開啟洗衣機門...")
}
//關閉洗衣機門
fun closeDoor() {
println("關閉洗衣機門...")
}
//調節轉速操作(不提供給使用者,使用private私有化)
private fun setMotorSpeed(speed:Int){
println("當前轉速為$speed")
}
//設定模式(使用者調節模式)
fun selectMode(mode: Int) {
this.mode = mode
}
//開始洗衣服的按鈕
fun start() {
when (mode) {
0 -> {
println("請選擇模式")
}
1 -> {
println("開始放水...")
println("水放滿了...")
println("開始洗衣服...")
println("洗衣服模式為輕柔")
setMotorSpeed(500)
println("衣服洗好了...")
}
2 -> {
println("開始放水...")
println("水放滿了...")
println("開始洗衣服...")
println("洗衣服模式為狂柔")
setMotorSpeed(10000)
println("衣服洗好了...")
}
else->{
println("模式設定錯誤")
}
}
}
}
三、繼承
Kotlin中使用 :
來繼承 ,一個類可繼承只可繼承一個類(單繼承),Java中類和方法預設是open的,而Kotlin中預設都是final的,類和方法可以被繼承需要open
關鍵字來修飾,繼承方法必須使用override
標識。 否則和父類可以被繼承的方法同名,編譯器將報錯。Kotlin中使用override
修飾符是強制要求的,這樣會避免先寫出實現方法再新增抽象方法造成的意外重寫。
Kotlin中所有類都繼承Any
預設提供equals()
、hashCode()
、toString()
fun main(args: Array<String>) {
val son = Son()
son.horbe()
}
/**
* 父親類
* Kotlin中 預設類都是final 的不可繼承,需要增加open關鍵字 才可以繼承
*/
open class Father {
//靜態屬性
open var name: String = "張三"
open var age: Int = 45
//動態行為
open fun horbe() {
println("父親喜歡抽菸")
}
}
//孩子類 繼承自父親
class Son : Father() {
//繼承父親屬性
override var name: String="張四"
override var age: Int=1
override fun horbe() {
// super.horbe()
println("孩子喜歡抽菸")
}
}
四、抽象類
使用abstract
來修飾表示抽象類,kotlin中方法和屬性都可以為抽象。
fun main(args: Array<String>) {
val zhHuman = ZHHuman()
val color = zhHuman.color
val language = zhHuman.language
println("面板顏色:$color,使用語言:$language")//面板顏色:黃色,使用語言:中文
}
//人類(抽象類)
abstract class Human {
//膚色屬性
abstract var color: String
//語言屬性
abstract var language: String
//吃飯行為
abstract fun eat()
}
//中國人(繼承人類抽象類) open 用於其他類繼承
open class ZHHuman : Human() {
override var color: String = "黃色"
override var language: String = "中文"
override fun eat() {
println("使用筷子吃飯")
}
}
//美國人(繼承人類抽象類)
class USHuman : Human() {
override var color: String = "白色"
override var language: String = "英文"
override fun eat() {
println("使用刀叉吃飯")
}
}
五、介面
5.1、介面定義
Kotlin中使用 :
來實現介面,多個介面使用,
隔開,一個類可實現多個介面(多實現),實現介面中方法必須使用override
標識, 否則編譯器將報錯。
fun main(args: Array<String>) {
val xiaoMing = XiaoMing()
xiaoMing.ride()//小明學會了騎自行車
xiaoMing.drive()//小明學會了開車
}
//小明 繼承中國人 實現騎車、開車介面
class XiaoMing : ZHHuman(), RideBike, DriveCar {
override fun drive() {
println("小明學會了開車")
}
override fun ride() {
println("小明學會了騎自行車")
}
}
//騎車介面
interface RideBike {
//騎車行為
fun ride()
}
//開車介面
interface DriveCar {
//開車行為
fun drive()
}
5.2、介面細節
Kotlin中介面可以包含屬性申明,kotlin 介面中方法也可以有一個預設實現,有預設實現的方法介面被使用,可以直接使用預設實現,可以不用再次重寫此方法,當然也可以被重寫,使用super.方法名
來呼叫預設實現。
fun main(args: Array<String>) {
val xiaoFang = XiaoFang("12345678")
xiaoFang.drive()
//列印結果:
// 出示駕照12345678
// 掛擋 踩油門 走
// 小方學會了開車
}
//小方 繼承中國人 實現騎車、開車介面
class XiaoFang(override var license: String) : ZHHuman(), RideBikeNew, DriveCarNew {
override fun drive() {
super.drive()
println("小方學會了開車")
}
override fun ride() {
println("小方小學會了騎自行車")
}
}
//騎車介面
interface RideBikeNew {
//騎車行為
fun ride()
}
/**
* 開車介面,Kotlin 介面中欄位不可實現(賦值),只能實現類賦值,Java中可以
* Java 介面中方法不可實現,Kotlin中可以
*/
interface DriveCarNew {
//駕照號碼
var license: String
//開車行為
fun drive() {
println("出示駕照${license}")
println("掛擋 踩油門 走")
}
}
如果一個類實現了兩個介面中相同的方法,可以使用super<介面名>.方法名
來呼叫介面中預設實現。
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
六、多型
多型:同一種功能多種表現形式
fun main(args: Array<String>) {
// 多型特點:通過父類接收 執行的是子類的方法
val dog:Animal = Dog("黑色")
println("毛髮顏色:${dog.color},動態行為:${dog.call()}")//毛髮顏色:黑色,動態行為:狗汪汪叫
val cat:Animal = Cat("白色")
println("毛髮顏色:${cat.color},動態行為:${cat.call()}")//毛髮顏色:白色,動態行為:貓喵喵叫
}
//動物抽象類
abstract class Animal {
//靜態屬性 毛髮顏色
abstract var color: String
//動態行為
abstract fun call():String
}
//狗 實體類
class Dog(override var color: String) : Animal() {
override fun call(): String{
return