赞
踩
Kotlin 是面向对象编程语言,与 Java 语言类似,都有类、对象、属性、构造函数、成员函数,都有封装、继承、多态三大特性,不同点如下。
在包下面右键,依次点击【New → Kotlin Class/File】,输入类名后,创建 Kotlin 类文件。
如下,创建了一个 Student.kt 文件。
- package com.zhyan8.kotlinStudy
-
- class Student {
- }
笔者为简化代码,将定义的类与 main 函数放在同一个文件中了。
如下,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
类的初始化顺序如下:
父类静态代码块(companion object)→ 子类静态代码块(companion object)→ 父类属性初始化 → 父类 init 代码块 → 父类构造函数 → 子类属性初始化 → 子类 init 代码块 → 子类构造函数。
主构造函数是紧接在类名后面的构造函数,次要构造函数是类体内部定义的构造函数,它们的区别如下。
- 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() {
- ...
- }
- 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
- 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) {
- ...
- }
封装是指将相关联的属性和函数封装到同一个类中,并且可以控制这些属性和函数的访问权限,它通过隐藏内部细节和提供清晰的接口,提高了代码的安全性、可维护性和可理解性,它是面向对象编程中的重要概念之一。
在 Kotlin 中,有四种访问权限修饰符:private、protected、internal 和 public。这些修饰符控制了代码中类、函数、属性等成员的可见性和访问权限。
继承是指一个类(称为子类或派生类)基于另一个类(称为父类或基类)创建新类,子类继承了父类的属性和函数,并且可以在此基础上进行扩展或修改,它是面向对象编程中的重要概念之一。在 Kotlin 中,继承使用冒号(:)来表示,Any 类是所有类的基类。
类的初始化顺序如下。
- 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
- 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
多态是指同一个函数可以在不同的对象上表现出不同的行为,这种行为通常通过继承和接口来实现。多态使得代码更加灵活和可扩展,是面向对象编程中的重要概念之一。
- 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
- 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
- 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 没有智能转换特性,需要进行强制类型转换。
使用 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
接口与抽象类有些类似,接口里只有抽象属性和函数(函数允许有默认实现,属性不能),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
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
- }
在 class 前面添加 data 关键字表示为一个数据类,编译器会根据主构造函数中声明的所有属性自动为其生成以下函数。
- 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)
为了确保生成代码的一致性和有效性,数据类必须满足以下要求。
数据类中成员函数的生成遵循以下规则。
componentN 函数的介绍见 → 运算符函数、解构函数、中缀函数。
内部类是指在类内部申明的类,并且在 class 前面添加了 inner 申明。
- fun main() {
- var a = A()
- var b = a.B()
- b.test()
- }
-
- class A {
- private var str1 = "A-abc"
- private var str2 = "A-xyz"
-
- private fun fun1() {
- println("A-fun1")
- }
-
- private fun fun2() {
- println("A-fun2")
- }
-
- inner class B {
- private var str1 = "B-abc"
-
- private fun fun1() {
- println("B-fun1")
- }
-
- fun test() {
- println(str1) // B-abc
- println(this@A.str1) // A-abc
- println(str2) // A-xyz
-
- fun1() // B-fun1
- this@A.fun1() // A-fun1
- fun2() // A-fun2
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。