静态行为,动态方法 这里静态的是这个长方形的属性,长和宽 这里动态的是这个长方形的方法,获取面积和获取周长的方法
我们再来举个栗子,洗衣机的栗子
新建一个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 ,因为在主构造函数中声明成 val 或 var 的参数将自动成为该类的字段,会导致和父类同名字段冲突
任何一个类只能有一个主构造函数,但可以有多个次构造函数,次构造函数通过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 关键字