kotlin入门潜修之类和对象篇—类和对象

本文收录于 kotlin入门潜修专题系列,欢迎学习交流。

写在前面

知人者智,自知者明。胜人者有力,自胜者强。——与君共勉。

kotlin中定义类的关键字和java一样,都是class,简单示例如下:

class Hello {}

类的定义主要有三部分组成:name、header以及body(即{}中的内容)。其中header和body都是可省略的,如果一个class没有body,则{}也可以省略。
类似于下面代码:

class Hello

构造方法

众所周知,java中的类都有构造方法,用户如果没有定义则由系统提供一个默认的无参构造方法。kotlin中也有构造方法,但是表达形式却和java相差很大。

在kotlin中,构造方法被分为了两个类型,一类是主构造方法(primary constructor);另一类被称为第二构造方法(secondary constructor)。其中,主构造方法有且只有一个,而第二构造方法可以有多个。

主构造方法

kotlin中的主构造方法示例如下:

class Person  private constructor(name: String){}

可以看出,主构造方法属于class header,位于class name之后,由constructor关键字来定义,可以有入参。

当class没有权限修饰符或者注解时(对于这个例子就是没有private)可以省略constructor关键字。如下所示:

class Person(name: String){}

需要注意的是,主构造方法不能包含任何代码语句,但是如果想要在主构造方法执行的时候做些操作怎么办?kotlin为我们提供了另一套机制来执行主构造方法的初始化。如下所示:

class Person(name: String, age: Int) {
    val firstProperty = "first property print person name: $name".run(::print)//这里f表示定义了一个属性
    init {//init块
        println("first init block print person name: $name")
    }
    val secondProperty = "second property print person age: $age".run(::print)
    init {
        println("second init block print person age: $age")
    }
}

代码调用如下:

       @JvmStatic fun main(args: Array<String>) {
            val person = Person("张三", 30)
        }

上面代码执行过后,依次打印如下:

first property print person name: 张三
first init block print person name: 张三
second property print person age: 30
second init block print person age: 30

这样说明了,init是和属性同级的,谁在前就先执行谁,即按照代码书写顺序执行。同时也表明,主构造方法中的参数可以在class body中初始化属性,如下所示:

class Person(name: String, age: Int) {
    val upperName = name.toUpperCase()
}

上面提到了kotlin中的属性,实际上对于用主构造方法初始化属性kotlin提供了更简洁的写法:

class Person(var name: String, age: Int) {//这里注意name和age定义的区别,name前面加上了var关键字(val关键字也一样),这表示name被定义为了属性
    fun getPersonName():String{
        return this.name//编译正确,因为name被定义为了属性
    }
    fun getPersonAge():Int{
        return this.age//!!!注意,这里无法通过编译,因为age不是属性
    }
}

再来看一个关于属性的例子:

class Person(var name: String, age: Int) {
    fun getName():String{//!!!注意,这里是无法编译通过的
        return this.name
    }

}

运行上面的代码发现,根本无法编译通过,为什么?这是因为kotlin中会默认为属性提供get、set方法,故会报方法已定义的错误。

第二构造方法

kotlin中可以有多个第二构造方法,其定义关键字依然是constructor,不过是在class body中定义,如下所示:

class Person {
    constructor(name: String) {//第二构造方法定义
        
    }
}

注意,当一个类既有主构造方法又有第二构造方法的时候,第二构造方法必须要直接或者间接的委托实现主构造方法(即要首先完成主构造方法的初始化)。如下所示:

class Person(name: String) {
    constructor(name: String, age: Int) : this(name) {//直接委托实现主构造方法

    }
    constructor(name: String, age: Int, sex: String) : this(name, age) {//间接的通过两个参数的第二构造方法委托实现主构造方法
        
    }
}

从上面代码可以看出,kotlin是通过this关键字来实现委托机制的,从这里来看,this的使用方法和java异曲同工。

再看下面一个例子:

class Person(name: String) {
    init {
        println("init execute...")
    }
    constructor(name: String, age: Int) : this(name) {
        println("second execute...")
    }
}

上述代码执行过后,打印结果如下:

init execute...
second constructor execute...

由此可知,在委托机制发生的时候,kotlin会先于第二构造方法执行init块,这是因为init是作为主构造方法的一部分执行的,而主构造方法先于第二构造方法,故init块也会先于第二构造方法执行。

那如果没有显示定义主构造方法呢?如下所示:

class Person {//注意这里,并没有定义主构造方法
    init {
        println("init execute...")
    }
    constructor(name: String, age: Int) {
        println("second constructor execute...")
    }
}

上述代码执行结果为:

init execute...
second constructor execute...

从执行结果来看,和有主构造方法执行顺序保持一致。这是为什么?这是因为一个class即使没有主构造方法,委托依然会隐式的发生,所以init会得到执行。

如果class既没有主构造方法也没有第二构造方法,kotlin会自动生成一个无参的主构造方法,且该方法默认为public,如果想要改变其修饰权限,可以自己定义主构造方法,如下所示:

class Person {//这里会默认生成一个共有的无参的主构造方法
}

class Person private constructor(){//通过这种方式可以定义一个私有的主构造方法
}

此外,如果主构造方法都有默认值(这里的默认值是指所有入参都要有默认值),那么kotlin编译器会为该类再默认生成一个无参的主构造方法,这么做的目的是为了方便第三方库的使用(如jackson使用时需要无参的实例等),如下所示:

        class Person constructor(val name: String = "") {//注意,name有默认值
        }
        //调用处代码
        @JvmStatic fun main(args: Array<String>) {
            val person2 = Person()//注意这里,创建了一个无参的person对象,而Person类并没有提供无参构造方法,证明编译器帮我们生成了一个主无参构造方法
            val person = Person("张三")
        }

对象

前面介绍kotlin的类相关机制的时候已经用到了其对象,基本和java一致,但是和java有个最大的区别就是,kotlin不在提供new关键字,二者对比如下:

//java代码
Person person = new Person()

//kotlin代码
val person = Person()//注意,这里没有了new关键字

类成员

前面已经提到了class所包含的部分成员,比如构造方法、属性等,下面罗列下class中具体都可以包含哪些成员:
— 构造方法和init块
— 方法(后面文章会分析)
— 属性(后面文章会分析)
— 嵌套类和内部类(后面文章会分析)
— object 定义(即kotlin中特有的单例,后面文章会阐述)

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