【kotlin】面向对象、封装、继承、多态

1,727 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情

面向对象

fun main(args: Array<String>) {
	var rect01 = Rect(20,10)
	println("矩形的宽度:"+rect01.width+",矩形的高度:"+rect01.height)
}

class Rect(var width:Int,var height:Int)

在这里插入图片描述

fun main(args: Array<String>) {
	var rect01 = Rect(20,10)
	rect01.area()
	rect01.circu()
}

class Rect(var width:Int,var height:Int){
	fun area(){
		println("矩形的面积:"+width*height)
	}
	fun circu(){
		println("矩形的周长::"+(width+height)*2)
	}
}

在这里插入图片描述

静态行为,动态方法 这里静态的是这个长方形的属性,长和宽 这里动态的是这个长方形的方法,获取面积和获取周长的方法

封装

在这里插入图片描述

我们再来举个栗子,洗衣机的栗子

新建一个class文件WashMachine

class WashMachine(var module:String,var size:Int) {
	var isDoorOpen = true
	var currentMode = 0
	
	fun openDoor(){
		println("洗衣机的门打开了")
		isDoorOpen = true
	}
	fun closeDoor(){
		println("洗衣机的门关闭了")
		isDoorOpen = false
	}
	fun selectMode(mode:Int){
		currentMode = mode
		when(mode){
			0 -> println("初始模式,请选择模式")
			1 -> println("消毒洗")
			2 -> println("棉麻洗")
			else -> println("进入了奇怪模式")
		}
	}
	fun start(){
		if(isDoorOpen){
			println("嘀嘀嘀门还没关,不能运行")
		}else{
			when(currentMode){
				0 -> {println("选择模式错误,不能运行")}
				1 -> {
					println("进入消毒洗,高温")
					setMotorSpeed(100)
				}
				2 -> {
					println("进入棉麻洗,轻柔")
					setMotorSpeed(200)
				}
			}
			println("洗衣服开始")
		}
		
	}
	
	//私有,只有这个类中能调用
	private fun setMotorSpeed(speed:Int){
		println("当前发动机转速${speed}圈/秒")
	}
}
fun main(args: Array<String>) {
	var washMachine = WashMachine("小天鹅",12);
	washMachine.openDoor()
	washMachine.closeDoor()
	washMachine.selectMode(1)
	washMachine.start()
}

在这里插入图片描述

继承

在 Kotlin 中任何一个非抽象类默认都是不可以被继承的(抽象类本身无法创建实例,一定要由子类继承它才能创建实例),相当于给 Java 中给类声明了 final,好的编程习惯是如果一个类不是专门为继承而设计的,那么就应该主动将它加上 final声明,禁止它可以被继承

新建一个Father类,如果想被继承需要加open关键字

open class Father {
	var character:String = "性格外向"
	fun action(){
		println("喜欢在公共场合唱歌");
	}
}

新建一个Son类继承Father类,可以发现 Father 后有一对括号,这就涉及到 Java 继承特性中的一个规定:子类总的构造函数必须调用父类中的构造函数,这个规定 Kotlin 中也要遵守。子类中的主构造函数调用父类中的哪个构造函数,在继承的时候通过括号来指定

Father 类后一对空括号表示 Son 类的主构造函数在初始化的时候会调用 Father 类的无参构造函数,即使在无参数情况下,括号也不能省略

class Son : Father() {
}

测试下

fun main(args: Array<String>) {
	var son = Son()
	println(son.character)
	son.action()
}

查看运行结果

在这里插入图片描述

我们来试下重写父类方法

class Son : Father() {
	override fun action(){
		println("喜欢在公共场合跳舞")
	}
}

查看执行结果

在这里插入图片描述

多态

在这里插入图片描述

创建一个抽象的人类

/*
 * 抽象的人类
 */
abstract class Human(var name:String) {
	abstract fun eat()
}

创建男人类

class Man(name:String):Human(name) {
	override fun eat(){
		println("${name}喜欢吃鸡腿")
	}
}

创建女人类

class Woman(name:String):Human(name) {
	override fun eat(){
		println("${name}喜欢吃鸭脖")
	}
}

编写测试代码

fun main(args: Array<String>) {
	var man = Man("赵四")
	man.eat()
	
	var woman = Woman("李小花")
	woman.eat()
}

查看测试结果

在这里插入图片描述

我们给Human再增加一个方法love

/*
 * 抽象的人类
 */
abstract class Human(var name:String) {
	abstract fun eat()
	abstract fun love()
}

Man和Woman都需要重写这个方法

class Man(name:String):Human(name) {
	......
	override fun love(){
		println("${name}爱买游戏")
	}
}

class Woman(name:String):Human(name) {
	......
	override fun love(){
		println("${name}爱买面膜")
	}
}

编写测试代码

fun main(args: Array<String>) {
	var man1 = Man("赵四")
	var woman1 = Woman("李小花")
	var man2 = Man("刘能")
	var woman2 = Woman("王大花")
	
	var humanList = listOf<Human>(man1,woman1,man2,woman2)
	for(h in humanList){
		h.love()
	}
}

查看运行结果

在这里插入图片描述

主构造函数和次构造函数

Kotlin 将构造函数分成了两种:主构造函数和次构造函数 每个类都默认有一个不带参数的主构造函数,当然你也可以显式地给它指明参数。主构造函数特点是没有函数体,直接定义在类名后面即可。例如上面的洗衣机类 WashMachine 就将两个字段放到了主构造函数中了

由于构造函数中的参数是在创建实例的时候传入的,因此我们可以将参数声明成 val

Kotlin 为我们提供了一个 init 结构体,所有主函数中的逻辑都可以写在这里,绝大多数情况下我们不需要写 init 结构体的

class WashMachine(var module:String,var size:Int) {
    var isDoorOpen = true
    var currentMode = 0

    init{
        println("module:"+module)
        print("size:"+size)
    }
    ......
}

如果 将 Father 类改造下

open class Father(character:String,like:String) {
    ...
}

那么 Son 类一定会报错,以为要给 Father 传入两个参数,而 Son 类中没有,所以得增加如下

class Son(character:String,like:String) : Father(character,like) {
}

在 Son 类主构造函数增加 character 和 like 时,不能声明成 val ,因为在主构造函数中声明成 valvar 的参数将自动成为该类的字段,会导致和父类同名字段冲突

任何一个类只能有一个主构造函数,但可以有多个次构造函数,次构造函数通过constructor来定义。Kotlin 规定当一个类既有主构造函数,又有次构造函数时,所有次构造函数必须调用主构造函数(包括间接调用)

class Son(character:String,like:String) : Father(character,like) {
    constructor(character: String):this("","")
    constructor():this("")
}

于是我们有3种方式对 Son 实例化

    val son1 = Son();
    val son2 = Son("性格内向");
    val son3 = Son("性格内向","喜欢运动");

还有一种非常特殊的情况:类中只有次构造函数,没有主构造函数。当一个类中没有显式地定义主构造函数且定义了次构造函数,它就是没有主构造函数的

class Son: Father{
    constructor(character: String,like:String):super(character,like)
}

Son 是没有主构造函数的,继承 Father 类时也就不需要加括号了。由于没有主构造函数,次构造函数只能调用父类的构造函数,所以用了 super 关键字