前文讲到,Kotlin中万物皆对象,连《基础数值类型》都不放过。
除了文字版本,也有Xmind版本 github地址
带几个问题吧
① Any 跟object什么区别?
② 子类的初始化顺序如何?
③ super的覆盖规则是什么?
④ 与java对比,kotlin在继承有什么变化?加强了什么?
本文从以下几个方面讲继承
首先,Any 不是 java.lang.Object。
在Kotlin中,Any是所有类的超类
如果没有显式声明超类型声明的类,其默认的超类是Any
Any 默认提供了三个函数
把超类型 放在冒号 之后
open class Base(p: Int)
class Derived(p: Int) : Base(p)
如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。
这话看起来看起来,比较难懂。
先看个范例
open class Person(var name : String, var age : Int, var score : Int){// 基类
}
class Student(name : String, age : Int, var no : String, score : Int) : Person(name, age, score) {
}
// 测试
fun main(args: Array) {
val s = Student("wangxueming", 18, "S12346", 89)
println("学生名: ${s.name}")
println("年龄: ${s.age}")
println("学生号: ${s.no}")
println("成绩: ${s.score}")
}
讲解
Person是基类。Student是子类。
Person定义了name, age, score。Student有参数:name、age、no、score。
如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。
就是说:如果基类Person定义的name、age、score,在子类中必须要进行赋值。
即 : 冒号之后,Person(name, age, score) 必须要把参数传入。
如果在name上加上var呢?
class Student(var name : String, age : Int, var no : String, score : Int) : Person(name, age, score) {
}
输出结果
‘name’ hides member of supertype ‘Person’ and needs ‘override’ modifier
报错了,因为Person的name与Student的name重名了;
换言之。如果你把Person的name,换个名字,改成otherName。
或者把Person的name改成otherName结果怎么样呢?
会错吗?答案是不会的。
open class Person(var otherName : String, var age : Int, var score : Int){// 基类
}
class Student(var myName : String, age : Int, var no : String, score : Int) : Person(myName, age, score) {
}
// 测试
fun main(args: Array) {
val s = Student("wangxueming", 18, "S12346", 89)
println("学生名: ${s.otherName}")
println("年龄: ${s.age}")
println("学生号: ${s.no}")
println("成绩: ${s.score}")
}
这里会正常输出结果
学生名: wangxueming
年龄: 18
学生号: S12346
成绩: 89
必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数
看范例
/**用户基类**/
open class Person(name:String){
/**次级构造函数**/
constructor(name:String,age:Int):this(name){
//初始化
println("-------基类次级构造函数---------")
}
}
/**子类继承 Person 类**/
class Student:Person {
/**次级构造函数**/
constructor(name:String,age:Int,no:String,score:Int):this(name,age,no,score, 0){
println("-------继承类次级构造函数 A---------")
}
/**次级构造函数**/
constructor(name:String,age:Int,no:String,score:Int, sex : Int):super(name,age){
println("-------继承类次级构造函数 B---------")
println("学生名: ${name}")
println("年龄: ${age}")
println("学生号: ${no}")
println("成绩: ${score}")
println("性别: ${sex}")
}
}
fun main(args: Array) {
var s = Student("wangxueming", 18, "S12345", 89)
println()
println()
println()
var s2 = Student("wangxueming", 18, "S12345", 89, 1)
}
输出结果
-------基类次级构造函数---------
-------继承类次级构造函数 B---------
学生名: wangxueming
年龄: 18
学生号: S12345
成绩: 89
性别: 0
-------继承类次级构造函数 A----------------基类次级构造函数---------
-------继承类次级构造函数 B---------
学生名: wangxueming
年龄: 18
学生号: S12345
成绩: 89
性别: 1
这个结果。
Student(“wangxueming”, 18, “S12345”, 89)
用this在代理另一个构造函数是
Student(“wangxueming”, 18, “S12345”, 89, 1)
用super 关键字初始化基类
Kotlin 力求清晰显式
加强了继承的限制。也就加强了 类之间的关联界定。
有几种情况要注意:
跟java的差异
用override关键字。
这基本跟java一致。
在Kotlin中,override某变量,必须要标注override!
这也是加强了类继承中,变量重写的界定。
kotlin较java
kotlin对继承更细化,对继承中,增强 改变的部分 的标注
先说结论
1、父结构体
2、父结构体内参数处理
3、子类 init & 属性
4、父类init & 属性
看范例
open class Base(val name: String) {
open val size: Int =
name.length.also { println("Initializing size in Base: $it") }
init { println("Initializing Base"+size) }
}
class Derived(
name: String,
val lastName: String
) : Base(name.capitalize().also { println("Argument for Base: $it") }) {
init { println("Initializing Derived") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in Derived: $it") }
}
fun main() {
println("Constructing Derived(\"hello\", \"world\")")
val d = Derived("hello", "world")
}
结果输出
Constructing Derived("hello", "world")
Argument for Base: Hello
Initializing size in Base: 5
Initializing Base0
Initializing Derived
Initializing size in Derived: 10
使用 super 关键字
基本与java一致
在一个内部类中访问外部类的超类,可以通过由外部类名限定的 super 关键字来实现:super@Outer
我们来看个范例,了解下
class FilledRectangle: Rectangle() {
fun draw() { /* …… */ }
val borderColor: String get() = "black"
inner class Filler {
fun fill() { /* …… */ }
fun drawAndFill() {
[email protected]() // 调用 Rectangle 的 draw() 实现
fill()
println("Drawn a filled rectangle with color ${[email protected]}") // 使用 Rectangle 所实现的 borderColor 的 get()
}
}
}
一个类继承多个
为了表示采用从哪个超类型继承的实现,需要显式的标明。
用由尖括号中超类型名限定的 super进行标明,如 super
范例
open class Rectangle {
open fun draw() { /* …… */ }
}
interface Polygon {
fun draw() { /* …… */ } // 接口成员默认就是“open”的
}
class Square() : Rectangle(), Polygon {
// 编译器要求覆盖 draw():
override fun draw() {
super.draw() // 调用 Rectangle.draw()
super.draw() // 调用 Polygon.draw()
}
}