> 文章列表 > Kotlin 面向对象(二)

Kotlin 面向对象(二)

Kotlin 面向对象(二)

【文字内容源于《疯狂Kotlin讲义》,代码内容原创】

Kotlin 面向对象(一)_桃子不出的博客-CSDN博客

目录

四、隐藏和封装

1、包和导包

2、Kotlin的默认导入

3、使用访问控制符

五、深入构造器

1、主构造器和初始化

2、次构造器和构造器重载

3、主构造器声明属性


四、隐藏和封装

封装( Encapsulation )是面向对象的三大特征之一(另外两个特征是继承和多态)。指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。

封装是面向对象编程语言对客观世界的模拟,在客观世界里,对象的状态信息都被隐藏在对象内部,外界无法直接操作和修改。对一个类或对象实现良好的封装,可以实现以下目的:
  • 隐藏类的实现细节
  • 让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对属性的不合理访问
  • 可进行数据检查,从而有利于保证对象信息的完整性
  • 便于修改,提高代码的可维护性

为了实现良好的封装,需要从两个方面考虑:

  • 将对象的属性和实现细节隐藏起来,不允许外部直接访问
  • 把方法暴露出来,让方法来控制对这些属性进行安全的访问和操作

1、包和导包

Kotlin 的包与 Java 的包相同,既是逻辑上的一个程序单元,也是一个命名空间。如果希望把函数、类放在指定的包结构下 ,则应该在 Kotlin 源程序的第一个非注释行放置如下格式的代码

package com.example.kotlintest

2、Kotlin的默认导入

Kotlin 默认会导入如下包:

  • kotlin.*
  • kotlin.annotation. *
  • kotlin.collections. *
  • kotlin.comparisons. * (自 Kotlin1.1起)
  • kotlin.io. *
  • kotlin.ranges.*
  • kotlin.sequences. *
  • kotlin.text. *

此外,对于JVM平台,还会自动导入如下两个包:

  • java.lang.*
  • kotlin.jvm. *

对于 JavaScript 平台,则额外导入如下包:

  • kotlin.js.*

3、使用访问控制符

Kotlin 提供了4个访问控制符 private、internal、protected、public 分别代表4个访问控制级别。 

  • private:与Java private类似private成员只能在该类的内部或文件的内部被访问
  • internalinternal成员可以在该类的内部或文件的内部或者同一个模块内被访问
  • protected:protected 成员可以在该类的内部或文件的内部或者其子类中被访问
  • public:public成语可以在任意地方被访问

五、深入构造器

构造器用于在创建实例时执行初始化。构造器是创建对象的重要途径,因此Kotlin类必须包含一个或一个以上的构造器。

1、主构造器和初始化块

Kotlin 类可以定义0~1个主构造器和0~N个次构造器。如果主构造器没有任何注解或可见性修饰符,则可以省略 constructor 关键字。

主构造器作为类头的一部分,可以声明形参,但它自己并没有执行体。那么主构造器的形参有什么用呢?其作用主要有两点:

【1】初始化块可以使用主构造器定义的形参

【2】在声明属性时可以使用主构造器定义的形参

由此可见, Kotlin 主构造器并不是传统意义上的构造器,它更像 Java 的初始化块,或者说是对初始化块的增强一-Java 的初始化块不能传入参数: Kotlin 通过主构造器的设计,允许为初始化块传入参数。
class Apple(name: String) {init {println("name is $name")}
}调用函数:
Apple("红富士")运行结果:
name is 红富士

程序调用主构造器创建对象,实际上就是执行初始化块。由此可见,主构造器的主要作用就是为初始化块定义参数,因此主构造器更像是初始化块的一部分。也可以说,初始化块就是主构造器的执行体。

2、次构造器和构造器重载

class Apple {var name: String?constructor() {name = "null"}constructor(name: String) {this.name = name}init {println("init...")}
}调用方法:
val a1 = Apple()
val a2 = Apple("红富士")
println("${a1.name}")
println("${a2.name}")运行结果:
init...
init...
null
红富士

上面的Apple类提供了两个重载的次构造器,但它们的形参列表不同。在调用构造器时,系统将根据传入的实参列表来决定调用哪个构造器。

从运行结果可以看出,不管调用哪个构造器创建对象,系统总会先执行初始化块。也就是说,初始化块总会在所有次构造器之前执行。用 Kotlin的专业术语来说,叫作:所有的次构造器都要委托调用初始化块。

class Apple(name: String) {operator fun component1(): String {return this.name}operator fun component2(): String {return this.color}var name: Stringvar color: String//委托给主构造器constructor(name: String, color: String) : this(name) {this.color = color}init {println("init...")this.name = namethis.color = "default"println("name is $name, color is $color")}
}调用函数:
val (name1, color1) = Apple("红富士")
val (name2, color2) = Apple("红富士", "红色")
println("$name1, $color1")
println("$name2, $color2")运行结果:
init...
name is 红富士, color is default
init...
name is 红富士, color is default
红富士, default
红富士, 红色

当程序调用主构造器创建实例时 主构造器自动执行初始化块;程序调用次构造器创建实例时,也会先执行初始化块,这是由于它们都委托了主构造器的缘故。

3、主构造器声明属性

Kotlin 允许在主构造器上声明属性,直接在参数之前使用 var / val 即可声明属性一一使用var 声明的是读写属性,使用 val 声明的是只读属性。当程序调用这种方式声明的主构造器创建对象时,传给该构造器的参数将会赋值给对象的属性。

class Apple(var name: String) {}调用函数:
val apple = Apple("红富士")
println("apple name is ${apple.name}")运行结果:
apple name is 红富士