Kotlin第二讲 —— Class(构造函数,属性,成员函数)

Kotlin是纯粹的面向对象语言,类可以帮助我们很好的实现封装,创建各种各样的对象。
使用关键字class声明类,包含类名、类头和类体
我们继续盖房子,创建了一个House类:

class House public @Inject constructor(name : Int){
    val myName :String = "Property--> my name is $name"
    init {
        println("This is init block, my house's name is $name")
    }
    constructor(param: Int) : this("Green House") {
        println("This is second constructor!")
    }
    fun whoAmI(){
        println("I am $myName")
    }
}

上面是一个完整的类声明,类名(House),类头(public constructor(name : Int),类体(大括号括起来的部分)。
类体又包括属性(myName字段),init块,次构造函数(constructor定义)和方法(fun

构造函数

  • 一个类可以有一个主构造函数(跟在类名后面)
  • 主构造函数不能包含任何代码,初始化代码放到init关键字的初始化块中
  • init块和属性都可以使用主构造函数的参数
  • 可以有N个次构造函数(N>=0)
  • 次构造函数需要委托给主构造函数,可以直接委托,或者通过其他构造函数委托,同一个类内部,使用this即可(this(“Green House”))

如果不委托的话会发生什么呢?

    constructor(){
        println("This is third constructor")
    }

编译一下,会看到提示
Error:(12, 5) Kotlin: Primary constructor call expected
我们开始化繁为简,Kotlin在未声明可见性的情况下,默认为public(下文会讲可见性),于是public可以省略:

class House @Inject constructor(name : String){
/**do something*/
}

不是所有的类定义都需要注解,当这两个条件同时满足时,可以省略constructor

class House (name : String){
/**do something*/
}

如果我们定义的类,不需要参数:

class House {
    constructor(param: Int){
        println("This is second constructor!")
    }
}

这种时候,委托会隐式发生,当然,还是会执行init初始化块
Kotlin更神奇的地方是,可以没有类体

class House

你没看错,这是一行合法的代码

这些构造函数,会在什么时机用到呢?——创建类的实例
Kotlin没有new 关键字,创建类的实例,跟调用方法写法是一样的:

    var house = House()
    val house2 = House(10)

运行一下:
在这里插入图片描述

属性

Kotlin中定义属性使用var(可变)和val(不可变)
定义一个属性的完整字段包括:

var [: ] [= ]
    []
    []

下面是一个完整的property定义:

    var myName :String? = "Property--> my name is Green House!"
        get() = "My value has changed! field is $field"
        set(value) {
            if (value != null) {
                field = value
            }
        }
  • 本例子使用var定义可变属性,并使用"Property–> my name is Green House!"赋初值
  • 属性名称myName,首字母小写,需要遵循驼峰命名
  • 属性类型为String,可为null(?标识可以为null)
  • 重写了get(),返回“My value has changed!”
  • 重写set(),判断不为null时才能赋值,也就是说myName不会再为null了
  • 此处需要扩展一些知识点,value是set的默认参数,当然你也可以改用别的名称
  • field标识符只能用在属性的访问器内,当一个属性需要幕后字段时,Kotlin会自动提供。这个幕后字段可以使用field标识符在访问器中引用。

Kotlin语言,访问属性比较简单,直接使用对象+属性名称访问(虽然用起来方便,但个人认为有点破坏封装,稍有不慎,所有内部的实现都会暴露在用户面前):

    var house = House()
    println(house.myName)
    house.myName="I have changed to Red"
    println(house.myName)

我们看一下运行结果:
在这里插入图片描述
可以看到,通过重写get()可以改变属性返回值,通过重写set()可以重新定义属性的赋值方式。
如果把var改成val属性会怎么样呢?
Kotlin第二讲 —— Class(构造函数,属性,成员函数)_第1张图片
会出现编译错误,A ‘val’-property cannot have a setter,可以看到val变量是不允许有set函数的。

  • 一般地,属性声明为非空类型必须在构造函数中初始化
    上面的初始化可以简化为:
class House (val myName="Property--> my name is Green House!")
  • 在构造函数中初始化,在某些时候会带来不方便,于是就有了lateinit关键字,用该关键字说明的属性,不会在类实例化的时候初始化,你可以选择在任何时候对它进行初始化,当然,在初始化前访问一个 lateinit 属性会抛出一个特定异常
lateinit var subject: TestSubject
fun setup() {
    subject = TestSubject()
}

成员函数

类内部的成员函数,跟上一章节说的函数是完全一样的,在类的内部自然多了一些跟类相关的属性,比如openoverride,Kotlin关于函数是否能被覆盖,以及覆盖父类的函数,都需要显示说明。详情我们会在类的覆盖和继承中讲解

open fun area(length: Int, width: Int): Int {
    return length * width
}

返回目录

你可能感兴趣的:(Kotlin,Android)