Kotlin 中所有类都继承该 Any 类,它是所有类的超类,对于没有超类型声明的类是默认超类:

class Example // 从 Any 隐式继承

Any 默认提供了三个函数:

equals()hashCode()toString()

注意:Any 不是 java.lang.Object。

如果一个类要被继承,可以使用 open 关键字进行修饰。

open class Base(p: Int)           // 定义基类class Derived(p: Int) : Base(p)

构造函数

子类有主构造函数

如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。

open class Person(var name : String, var age : Int){// 基类}class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {}// 测试
fun main(args: Array<String>) {val s =  Student("Runoob", 18, "S12346", 89)println("学生名: ${s.name}")println("年龄: ${s.age}")println("学生号: ${s.no}")println("成绩: ${s.score}")
}

输出结果:

学生名: Runoob
年龄: 18
学生号: S12346
成绩: 89

子类没有主构造函数

如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。

class Student : Person {constructor(ctx: Context) : super(ctx) {} constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {}
}

实例

/**用户基类**/
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):super(name,age){println("-------继承类次级构造函数---------")println("学生名: ${name}")println("年龄: ${age}")println("学生号: ${no}")println("成绩: ${score}")}
}fun main(args: Array<String>) {var s =  Student("Runoob", 18, "S12345", 89)
}

输出结果:

-------基类次级构造函数---------
-------继承类次级构造函数---------
学生名: Runoob
年龄: 18
学生号: S12345
成绩: 89

重写

在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,那么就要手动添加 open 修饰它, 子类重写方法使用 override 关键词:

/**用户基类**/
open class Person{open fun study(){       // 允许子类重写println("我毕业了")}
}/**子类继承 Person 类**/
class Student : Person() {override fun study(){    // 重写方法println("我在读大学")}
}fun main(args: Array<String>) {val s =  Student()s.study();}

输出结果为:

我在读大学

如果有多个相同的方法(继承或者实现自其他类,如A、B类),则必须要重写该方法,使用super范型去选择性地调用父类的实现。

open class A {open fun f () { print("A") }fun a() { print("a") }
}interface B {fun f() { print("B") } //接口的成员变量默认是 open 的fun b() { print("b") }
}class C() : A() , B{override fun f() {super<A>.f()//调用 A.f()super<B>.f()//调用 B.f()}
}fun main(args: Array<String>) {val c =  C()c.f();}

C 继承自 a() 或 b(), C 不仅可以从 A 或则 B 中继承函数,而且 C 可以继承 A()、B() 中共有的函数。此时该函数在中只有一个实现,为了消除歧义,该函数必须调用A()和B()中该函数的实现,并提供自己的实现。

输出结果为:

AB

属性重写

属性重写使用 override 关键字,属性必须具有兼容类型,每一个声明的属性都可以通过初始化程序或者getter方法被重写:

open class Foo {open val x: Int get { …… }
}class Bar1 : Foo() {override val x: Int = ……
}

你可以用一个var属性重写一个val属性,但是反过来不行。因为val属性本身定义了getter方法,重写为var属性会在衍生类中额外声明一个setter方法

你可以在主构造函数中使用 override 关键字作为属性声明的一部分:

interface Foo {val count: Int
}class Bar1(override val count: Int) : Fooclass Bar2 : Foo {override var count: Int = 0
}

总结:

1、子类继承父类时,不能有跟父类同名的变量,除非父类中该变量为 private,或者父类中该变量为 open 并且子类用 override 关键字重写:

open class Person(var name: String, var age: Int) {    open var sex: String = "unknow"    init {        println("基类初始化")    }
}
// 子类的主构造方法的 name 前边也加了 var,这是不允许的,会报'name' hides member of supertype and needs 'override' modifier
class Student(var name: String, age: Int, var no: String, var score: Int) : Person(name, age) {override var sex: String = "male"
}

2、子类不一定要调用父类和接口中共同拥有的同名的方法

2、子类不一定要调用父类和接口中共同拥有的同名的方法

引用文章中的话:“C 继承自 a() 或 b(), C 不仅可以从 A 或则 B 中继承函数,而且 C 可以继承 A()、B() 中共有的函数。此时该函数在中只有一个实现,为了消除歧义,该函数必须调用A()和B()中该函数的实现,并提供自己的实现。”

我试过了,不是必须调用 A() 和 B() 中该函数的实现,代码如下:

open class A {open fun f() {println("A")}fun a() {println("a")}
}
interface B {fun f() {println("B")}fun b() {println("b")}
}
class C : A(), B {override fun f() {// super<A>.f()// super<B>.f()println("C")}
}

如上代码片段,注释掉 super<A>.f() 和 super<B>.f() 也不报错。

3、关于子类不能用 val 重写父类中的 var,我的猜测是:子类重写父类属性,也就相当于必须重写该属性的 getter 和 setter 方法,而子类中的 val 不能有 setter 方法,所以无法“覆盖”父类中 var 的 setter 方法,相当于缩小了父类中相应属性的使用范围,是不允许的,就像我们不能把父类中一个 public 方法重写成 private 方法一样。

4、如果一个变量想要在定义的时候被初始化,则该变量必须拥有 backing field 字段,该变量的默认 getter 和 setter 方法中是有定义 field 字段的,但是如果我们重写了这个变量的 getter 方法和 setter 方法,并且在 getter 方法和 setter 方法中都没有出现过 filed 这个关键字,则编译器会报错,提示 Initializer is not allowed here because this property has no backing field,除非显式写出 filed 关键字(哪怕它什么都不干,只要放在那里就可以了,我理解是出现一次就相当于“声明”过了,就可以用了,而在定义变量的时候初始化是要求 field 被“声明”过才可以):

var aaa: Int = 0
get() {field // 这里必须出现一下field关键字,否则 var aaa: Int = 0 会报错,除非你去掉 = 0这部分,不要给它赋初始化值return 0
}
set(value) {}

Kotlin的继承(二)相关推荐

  1. Kotlin教程(二)函数

    写在开头:本人打算开始写一个Kotlin系列的教程,一是使自己记忆和理解的更加深刻,二是可以分享给同样想学习Kotlin的同学.系列文章的知识点会以<Kotlin实战>这本书中顺序编写,在 ...

  2. kotlin中继承父属性使用构造方法

    kotlin中继承父属性使用构造方法 1. 定义父类,给它两个属性: abstract class AbstractResponseMessage {private var success = tru ...

  3. Kotlin实战指南二:变量、常量、静态常量

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/87811333 本文出自[赵彦军的博客] Kotlin初体验二:变量.常量.静态常 ...

  4. kotlin实现继承_Kotlin程序| 继承的例子

    kotlin实现继承 遗产 (Inheritance) Inheritance is a mechanism wherein a new class is derived from an existi ...

  5. kotlin多继承_Kotlin继承

    kotlin多继承 Continuing with our series of Kotlin tutorials, today we'll look into inheritance in Kotli ...

  6. Kotlin基础 (二)

    Kotlin基础 (二) 11_kotlin命令行交互式终端 12_kotlin函数加强 函数的本质 kotlin函数编写规则 实战编写一个计算器: 作业练习 14_kotlin字符串模版 15_ko ...

  7. 【Kotlin】Kotlin 类的继承 二 ( 属性覆盖 | 属性覆盖的四种情况 | 常量 / 变量 属性覆盖 | 子类初始化与属性覆盖 )

    文章目录 I . 属性覆盖基本方式 II . 属性覆盖的四种情况 III . 常量 ( val ) / 变量 ( var ) 属性覆盖 IV . 子类初始化时考虑覆盖属性的使用 I . 属性覆盖基本方 ...

  8. Kotlin Coroutine(二):作用域及取消

    一.协程作用域 定义协程必须指定其 CoroutineScope .CoroutineScope 可以对协程进行追踪,即使协程被挂起也是如此.同调度程序 (Dispatcher) 不同,Corouti ...

  9. Kotlin学习(二)Kotlin基础语法

    学习一门语言,我总是会先学习一下基本的语法.因为并不急着应用Kotlin去开发项目,所以,还是有很多的时间去学习.今天,简单的总结一下Kotlin的基本语法. 一.函数 1.有参有返回值函数 fun ...

最新文章

  1. Apache POI和EasyExcel 第三集:Apache POI的Excel大数据量写入(分为03版的xls、07版的xlsx、升级版SXSSF)
  2. UI5 Source code map机制的细节介绍
  3. 耗时两个礼拜,8000字安卓面试长文,建议收藏
  4. 关于svn、git生成版本号脚本的改进
  5. 最小生成树的纠结_交流电之王-ChinaUnix博客
  6. HDU-1796 How many integers can you find 容斥定理
  7. nginx限制请求之一:(ngx_http_limit_conn_module)模块
  8. pythonzip压缩字符串_Python压缩与解压缩ZIP文件的实现方法
  9. 使用小波变换进行灰度图像的融合
  10. RS-485接口协议详解
  11. unrecognized selector sent to instance XXXXX
  12. Java swing+Mysql商品销售管理系统
  13. 程序猿头头(数组应用)
  14. 华硕开机时出现无法验证数字签名驱动
  15. MediaPipe人体关键点检测复现和未解决问题
  16. Envoy代理GRPC服务支持通过restful进行访问
  17. 计算机哪个按键可以和弦,钢琴键盘和弦图解大全!作曲必看!老师和家长快收藏起来...
  18. 华为OD机试 - 自动曝光(C 语言解题)【独家】
  19. TWaver 3D作品Viewer查看器
  20. 闲谈“个人核心竞争力”与“危机感”

热门文章

  1. [C++ Primer] 第2章: 变量
  2. hdu-1088 Write a simple HTML Browser
  3. mysql备份恢复数据库据/表
  4. 千万级分页存储过程结合Repeater+Aspnetpager7.2实现
  5. linux 启动tomcat 怎么显示日志文件,随着LINUX的启动,打开一个终端显示TOMCAT的日志文件,请问如何做到?...
  6. linux安装控制台驱动,linux设备驱动之控制台驱动
  7. 修改php前台地址,PHPCMS如何增加电话、地址等方便前台调用的自定义变量
  8. android申请多个运行时权限,Android 6.0(API 23) 运行时权限(二)之权限申请
  9. 事务例子_Spring事务专题(四)Spring中事务的使用、抽象机制及模拟Spring事务实现...
  10. eclipse还原默认窗口_第3天 | 12天搞定Python,用Eclipse编写代码