Kotlin: 面向对象编程(补档)

在面向对象的语言中,可以创建“类”,“类”是对事物的一种封装

类与对象

类:Class ,生成一个“Person”类:

1
2
class Person {
}

这是一个空的类实现,在Kotlin中,类用“class”关键字声明,可以在类中加入字段和函数来丰富它的功能,如:

1
2
3
4
5
6
7
8
class Person {
var name = “”
var age = 0

fun eat() {
println(name + “ is eating.He is “ + age + “years old.”)
}
}

如以上代码,在Person类中创建了“name”、“age”字段并定义了“eat()”函数

类的实例化

如下代码为对Person类的实例化

1
2
3
4
5
fun main(){
val p = Person()//存疑,是否应该用var
p.name = “Jack”
P.age = 19
p.eat

以上便是面向对象的基本用法

  1. 类的封装
  2. 定义类中的字段与函数
  3. 对类进行实例化
  4. 根据需求调用类

继承与构造函数

继承是面向对象编程中一个极其重要的特性

如下定一个Student类

1
2
3
class Student {
var son = “”
var grade = 0

若使Student类能继承Person类(即让Student拥有Person中定义的字段和函数)

  1. 将Person类转换为可继承的类
  2. 用Student继承Person

将Person转换为可被继承的形式:

1
2
3
open class Person() {
...
}

如上代码,在class关键字前加上open关键字,即代表此类是可被继承的

用Student类继承Person

1
2
3
4
class Student : Person() {
var son = “”
var grade = 0
}

如上代码,在Student类名后加:Person,即代表其继承了Person类


关于Kotlin语言类中的构造函数

任何一个面向对象的编程语言都会有构造函数的概念,Kotlin将构造函数分成了两种:主构造函数和次构造函数。

主构造函数

每个类都默认地有一个不带参数的主构造函数,可以显式地为其指明参数。主构造函数没有函数体,直接定义在类名的后面即可,如下代码:

1
2
class Student(val son : String,val grade : Int) : Person(){
}

在此代码中,son和grade字段都被传入了主构造函数。因此,将Student实例化的时候,应传入构造函数中要求的所有参数。比如:

1
val student = Student(“a123”,5)

主构造函数没有函数体,若要在主构造函数中添加逻辑语句,需使用init关键字,如下代码:

1
2
3
4
5
6
class Student(val son : String , val grade : Int) : Person() {
init {
println(“son is “ + son)
println(“grade is “+ grade)
}
}

关于:Person()中的括号

在Kotlin以及Java中,都有一个规定:
子类中的构造函数必须调用父类中的构造函数
由于在子类“Sudent”中创建了一个构造函数,因此该构造函数必须调用父类“Person”中的构造函数。在Kotlin中,子类调用了父类中的哪个构造函数由父类类名后括号中的字段来决定。例如上述代码中括号中无任何字段,即调用了Person类中无参数的构造函数(即使是无参数的构造函数,也不能省略这对括号)

  • 若把Person类改为如下形式:
1
2
3
open class Person(val name : String , val age : Int) {
...
}

则子类Student中的构造函数需传入name与age两个字段,如下代码:

1
2
3
class Student(val son : String , val grade : Int , name:String , age:Int) : Person(name , age) {
...
}

注:在子类的构造函数传入父类中构造函数的字段时,不使用var或val对该变量进行声明。因为在构造函数中声明的字段会被自动归为该类的字段。若在子类的构造函数中重复声明,会与父类的字段发生冲突。
创建一个Student类的实例

1
val student = Student(“a123” , 5 , ”Jack” , 19)

次构造函数

任何一个类只能有一个主构造函数,但可以有无数多个次构造函数。次构造函数也可以用于实例化一个类。次构造函数有函数体。
Kotlin规定:当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数,如下代码:

1
2
3
4
5
6
class Student(val sno : String, val grade : Int , name : String , age : Int) : Person(name ,  age) {
constructor(name : Stirng , age : Int) : this(“ “ , 0 , name , age) {
}
constructor() : this(“” , 0){
}
}

次构造函数是通过constructor关键字来定义的

第一个次构造函数接收name和age参数,然后通过 :this关键字调用了主构造函数,并为sno以及grade赋初始值。

第二个次构造函数不接收参数,调用了第一个次构造函数(即间接地调用了主构造函数,这是合法的),并将name和age参数也赋初始值。

按照上述代码,将Student类实例化的三种方式:

val student = Student() 通过无参量的次构造函数将类实例化
val student = Student(“Jack”,19) 通过传入两个参量的次构造函数将类实例化
val student = Student(“a123” , 5 , “Jack” , 19)通过传入四个参量的主构造函数将类实例化


特殊情况:类中只有次构造函数,没有主构造函数

这种情况比较少见,但在Kotlin中这是允许的。当一个类没有显式地定义主构造函数且定义了次构造函数时,它就是没有主构造函数的,如下代码所示:

1
2
3
4
class Student : Person {
constructor (name : String , age : Int) : super(name, , age) {
}
}
  • Student类的后面没有显式地定义主构造函数
  • Student继承Person类的时候不用加()
  • 由于没有主构造函数,次构造函数只能调用父类的构造函数,用super关键字。

接口

接口是用于实现多态编程的重要组成部分。虽然一个类最多只能继承一个父类,但却可以实现任意多个接口。我们可以在接口中定义一系列的抽象行为,然后由具体的类去实现。

接口采用interface关键字定义,接口中的函数不要求有函数体。如下代码定义一个Study接口:

1
2
3
4
interface Study {
fun readBooks()
fun doHomework()
}

接下来让Student类实现Study接口:

1
2
3
4
5
6
7
8
9
class Student (name:String , age : Int) : Person ( name , age) , Study{
override fun readBooks() {
println(name + "is reading.")
}

override fun doHomework() {
println(name + "is doing homework.")
}
}

如上代码,在Student类声明中," : "之后:

  • 定义了Student类对Person类的继承
  • 实现了Study接口

" : “之间的各项用” , "分隔开

在main函数中调用Study接口的函数

1
2
3
4
5
6
7
8
9
fun main() {
val student = Student("Aucki",19)
doStudy(student)
}

fun doStudy(study: Study) {
study.readBooks()
study.doHomework()
}

Kotlin接口中函数的默认实现

修改Study接口中的代码:

1
2
3
4
5
6
interface Study {
fun readBooks()
fun doHomework(){
println("do homework default implementation")
}
}

如上代码,则表示在主函数调用了doHomework函数而在Student类中未规定doHomework函数的作用时,默认执行Study接口中所设定的函数功能,不强制要求实现doHomework函数。

若接口中的函数没有定义默认实现,则在实现该接口的类中(此处为Student类),强制实现该函数。


Kotlin中的函数可见性修饰符

关键字 作用
private 表示只对当前类内部可见
public 表示对所有类都可见
protected 表示只对当前类和子类可见
internal 表示只对同一模块的类可见

Kotlin中,默认的函数可见性是public


数据类与单例类

数据类

数据类用于将服务器端或者数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持。在Kotlin中创建一个数据类:

1
data class Cellphone {val brand : String , val price : Double )

如下代码示例,在主函数中测试该数据类:

1
2
3
4
5
6
fun main() {
val cellphone1 = Cellphone("Samsung" , 1299.99)
val cellphone2 = Cellphone("Samsung" , 1299.99)
println(cellphone1)
println("cellphone1 equals cellphone2 = " + (cellphone1 == cellphone2))
}

单例类

单例模式:单例模式是最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

在Kotlin中创建一个单例类:

1
2
object Singleton {
}

这样就创建了一个单例类Singleton了。我们可以直接在这个类中编写需要的函数,比如加入一个singletonTest()函数:

1
2
3
4
5
object Singleton {
fun singletonTest(){
println("singletonTest is called")
}
}

调用单例类中的函数:

1
Singleton.singletonTest()