Bootstrap

Kotlin语法入门-类与对象(6)

Kotlin语法入门-类与对象(6)

六、类与对象

1、声明和调用

fun main() {
    var a = A()  // 面相函数式,所以不用new关键字也可以
    a.print()
}

class A {
    val a = 2
    fun print() {
        println(a)
    }
}

2、get和set

在kotlin中,不能直接调用get和set方法,默认就是赋值就自动调用了set()方法,取值就自动调用get()方法。

就像下面这段示例,test.a = 5这个赋值操作调用set(),取值调用get():

fun main() {
    var test = A()
    test.a = 5
    test.print()

}

class A {
    var a = 2
        get() {
            return field - 1
        }
        set(value) {
            field = value + 1
        }
    fun print() {
        println(a)
    }
}

输出结果:

image-20240418153123854

3、init函数初始化

我们可以在类中添加初始化函数,每当创建一个类的对象之后,init方法就会自动调用,可以用于初始化数据

fun main() {
    var test = A()
}

class A {
    var a = 2
    init {
        println("A") //自动调用
    }
}

通过传入值初始化:

fun main() {
    var test = A(5)
}

class A(b: Int) {
    var a = 2

    init {
        a = b
    }
}

值得注意的是:在对对象传入值的之后可以同时对变量初始化,例如:class A(var b: Int) {},就代表了b就成为了A对象的成员变量,kotlin语法支持这样写。

但是只能在一级构造函数(主构造函数)上写这种,在二级构造函数中不支持这种语法,二级构造函数接下来有介绍。

4、constructor构造函数

在kotlin中奖构造函数分为主构造函数次构造函数

4.1、主构造函数
class  A constructor() {
    var a = 2
    init {
     	// 主构造函数的方法体
    }
}

其中,主构造函数关键字constructor可以省略不写,其构造的方法体就在init函数中。

4.2、二级构造函数
class A constructor(var b: Int = 1) {
    var a = 2

    init {
        println("init()...")
    }

    constructor() : this(3) { //代理主构造函数
        println("次构造函数...")
    }
}

注意:次构造函数需要主构造函数调用才能实现,即使用this()代理主构造函数,也可以传入参数this(3),可就是将b赋值为3。

这种方式就相当于java中的在构造方法中调用其他构造方法。

4.3、多个构造函数
class A constructor(var b: Int = 1) {
    var a = 2

    init {
        println("init()...")
    }

    constructor(c: Int, d: Int) : this(3) {
        println("次构造函数1...")
    }

    constructor() : this(1, 2) {
        println("次构造函数2...")
    }
}

image-20240418161321029

当然,次构2不一定要代理次构1,也可以直接代理主构,但是次构1就失效了。

4.4、省略主构造函数并写了次构造函数

例如这种,就直接成为主构造函数了:

class A  {
    constructor(c: Int, d: Int) {
        //此时识别为主构造函数
    }
}

多态

class A  {
    constructor(c: Int, d: Int) {
       
    }
    constructor(c: Int) {
        
    }
}

5、类的继承与重写

5.1、继承
fun main() {
    var b = B()
    b.print()
}

open class A {  //一定一定要添加open关键字
    var a = 1
}

class B : A() {
    var b = 2
    fun print() {
        println(a)
        println(b)
    }
}

一定一定要添加open关键字。

5.2、继承构造函数初始化

子类继承父类,子类要对父类进行构造方法的初始化:

1、主构造函数初始化

open class AParent {

}

class AChild() : AParent() {

} 

2、次构造函数初始化

open class AParent {

}

class AChild : AParent {
    constructor() : super(){}
}

3、父类多构造函数–子类主构造函数调用

当父类函数存在两个构造函数时,分别为主构造函数二级构造函数

open class AParent(name: String, age: Int) {
    constructor(name: String) : this(name, 30)
}

子类函数2:

class AChild() : AParent( "A") {}

子类函数1:

class AChild() : AParent( "A",15) {}

上述两种方式都可以实现父类构造函数的初始化,图解:

image-20240418172945118

3、父类多构造函数–子类副构造函数调用

image-20240418173640550

赋值输出:

fun main() {
    var aChild = AChild("rediaz")
    aChild.print()
}

open class AParent(var name: String, var age: Int) {
    constructor(name: String) : this(name, 30)
}

class AChild : AParent {
    constructor(name: String) : super(name)
    fun print(){
        println("name: ${super.name}")
    }
}

image-20240418174040391

5.3、函数的重写

正常继承,默认无法进行重写:

image-20240418174447191

它说需要override关键字,好嘛加上:

image-20240418174609562

然后又说基类的方法关键字是final修饰的。

正确重写方式,在父类的成员方法中加上open关键字:

open class AParent() {
    open  fun A() { println("A") }
    open fun B() { println("B") }
}

class AChild : AParent() {
    override fun A() {}
    override fun B() {}
}
5.4、属性的重写

这个是kotlin中特有的操作,Java中没有。

示例:

open class AParent() {
    open val a = 1
   open var b = 2
}

class AChild : AParent() {
    override val a: Int
        get() = super.a

    override var b: Int
        get() = super.b
        set(value) {}
}

上述这种方式就实现了重写属性成员a和b,其中a是常量,b是变量,所以重写之后有点区别。

重写的时候可以直接赋值进行覆盖:

open class AParent() {
    open val a = 1
    open var b = 2
}

class AChild : AParent() {
    override val a: Int = 0
    override var b: Int = 0
}

但是底层还是有get和set方法

重写时将a的val换成var,则其会将代码编译成新的变量,并生成对应的get和set方法:

image-20240418180434262

6、抽象类、嵌套类和内部类

6.1、抽象类

对于抽象类,其用法与Java无异

抽象是面向对象编程的特征之一,类本身,或类中的部分成员,都可以声明为abstract的。抽象成员在类中不存在具体的实现。

需要注意的是:不用对抽象类或抽象成员标注open注解。

abstract class AParent() { // 抽象类
    abstract fun sum() // 抽象方法
}

class AChild : AParent() {
    override fun sum() {
       
    }
}
6.2、嵌套类

先上代码:

fun main() {
    var aParent = AParent()
    aParent.print()
    var aChild = AParent.AChild()
    aChild.print()
}

class AParent() { // 抽象类
    fun print() {
        println("外部类")
    }

    class AChild() {
        fun print() {
            println("嵌套类")
        }
    }

}

注:在Java中,这是一个内部类的一个写法,但是在koltin中,这种事属于内部类的一个写法。

嵌套类是被final关键字修饰的

6.3、内部类

在嵌套类的基础上,在嵌套类的前面加上一个关键字inner就变成了内部类,并且可以访问外部类中的成员变量,使用this@类名的方式。示例:

fun main() {
    AParent().AChild().print()
}

class AParent() {
    val a = 1
    fun print() {
        println("外部类")
    }
 
    inner class AChild() { //加上inner关键字
        fun print() {
            println("嵌套类")
            println(this@AParent.a) //获取AParent中的a值
        }
    }
}
;