1 前言

​ Kotlin 是面向对象编程语言,与 Java 语言类似,都有类、对象、属性、构造函数、成员函数,都有封装、继承、多态三大特性,不同点如下。

  • Java 有静态(static)代码块,Kotlin 没有;
  • Java 有静态(static)函数,Kotlin 没有;
  • Java 构造函数名与类名相同,Kotlin 构造函数名为 constructor;
  • Kotlin 有初始化代码块(init),Java 没有;
  • Kotlin 有主构造函数,Java 没有。

​ 在包下面右键,依次点击【New → Kotlin Class/File】,输入类名后,创建 Kotlin 类文件。

​ 如下,创建了一个 Student.kt 文件。

package com.zhyan8.kotlinStudy

class Student {
}

​ 笔者为简化代码,将定义的类与 main 函数放在同一个文件中了。

2 类的结构

​ 如下,Student 类是一个自定义的类,里面包含了一个类的基本结构。

fun main() {
var stu1 = Student()
stu1.study()
println("-----------------------------------------")
var stu2 = Student("li si", 23)
} class Student {
private var name: String = "zhang san" // 属性
get() { // name的getter函数
return field
}
set(value) { // name的setter函数
field = value
} private var age: Int = 18 // 属性 init { // 初始化代码块, 在构造函数前执行
println("Student init, name=$name, age=$age")
} constructor() { // 无参构造函数
println("create-1, name=$name, age=$age")
} constructor(name: String, age: Int) { // 有参构造函数
println("create-2, name=$name, age=$age")
this.name = name
this.age = age
} fun study() { // 成员函数
println("study...")
}
}

​ 说明:init 代码块可以有多个,按照从前往后的顺序执行;上述构造函数都是次要构造函数,第 3 节中会介绍主构造函数。

​ 运行程序后,打印如下。

Student init, name=zhang san, age=18
create-1, name=zhang san, age=18
study...
-----------------------------------------
Student init, name=zhang san, age=18
create-2, name=li si, age=23

3 主构造函数

​ 主构造函数是紧接在类名后面的构造函数,次要构造函数是类体内部定义的构造函数,它们的区别如下。

  • 主构造函数:主构造函数只能存在一个,只有函数声明,没有函数体,可以在入参中定义类的属性,会自动进行类属性的初始化赋值。
  • 次要构造函数:次要构造函数可以存在多个,可以自定义函数体,也可以无函数体,不能在入参中定义类属性,当类有主构造函数时,所有次要构造函数必须直接或间接地调用主构造函数。

3.1 无参主构造函数

fun main() {
var stu1 = Student()
println("-----------------------------------------")
var stu2 = Student("zhang san")
} class Student() { // 等价与: class Student constructor()
init { // 初始化代码块, 在构造函数前执行
println("init")
} constructor(name: String): this() {
println("constructor, name=$name")
}
}

​ 运行程序后,打印如下。

init
-----------------------------------------
init
constructor, name=zhang san

​ class Student() 等价于 class Student constructor(),如果需要对主构造函数的权限进行控制,可以修改如下。

class Student private constructor() {
...
}

3.2 有参主构造函数(普通参数)

fun main() {
var stu1 = Student("xiao ming", 23)
println("-----------------------------------------")
// stu1.name // 编译报错, name不是成员属性
var stu2 = Student()
} class Student(name: String, age: Int) {
init {
println("init, name=$name, age=$age")
} constructor(): this("zhang san", 18) {
println("constructor")
}
}

​ 运行程序后,打印如下。

init, name=xiao ming, age=23
-----------------------------------------
init, name=zhang san, age=18
constructor

3.3 有参主构造函数(成员属性)

fun main() {
var stu1 = Student("xiao ming", 23)
println("stu1.name=${stu1.name}, stu1.age=${stu1.age}")
println("-----------------------------------------")
var stu2 = Student()
println("stu2.name=${stu2.name}, stu2.age=${stu2.age}")
} class Student(var name: String, var age: Int) {
init {
println("init, name=$name, age=$age")
} constructor(): this("zhang san", 18) {
println("constructor")
}
}

​ 说明:在主构造函数中,通过给入参添加 var(变量)或 val(常量)修饰,使得参数变为成员属性;在次要构造函数中,不能给入参添加 var 或 val 修饰。

​ 运行程序后,打印如下。

init, name=xiao ming, age=23
stu1.name=xiao ming, stu1.age=23
-----------------------------------------
init, name=zhang san, age=18
constructor
stu2.name=zhang san, stu2.age=18

​ 如果用户想修改入参属性的权限,可以在 var 或 val 前面添加权限修饰符。

class Student(private val name: String, protected var age: Int) {
...
}

4 封装

​ 封装是指将相关联的属性和函数封装到同一个类中,并且可以控制这些属性和函数的访问权限,它通过隐藏内部细节和提供清晰的接口,提高了代码的安全性、可维护性和可理解性,它是面向对象编程中的重要概念之一。

​ 在 Kotlin 中,有四种访问权限修饰符:private、protected、internal 和 public。这些修饰符控制了代码中类、函数、属性等成员的可见性和访问权限。

  • private:最严格的访问权限,只在声明它的类或文件内可见。
  • protected:与 Java 中的 protected 类似,不同之处在于 Kotlin 中 protected 修饰的成员仅对其子类可见,但不一定在同一个文件中可见。另外,protected 在 Kotlin 中不能直接应用于顶层函数和属性(直接定义在文件中的函数和属性,而不是在类中定义的)。
  • internal:模块内可见(模块是编译在一起的一组 Kotlin 文件),internal 修饰的成员对于同一模块中的任何其他代码都是可见的,但对于其他模块中的代码是不可见的。
  • public:最宽松的访问权限,public 成员可以被任何地方的代码访问,如果没有指定访问修饰符,默认为 public。

5 继承

​ 继承是指一个类(称为子类或派生类)基于另一个类(称为父类或基类)创建新类,子类继承了父类的属性和函数,并且可以在此基础上进行扩展或修改,它是面向对象编程中的重要概念之一。在 Kotlin 中,继承使用冒号(:)来表示,Any 类是所有类的基类。

​ 类的初始化顺序如下。

  1. 父类主构造函数
  2. 父类 init 代码块
  3. 父类次要构造函数
  4. 子类主构造函数
  5. 子类 init 代码块
  6. 子类次要构造函数

5.1 子类无主构造函数

fun main() {
var stu = Student("zhang san", 23, 1001)
} open class People(var name: String) {
init {
println("People init, name=$name") // 1
} constructor(name: String, age: Int): this(name) {
println("People constructor, name=$name, age=$age") // 2
}
} class Student : People {
init {
println("Student init, name=$name") // 3 (此处不能访问age和id)
} constructor(name: String, age: Int, id: Int) : super(name, age) {
println("Student constructor, name=$name, age=$age, id=$id") // 4
}
}

​ 说明:子类必须直接或间接调用一下父类的一个构造函数,否则编译报错。

​ 运行程序后,打印如下。

People init, name=zhang san
People constructor, name=zhang san, age=23
Student init, name=zhang san
Student constructor, name=zhang san, age=23, id=1001

5.2 子类有主构造函数

fun main() {
var stu = Student("zhang san", 23, 1001)
} open class People(var name: String) {
init {
println("People init, name=$name") // 1
} constructor(name: String, age: Int): this(name) {
println("People constructor, name=$name, age=$age") // 2
}
} class Student(name: String, var age: Int) : People(name, age) {
init {
println("Student init, name=$name, age=$age") // 3 (此处不能访问id)
} constructor(name: String, age: Int, id: Int): this(name, age) {
println("Student constructor, name=$name, age=$age, id=$id") // 4
}
}

​ 说明:子类必须直接或间接调用一下父类的一个构造函数,否则编译报错;当子类中有主构造函数时,子类中的次要构造函数。

​ 运行程序后,打印如下。

People init, name=zhang san
People constructor, name=zhang san, age=23
Student init, name=zhang san, age=23
Student constructor, name=zhang san, age=23, id=1001

6 多态

​ 多态是指同一个函数可以在不同的对象上表现出不同的行为,这种行为通常通过继承和接口来实现。多态使得代码更加灵活和可扩展,是面向对象编程中的重要概念之一。

6.1 覆盖函数

fun main() {
var peo: People = Student("li si", 25, 1002)
peo.say()
} open class People(var name: String, var age: Int) {
init {
println("People init, name=$name, age=$age")
} open fun say() {
println("People say")
}
} class Student(name: String, age: Int, var id: Int) : People(name, age) {
init {
println("Student init, name=$name, age=$age, id=$id")
} override fun say() {
println("Student say")
}
}

​ 运行程序后,打印如下。

People init, name=li si, age=25
Student init, name=li si, age=25, id=1002
Student say

6.2 覆盖属性

fun main() {
var peo : People = Student()
peo.doSomething()
} open class People {
open var name: String = "zhang san" fun doSomething() {
println("doSomething, name=$name")
}
} class Student : People() {
override var name: String = "li si"
}

​ 运行程序后,打印如下。

doSomething, name=li si

6.3 类型智能转换

fun main() {
var peo: People = Student()
// peo.study() // 编译报错
if (peo is Student) {
peo.study() // 智能转换为Student
}
} open class People {
} class Student : People() {
fun study() {
println("study...")
}
}

​ 说明:Java 没有智能转换特性,需要进行强制类型转换。

7 抽象类

​ 使用 abstract 修饰的类称为抽象类,抽象类中可以有抽象属性和函数,这些属性和函数被添加了 abstract 修饰符,父类不能实现,子类必须重写实现(子类如果也是抽象类除外)。抽象类不能被实例化,只能实例化其具化子类,抽象类中允许有具化的属性和函数。

fun main() {
// var peo = People() // 编译报错, 抽象类不能被实例化
var stu = Student()
stu.say()
} abstract class People {
abstract var name: String
abstract fun say()
} class Student : People() {
override var name: String = "xiao min" override fun say() {
println("$name: Hello")
}
}

​ 说明:Java 中只有抽象函数,没有抽象属性。

​ 运行程序后,打印如下。

xiao min: Hello

8 接口

​ 接口与抽象类有些类似,接口里只有抽象属性和函数(函数允许有默认实现,属性不能),Kotlin 中允许一个类实现多个接口,但最多只能继承一个类。

fun main() {
var c = C("xxx", "yyy")
c.aFun()
c.bFun()
} interface A {
var x: String
fun aFun()
} interface B {
var y: String
fun bFun()
} class C(override var x: String, override var y: String) : A, B {
override fun aFun() {
println("aFun, x=$x")
} override fun bFun() {
println("bFun, y=$y")
}
}

​ 运行程序后,打印如下。

aFun, x=xxx
bFun, y=yyy

9 枚举类型

1)枚举类

enum class Color(val tag: String) {
RED("red") {
override fun test() {
println("test, $tag")
}
},
GREEN("green") {
override fun test() {
println("test, $tag")
}
},
BLUE("blue") {
override fun test() {
println("test, $tag")
}
}; fun printColor(): Unit {
println("color=$tag")
} abstract fun test()
}

2)enumValueOf、enumValues

fun main() {
var color: Color = enumValueOf<Color>("RED")
var colors: Array<Color> = enumValues<Color>()
println(colors.joinToString()) // RED, GREEN, BLUE
}

3)name、ordinal、entries、values

fun main() {
println(Color.GREEN.name) // GREEN
println(Color.RED.ordinal) // 0
var entries: EnumEntries<Color> = Color.entries
println(entries) // [RED, GREEN, BLUE]
var colors: Array<Color> = Color.values()
println(colors.joinToString()) // RED, GREEN, BLUE
}

4)自定义属性和函数

fun main() {
Color.RED.printColor() // color=red
Color.GREEN.test() // test, green
println(Color.BLUE.tag) // blue
}

10 data class

​ 在 class 前面添加 data 关键字表示为一个数据类,编译器会根据主构造函数中声明的所有属性自动为其生成以下函数。

  • equals()
  • hashCode()
  • toString()
  • componentN()
  • copy()
fun main() {
val stu1 = Student("Zhang", 20)
val stu2 = Student("Zhang", 20)
// hashCode、equals
println(stu1 == stu2) // true
// toString
println(stu1) // Student(name=Zhang, age=20)
// componentN
var (name, age) = stu1
println("($name, $age)") // (Zhang, 20)
// copy
var stu3 = stu1.copy()
} data class Student(var name: String, var age: Int)

​ 为了确保生成代码的一致性和有效性,数据类必须满足以下要求。

  • 主构造函数中至少有一个参数。
  • 主构造函数中的参数必须标记为 val 或 var。
  • 数据类不能是抽象的、开放的、封闭的、内部的。

​ 数据类中成员函数的生成遵循以下规则。

  • 如果数据类中,equals、hashCode、toString 等函数存在显示实现,或者在父类中有 final 实现,则不会自动生成这些函数,并使用现有的实现。
  • 如果父类具有 open、componentN 函数,并返回兼容类型,则为数据类生成相应的函数,并覆盖父类的相应函数。
  • 不允许为 componentN 和 copy 函数提供显示实现。

​ 声明:本文转自【Kotlin】类和对象

【Kotlin】类和对象的更多相关文章

  1. Kotlin 类和对象

    类定义 Kotlin 类可以包含:构造函数和初始化代码块.函数.属性.内部类.对象声明. Kotlin 中使用关键字 class 声明类,后面紧跟类名: class Runoob { // 类名为 R ...

  2. Kotlin语法(类和对象)

    二.类和对象: 1. 类定义: 类的声明包含类名,类头(指定类型参数,主构造函数等等),以及类主体,用大括号包裹.类头和类体是可选的:如果没有类体可以省略大括号. class Invoice{ } 2 ...

  3. Kotlin基础(三)类、对象和接口

    类.对象和接口 一.定义类的继承结构 一)Kotlin中的接口 Kotlin的接口与Java8中相似,它们可以包含抽象方法的定义以及非抽象方法的实现,但它们不能包含任何状态. interface Cl ...

  4. 类和对象在JVM中是如何存储的,竟然有一半人回答不上来!

    前言 这篇博客主要来说说类与对象在JVM中是如何存储的,由于JVM是个非常庞大的课题,所以我会把他分成很多章节来细细阐述,具体的数量还没有决定,当然这不重要,重点在于是否可以在文章中学到东西,是否对J ...

  5. Kotlin类:功能更强、而更简洁(KAD 03)

    作者:Antonio Leiva 时间:Dec 7, 2016 原文链接:http://antonioleiva.com/classes-kotlin/ Kotlin类尽可能简单,这样用较少的代码完成 ...

  6. Java编程里的类和对象

    像我们搞计算机这块的,都知道这么一件事,当前的计算机编程语言主要分为两大块,一为面向过程,二为面向对象.Java就是一门纯面向对象的语言.学习了一个月左右的Java,在下对于Java当中的类和对象有了 ...

  7. Python - 类与对象的方法

    类与对象的方法

  8. C++基础知识(5)---类和对象

    终于把C++中的基础在前面的几篇博客中总结完了,可能还有一些语法还没有总结到,没关系,以后用到了再查资料就好.类是C++中的一个非常重要的概念,这是区别你使用的C++到底是面向过程还是面向对象的一个重 ...

  9. 简述JavaScript对象、数组对象与类数组对象

    问题引出 在上图给出的文档中,用JavaScript获取那个a标签,要用什么办法呢?相信第一反应一定是使用document.getElementsByTagName('a')[0]来获取.同样的,在使 ...

  10. 前端学PHP之面向对象系列第一篇——类和对象

    × 目录 [1]类 [2]成员属性[3]成员方法[4]对象[5]成员访问[6]this 前面的话 面向对象程序设计(OOP)是一种计算机编程架构.计算机程序由单个能够起到子程序作用的单元或对象组成,为 ...

随机推荐

  1. 有了这份Java面试中的葵花宝典,让你面试起飞!!!

    HashMap面试题 HashMap与HashTable的区别 1.HashMap线程不安全 HashTable 线程是安全的采用synchronized 2.HashMap允许存放key 为null ...

  2. HashMap,TreeMap,LinkedHashMap的默认排序

    简单描述 Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,HashTable以及LinkedHashMap等. TreeMap:能够把它保存的记录根据键(key)排序,默 ...

  3. DataGear数据可视化分析平台介绍

    DataGear 是一款开源免费的数据可视化分析平台,自由制作任何您想要的数据看板,支持接入SQL.CSV.Excel.HTTP接口.JSON等多种数据源. 系统特点: 友好的数据源接入 支持运行时接 ...

  4. 【Azure Function App】在VS Code中,创建好Function App后部署到Azure中,无法选择Subscriptions

    问题描述 在VS Code中,创建好Function App后部署到Azure中,无法选择Subscriptions 问题解答 对于无法使用 VS Code 部署 Function App 到 Azu ...

  5. 【Azure 应用服务】使用Python Azure SDK 来获取 App Service的访问限制信息(Access Restrictions)

    问题描述 为Azure App Service添加访问限制,需要Python Azure SDK来实现的示例代码. 问题解答 查阅Azure App Service的官方资料,使用Python SDK ...

  6. 【Azure 应用服务】本地Node.js部署上云(Azure App Service for Linux)遇到的三个问题解决之道

    问题描述 当本地Node.js(Linux + Node.js + npm + yarn)部署上云,选择 Azure App Service for Linux 环境.但是在部署时,遇见了以下三个问题 ...

  7. Java 类的内部成员之五:内部类

    1 package com.bytezreo.innerclass; 2 3 /** 4 * 5 * @Description 类的内部成员之五:内部类 6 * @author Bytezero·zh ...

  8. 关于Jitpack发布aar,会丢失内置依赖库问题

    原文:关于Jitpack发布aar,会丢失内置依赖库问题 | Stars-One的杂货小窝 关于发布aar出现的一个大坑排查,折腾了两天,终于是找到了解决方案 问题描述 有这样的一个情况,我新建了个A ...

  9. OBS无法捕获 chrome、webkit、electron窗口,捕获后黑屏

    使用 electron 打包的 pc 应用,用于直播软件推流的 OBS 捕获窗体黑屏 现象:唯独chrome浏览器 edge 浏览器等,其它窗体都正常. 猜测:是由 chromium 内核引起的 修改 ...

  10. Java加密技术(四)——非对称加密算法RSA

    Java非对称加密算法rsa     接下来我们介绍典型的非对称加密算法--RSA RSA     这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法.它易于理解和操作,也很 ...