Kotlin实战(五)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zping0808/article/details/85312757

一、面向对象基础知识

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

没有使用varval声明的主构造函数需要手动赋值才可使用

//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
    }
}

使用了varval声明的主构造函数中参数,外部可以直接通过 对象.参数 来访问

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 "狗汪汪叫"
    }
}

//猫 实体类
class Cat(override var color: String) :Animal(){
    override fun call():String {
        return  "猫喵喵叫"
    }
}

猜你喜欢

转载自blog.csdn.net/zping0808/article/details/85312757