kotlin学习--类和对象

在任何一门面向对象的语言编程里,类(class)都是最基础,但是一项非常重要的组成部分。code说万物皆对象,对象生成的也就是类,在kotlin中也是这样。所以今天让我们看看kotlin中的类。

一、类的定义和声明

在kotlin中类可以包含构造器、类初始化代码快、属性、函数、内部类和对象声明

1.1 关键字

类声明的关键字是class,eg:

class TestKotlinClass{
}

其中当类没有结构体的时候,大括号可以省略,eg:

class TestKotlinClass

二、类的属性

2.1 属性的定义

上一节分享我们有讲到了属性是可以用var和val这两个关键字来定义的

  • var:用这个var来修饰的变量是可读可写的
  • val:用这个val来修饰的变量只能读,不能写
class AttriKotlin {
    //val song :Int//Property must be initialized or be abstract
    val song :Int = 0
    var biao :String = "biao"
}

如上代码所示,在编辑器中当我们在类中定义属性的时候不允许我们不为属性初始化,除非使其抽象。但是在开发过程中我们会遇到先不初始化,在后续的逻辑中再使其初始化,kotlin也考虑到了这一点,提供了延迟初始化的方案kotlin延迟初始化

我们可以像使用普通函数那样使用构造函数创建类实例:

var attriKotlin = AttriKotlin() //kotlin中没有new关键字

要使用一个属性,只要用名称引用它即可

attriKotlin.biao //想要使用该属性使用"."就可以
attriKotlin.song

2.2 getter和setter

属性声明的完整语法

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

由此可以看出声明属性之后都有一个访问器,即getter和setter,访问器是可选的,也可以自定义。
如果属性类型可以从初始化语句或者类的成员函数中推断出来,那就可以省去类型,val不允许设置setter函数,因为它是只读的。

var attriOne:Int? //编译错误,需要一个初始化语句,默认实现了getter和setter
var attriTwo = 0 //推断类型为Int,默认实现了getter和setter
val attriThree = 1 //默认实现了getter 
val attriFour:Int? //默认实现了getter,但是必须在构造器中初始化
init{//主构造器的初始化段,init为关键字
    attriFour = 0
}
var attriFive:Int? //如果是var的话不能像上面这样声明,只能添加初始化语句或者在主构造器中作为参数传入或使用延迟初始化关键字,eg
class AttriKotlin constructor(var attriFive: Int?){
    init {
        attriFive = 0
    }
}
var nullable: Int? = null //可空变量 "?"是不能省略的,不然就跟普通变量一样了

实例:

 class AttriKotlin {
    var biao: String = "biao"
        get() = field.toUpperCase()   // 将变量赋值后转换为大写
        set(value) {
            field = if (value.isNotEmpty()) value else "null"
        }

    var age: Int = 100
        set(value) {
            if (value < 10) {       // 如果传入的值小于 10 返回该值
                field = value
            } else {
                field = -1         // 如果传入的值大于等于 10 返回 -1
            }
        }

    private val num: Int = 0

    val isBland: Boolean
        get() = this.num == 0

    var xie: String = ""
        get() = "不管如何我就是不会改"
        set(value) {
            field = if (value.isNotEmpty()) value else "null"
        }
    
}

fun main(args:Array<String>){
    var attriKotlin = AttriKotlin()
    attriKotlin.biao = "songbiao"
    println("name:${attriKotlin.biao}")

    attriKotlin.biao = ""
    println("name:${attriKotlin.biao}")

    attriKotlin.age = 9
    println("age:${attriKotlin.age}")

    attriKotlin.age = 20
    println("age:${attriKotlin.age}")

    println("isBland:${attriKotlin.isBland}")

    println("xie:${attriKotlin.xie}")
    attriKotlin.xie = ""
    println("xie:${attriKotlin.xie}")
    attriKotlin.xie = "value"
    println("xie:${attriKotlin.xie}")
}
 //以上例子中都用到了field,field指的是属性本身

输出结果

name:SONGBIAO
name:NULL
age:9
age:-1
isBland:true
xie:不管如何我就是不会改
xie:不管如何我就是不会改
xie:不管如何我就是不会改

从上面例子中我们在访问器中有用到field,field是什么,为什么要用到,让我们来了解下Field

在java中的我们都知道可以定义不赋值的变量,系统会给这个变量默认值。并且可为null,这样在后续的逻辑代码中,我们需要去判空。而kotlin中的可空变量相对于Java来说相对简洁了很多。接下来让我们看看kotlin中的空安全

2.3 编译时常数

开发中我们难免会用到一些静态常量,这些在kotlin中称为编译时常量,可以用关键字const,通常和val一起使用

  • 关键字:const
  • const的条件(正确使用方式)
    1、顶层声明(跳脱方法和类)
    2、初始化为String或基本类型的值
    3、在object修饰的类中声明,在kotlin中称为对象声明,它相当于Java中一种形式的单例类
    4、在伴生对象中声明

例子:
在顶层声明

const val constAttri:String = "顶层声明"

在object修饰的类中声明

object ObjectClass{
    const val constAttri:String = "在object对象中声明"
}

在伴生对象中声明

class AttriKotlin {
    companion object {
        const  val constAttri:String = "kotlin"
    }
}

调用

println("constAttri:$constAttri")
println("constAttri:${ObjectClass.constAttri}")
println("constAttri:${AttriKotlin.constAttri}")

打印

constAttri:顶层声明
constAttri:在object对象中声明
constAttri:在伴生对象中声明

2.4 番外---接口中的属性

在接口中属性的修饰符只能用public,eg:

interface Ikotlin{
    public var name:String
    private var age:Int//Abstract property in an interface cannot be private
    protected var sex:String//Modifier 'protected' is not applicable inside 'interface
    internal var birth:Int//Modifier 'internal' is not applicable inside 'interface'
}

从上面的例子可以看出在接口中使用private、protected、internal修饰符的时候会报错。属性的默认修饰符是public,因此public可以省略不写。

再看

var name:String = "biao"//Property initializers are not allowed in interfaces(接口中不允许属性初始值设定项)

从上面例子中可以看出接口中不允许属性初始化,如此我们好像不能像java那样直接从接口中引用属性,那怎么办列,只能通过定义一个类去实现该接口并重写该属性。eg:

interface Ikotlin{
    var name:String
}

class IKotlinImpl:Ikotlin{
    override var name: String
        get() = "biao"
        set(value) {}
}

val IName = IKotlinImpl().name
println("IName:$IName")

三、类的构造函数

类的代码执行循序-->主函数--次函数--其他代码按上到下执行 实现次函数的时候,主函数的代码会走,不管多少个次函数,只走一个(在说明类的构造器时引用)

  • 在kotlin中构造函数分为主构造函数和次构造函数,允许多个次构造函数存在
  • 关键字constructor

3.1 主构造函数

  • 主构造函数是类头的一部分,类名的后面跟上构造函数的关键字以及类型参数。
  • 主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀。

例子:

class TestKotlinClass  constructor(name:String){
//name使用val修饰的,constructor关键字可以省略
    init {  
        println("name--->$name")
    }
}
class TestKotlinClass(name:String){
//name使用val修饰的,constructor关键字可以省略
    init {  
        println("name--->$name")
    }
}

属性定义可以在主构造函数中,eg

class Runnan constructor(var one:Int,val two:String){
    init {
        one = 5
        println("one:$one\ntwo:$two")
    }
}

fun main(args:Array<String>){
    val runnan = Runnan(1, "two")
   val one = runnan.one
    println("one--$one")
}

结果:

one:5
two:two
one--5

什么时候constructor关键字可以省略呢?

  • 在构造函数不具有注释符或者默认的可见性修饰符时,constructor关键字可以省略。
  • 默认的可见性修饰符时public。可以省略不写。

想上面的例子中因为构造函数是默认public修饰符且没有注释符,故可以省略,来看看不能省略的例子

class PrivateClass private constructor(name:String){
    //用到了private修饰符,故不能省略
}
class AptClass @Inject constructor(num: Int){
    //用到了@Inject注解符,故不能省略
}

3.2 次构造函数

3.2.1 kotlin中支持二级构造函数,声明时需要加上constructor关键字作为前缀。

例子:

class MultConst(){
    constructor(参数列表){
    }
}
3.2.2 如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字。

例子:

class TestKotlinClass  constructor(name:String){
    init {
        println("name--->$name")
    }
    constructor(name: String,value:Int) : this(name) {
        println("name-->$name+===value-->$value")
    }
    constructor(name: String,value: Int,cn:String) : this(name) {
        println("name-->$name&&cn-->$cn&&value-->$value")
    }
}

fun main(args:Array<String>){
    var testKotlinClass = TestKotlinClass("biao",24,"China")
    testKotlinClass.biao = 2
    println("了解class-->${testKotlinClass.biao}")
}

结果:

name--->biao
name-->biao&&cn-->China&&value-->24
了解class-->2

说明:二级构造函数中的参数name是委托了主构造函数中的name
由上面例子可以看出当实例化类调用的是二级构造函数的时候,会先走init函数,再走二次函数的代码。

3.2.3 当类的主构造函数都存在默认值时的情况
  • 在JVM上,如果类主构造函数的所有参数都具有默认值,编译器将生成一个额外的无参数构造函数,它将使用默认值。 这使得更容易使用Kotlin与诸如Jackson或JPA的库,通过无参数构造函数创建类实例。
  • 同理可看出,当类存在主构造函数并且有默认值时,二级构造函数也适用

例子:

class Runnan constructor(var one:Int = 0,val two:String = "two"){
    init {
        println("one:$one///two:$two")
    }
    
    constructor(three:Int) : this(){
        println("three:$three")
    }
    
    constructor( one:Int = 1, two: String = "two", four:Int = 3):this(one, two){
        println("one:$one///two:$two///four:$four")
    }
}


fun main(args:Array<String>){
    val runnan = Runnan()
    val runnan1 = Runnan(1, "二")
    val runnan2 = Runnan(3)
    val runnan3 = Runnan(1, "二",30)
    val one = runnan3.one
    println("one--$one")
}

结果:

one:0///two:two
one:1///two:二
one:0///two:two
three:3
one:1///two:二
one:1///two:二///four:30
one--1

当实例化无参构造器的时候,用的是主构造器的默认值

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

推荐阅读更多精彩内容