Kotlin学习笔记(5)- 类

系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正。如果你觉得我的文章对你有用,欢迎关注我,我们一起学习进步!
Kotlin学习笔记(1)- 环境配置
Kotlin学习笔记(2)- 空安全
Kotlin学习笔记(3)- 语法
Kotlin学习笔记(4)- 流程控制
Kotlin学习笔记(5)- 类
Kotlin学习笔记(6)- 属性
Kotlin学习笔记(7)- 接口
Kotlin学习笔记(8)- 扩展
Kotlin学习笔记(8)- 扩展(续)
Kotlin学习笔记(9)- 数据类
Kotlin学习笔记(10)- 泛型
Kotlin学习笔记(11)- 内部类和嵌套类
Kotlin学习笔记(12)- 委托
Kotlin学习笔记(13)- 函数式编程
Kotlin学习笔记(14)- lambda

一、类

1.类修饰符

修饰符分为属性修饰符和访问权限修饰符。

// 属性修饰符
annotation  //注解类
abstract   //抽象类
final     //类不可继承,默认属性
enum     //枚举类
open    //类可继承,类默认是final的

// 访问权限修饰符
private   //仅在同一个文件中可见
protected //同一个文件中或子类可见
public    //所有调用的地方都可见
internal  //同一个模块中可见
2.类定义

kotlin默认唯一构造器,暨类定义同时也是构造器。

class Person(name : String, age : Int) {
} 

翻译成java为:

final public class Person {
    public Person(String name, int age){
    }
}
3.构造函数

仔细看会发现,翻译成的java类定义前面有final修饰符,因为在kotlin中类默认为final的,也就是不可继承的。如果要继承,需要声明为open,或者abstract

class Person(name : String, age : Int)

如果连参数也没有,也可以这么写

class Person
4.类初始化

因为kotlin中的类定义同时也是构造函数,这个时候是不能进行操作的,所以kotlin增加了一个新的关键字init用来处理类的初始化问题,init模块中的内容可以直接使用构造函数的参数。

class Person(name : String, age : Int){
    init{
        // to do something
    }
}
5.次级构造函数

我们知道,java中可以有多个不同类型、不同个数的同名构造函数,以此满足我们的各种需求。而上面我们说过,kotlin中的类定义同时也是构造函数,kotlin中也默认只有这一个构造函数,那我们怎么办呢?很常见的一个问题是,View的自定义。根据android系统版本不同,View有3到4个构造函数,如果只用kotlin中的默认构造函数,我们确实可以在普通代码中正常使用,那么如何在xml中进行定义呢?旧版的kotlin没有处理这个问题,我们只能在java中自定义View,然后再进行调用。而在新版的kotlin已经解决了这个问题,那就是次级构造函数constructor。

次级构造函数用constructor加上参数,后面用this加上主构造函数的参数。同时次级构造函数中可以直接进行代码操作,所以没有init模块

class ParentClass(name: String) {
    var a = 1
    init {
        log("This is --> primary constructor, a=$a, name=$name")
    }

    constructor(name : String, age : Int) : this(name) {
        log("This is --> secondry constructor, a=${++a}, age=$age")
    }
}

// 翻译成java

final class ParentClass{
    int a = 1;
    public ParentClass(String name){
        log("This is --> primary constructor, a=$a, name=$name")
    }
    
    public ParentClass(String name, int age){
        this(name);
        log("This is --> secondry constructor, a=${++a}, age=$age")
    }
}

// 也就是说,如果新建一个类ParentClass("name", age),那么就会进行两次log输出
6.参数默认值

kotlin中支持类定义的时候,参数可以设置默认值。

// 含有默认值的参数,可以不传,也就是说ParentClass("xiaoming", 22, 1)和ParentClass("xiaoming", 22)这两种调用方式都是可以的
constructor(name : String, age : Int, sex : Int = 0) : this(name) {
    log("This is --> secondry constructor, a=${++a}, age=$age, sex=$sex")
}

如果构造函数中的所有参数都有默认值,则kotlin会多创建一个无参数的构造函数。

constructor(name : String = "", age : Int = 12, sex : Int = 0) : this(name) {
    log("This is --> secondry constructor, a=${++a}, age=$age, sex=$sex")
}

如果有多个构造函数,且某个或某几个构造函数中有默认值,则kotlin会选择最符合条件的一个作为构造函数。在下面的示例中,第三个构造函数的第三个参数是有默认值的,可以不传,这就和第二个构造函数有了相同的假象。kotlin的规则是,选择最符合条件的一个,也就是如果你这样创建:ParentClass("xiaoming", 22),kotlin会先去找只有这两参数类型的构造函数,也就是第二种。

class ParentClass(name: String) {
    var a = 1
    init {
        log("This is --> primary constructor, a=$a, name=$name")
    }

    constructor(name : String, age : Int) : this(name) {
        log("This is --> secondry constructor, a=${++a}, age=$age")
    }

    constructor(name : String, age : Int, sex : Int = 0) : this(name) {
        log("This is --> secondry constructor, a=${++a}, age=$age, sex=$sex")
    }
}

二、继承

1.继承的基本使用

在kotlin中,类默认是final类型的,也就是不可继承的。如果需要继承,需要显式的将类声明为open。我觉得这其实也表现出kotlin不推荐使用继承的一种态度,毕竟在面向对象设计中,是推荐多用组合、少用继承的。kotlin使用冒号:代替java中的extend来表示继承关系,如果父类的构造函数有参数,则在继承时也要注明。

open class ParentClass(name: String) {
    var a = 1
    init {
        log("This is --> primary constructor, a=$a, name=$name")
    }
}
class Child(name: String, age : Int) : ParentClass(name){
}
2.多构造函数的继承

次级构造函数初始化使用super关键字,类似于java中的super

class Child2 : ParentClass {
    constructor(name : String) : super(name){
        log("Child2 age : $name")
    }
    // 可以对参数进行扩展
    constructor(name: String, age: Int) : super(name){
    }
}
3.方法重载

同样的,秉承着多用组合、少用继承的原则,类中的方法默认也是final的,父类如果想要某个方法可以被子类重载,那么这个方法也要显式的被声明为open;而子类如果要重载父类的方法,则该方法必须使用override关键字。

open class ParentClass(name: String) {
    open fun publicMethod(){
        log("I am public")
    }
}
class Child(name: String, age : Int) : ParentClass(name){
    override fun publicMethod() {
        super.publicMethod()
    }
}

成员标记为override的本身是开放的,也就是说,它可以在子类中重写。如果你想禁止重写的,使用final关键字。

class Child(name: String, age : Int) : ParentClass(name){
    final override fun publicMethod() {
        super.publicMethod()
    }
}
4.同名方法

我们可能还会遇到一种问题:类实现了多个接口,其中某些接口中恰好有相同的方法。kotlin中使用尖括号对父类进行标记,以示区分。

open class ParentClass(name: String) {
    open fun publicMethod(){
        log("I am public from ParentClass")
    }
}
interface ParentInterface(name: String) {
    fun publicMethod(){
        log("I am public from ParentInterface")
    }
}
class Child(name: String, age : Int) : ParentClass(name),ParentInterface{
    override fun publicMethod() {
        super<ParentClass>.publicMethod()
        super<ParentInterface>.publicMethod()
    }
}

三、抽象

和java一样,抽象也使用abstract关键字。抽象类中可以没有抽象方法,但抽象方法一定在抽象类中。那么既然是抽象的,那么肯定是需要继承的,所以abstract自动包含open属性,这也是不言而喻的。

abstract class ParentClass(name: String) {
    abstract fun abstractMethod()
}
class Child(name: String, age : Int) : ParentClass(name){
    override fun abstractMethod() {
        //To implemented it
    }
}

其实抽象用到的也是继承,但是为什么没有放到第二部分里呢?这里有一点个人的理解。我觉得抽象和单纯的继承在使用目的上是有本质区别的。抽象是为了封装变化,将不同的实现交给不同的子类去完成。而单纯的继承和方法重载反而破坏了封装的美感,既然需要通过重载父类方法来实现目的,那很可能你在设计父类的时候就已经做出了不恰当的决定。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容