Kotlin 面向对象(一)

news2024/11/23 22:09:09

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

目录

一、类和对象

1.定义类

2.对象的产生和使用

3.对象的this引用

二、方法详解

1.方法与函数的关系

2.中缀表示法

3.componentN方法与解构

4、数据类和返回多个值的函数

5、在Lambda表达式中结构

三、属性和字段

1、读写属性和只读属性

2、自定义getter和setter

3、幕后字段

4、幕后属性

5、延迟初始化属性


一、类和对象

1.定义类

Kotlin 的类定义由类名、类头(指定其泛型声明、主构造器等)和用花括号包围的类体构成。类头和类体都是可选的。对于一个类定义而言,可以包含3种最常见的成员:构造器、属性和方法,这 种成员都可以定义零个或多个,如果三种成员都只定义零个,就是定义了一个空类。空类没有类体,可以省略花括号。

/**
 * Created by tzbc on 2022/6/2.
 *
 * @author tzbc
 */
class Fruit(name: String, color: String) {

    var fruitName: String = name
    var fruitColor: String = color

    fun getFruitInfo(): String {
        return "fruitName is $fruitName, fruitColor is $fruitColor";
    }
}

2.对象的产生和使用

创建对象的根本途径是构造器,调用某个类的构造器即可创建这个类的对象,并且无须使用new 关键字。

Kotlin 的对象大致有如下作用。

【1】访问对象的属性

【2】调用对象的方法

如果访问权限允许,那么在类中定义的方法和属性都可通过对象来调用。

通过对象访问方法或属性的语法是:对象属性|方法(参数)。

在这种方式中,对象是主调者,用于访问该对象的属性或方法。

val fruit1: Fruit = Fruit("苹果", "红色")
println(fruit1.getFruitInfo())

val fruit2: Fruit = Fruit("香蕉", "黄色")
fruit2.fruitName = "🍌"
println(fruit2.getFruitInfo())

运行结果:
fruitName is 苹果, fruitColor is 红色
fruitName is 🍌, fruitColor is 黄色

3.对象的this引用

Kotlin 也提供了 this 关键字, this 关键字总是指向调用该方法的对象。根据 this 出现位置的不同, this 作为对象的默认引用有两种情形:

【1】在构造器中引用该构造器正在初始化的对象

【2】在方法中引用调用该方法的对象

在后面介绍的扩展函数或带接收者的匿名函数中, this 代表点号左侧传递的接收者。this 关键字最大的作用就是让类中的1个方法访问该类的另1个方法或属性。假设定义了Dog 类,这个 Dog 对象的 run()方法需要调用它的 jump()方法,此时就可通过 this 关键字作为 jump()方法的调用者。

this 可以代表任何对象,当 this 出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的。它所代表的只能是当前类的实例:只有当这个方法被调用时,它所代表的对象才被确定下来(谁在调用这个方法, this 就代表谁)。

class Fruit(name: String, color: String) {

    var fruitName: String = name
    var fruitColor: String = color

    fun getFruitInfo(): String {
        println(this.initFruit())
        return "fruitName is $fruitName, fruitColor is $fruitColor"
    }

    private fun initFruit() = "This is fruit!"
}

调用函数:
val fruit = Fruit("苹果", "红色")
println(fruit.getFruitInfo())

运行结果:
This is fruit!
fruitName is 苹果, fruitColor is 红色

Kotlin允许对象的一个成员直接调用另一个成员,可以省略this前缀,也就是说将上面的方法调用改为以下形式也完全正确。

fun getFruitInfo(): String {
    println(initFruit())
    return "fruitName is $fruitName, fruitColor is $fruitColor"
}

大部分时候,一个方法调用类中的其他方法、属性时无须使用this前缀,但如果方法中有一个局部变量和属性同名,但程序又需要在该方法中访问这个被隐藏的属性,则必须使用this前缀。

二、方法详解

1.方法与函数的关系

Kotlin 的方法与函数其实是统一的,不仅定义函数和方法的语法相同,而且定义在类中的方法依然可独立出来。 也就是说,即使我们将方法定义在类里面,这个方法也依然可以转换为函数。

2.中缀表示法

Kotlin 的方法还可使用 infix 修饰,这样该方法就可通过中缀表示法调用,就像这些方法 是双目运算符一样。需要指出的是, infix 方法只能有一 个参数一一原因很简单,因为双目运算符的后面只能带 1个参数。

中缀表达式的要求:

  • 中缀表达式必须是扩展函数方法
  • 中缀表达式只能有一个参数
  • 中缀表达式的参数不能有默认值(否则参数可能为空)
  • 中缀表达式的参数不能是可变参数(否则参数可能不止一个)
infix fun Int.judge(other: Int): String {
    return when {
        this - other < 0 -> "小于"
        this - other > 0 -> "大于"
        else -> "等于"
    }
}


调用函数:
println(33 judge 41)

运行结果:
小于

3.componentN方法与解构

Kotlin 允许将一个对象N个属性“解构”给多个变量如果希望将对象解构给多个变量,那么必须为该对象的类定义 componentN()方法

程序希望将对象解构给几个变量,就需要为该类定义几个 componentN()方法,且该方法需要使用 operator修饰。

在某些时候,程序希望解构对象后面几个 componen tN ()方 法的返回值、忽略前面几个
componentN ()方法的返回值,此时可通过下划线_来占位。
//定义operator修饰的componentN方法,用于解构
operator fun component1(): String {
    return this.fruitName
}

//定义operator修饰的componentN方法,用于解构
operator fun component2(): String {
    return this.fruitColor
}

调用函数:
val (name, color) = Fruit("苹果", "红色")
//上述代码的实际处理方式为
//val name = Fruit("苹果", "红色").component1()
//val color = Fruit("苹果", "红色").component2()
println(name)
println(color)
val (_, color1) = Fruit("苹果", "红色")
println(color1)

运行结果:
苹果
红色
红色

思考:遍历map

for((key,value) in map){
    //使用key、value
}

4、数据类和返回多个值的函数

思路:借用解构

fun getMultiFruitByType(int: Int): Fruit {
    return when (int) {
        0 -> Fruit("苹果", "红色")
        1 -> Fruit("香蕉", "黄色")
        else -> Fruit("null", "null")
    }
}


调用函数:
val (multiName, multiColor) = getMultiFruitByType(1)
println("multiName=$multiName, multiColor=$multiColor")

运行结果:
multiName=香蕉, multiColor=黄色

5、在Lambda表达式中结构

Kotlin 允许对 Lambda 表达式使用解构,如果 Lambda 表达式的参数是支持解构的类型,它们都具有 operator 修饰的 componentN()方法),那么即可通过将它们放在括号中引入多个新参数来代替单个参数。

三、属性和字段

1、读写属性和只读属性

Kotlin 使用 val 定义只读属性,使用 var 定义读写属性,系统会为只读属性生成getter方法,会为读写属性生成 getter + setter 方法。

在定义 Ko tlin 普通属性时,需要程序员显式指定初始值:要么在定义时指定初始值,要么在构造器中指定初始值。
var apple:String = ""
val banana:String = ""
apple = "苹果"
banana = "香蕉" //error

Kotlin 类中定义属性后,被 Kotlin 程序使用时只能使用点语法访问属性; Java 程序使用时只能通过getter 、setter 方法访问属性。

2、自定义getter和setter

定义getter、setter方法时无需使用fun关键字。

var fruitName: String = name
    get() {
        println("fruitName get()...")
        return "fruitName: $field"
    }
    set(value) {
        println("fruitName set()...")
        field = value
    }

调用函数:
val orange = Fruit("橙子","橙色")
println(orange.fruitName)
orange.fruitName = "橘色"

运行结果:
fruitName get()...
fruitName: 橙子
fruitName set()...

3、幕后字段

在kotlin中定义1个普通属性时,Kotlin 会为该属性生成field(字段)、getter和setter方法(只读属性没有setter方法〉。 Kotlin为该属性所生成的field就被称为幕后字段(backing field)。

只要满足以下条件 系统就会为属性生成幕后字段:
  • 该属性使用Kotlin自动生成的getter / setter方法或其中之一。换句话说,对于只读属性,必须重写 getter 方法:对于读写属性,必须重写getter + setter方法,否则总会为该属性生成幕后宇段。
  • 重写getter、setter方法时,使用 field 关键字显式引用了幕后字段。

在getter、setter方法中需要通过field关键字引用幕后字段

4、幕后属性

在个别情况下,开发者希望自己定义 field ,并为该 field 提供getter、setter方法,就像 Java所使用的方法。此时可使用 Kotlin 的幕后属性。

幕后属性就是用 private 修饰的属性。 Kotlin 不会为幕后属性生成任何 getter、setter 方法。 因此程序不能直接访问幕后属性,必须由开发者为幕后属性提供 getter、setter 方法。
//幕后属性
private var _taste:String = ""

5、延迟初始化属性

Kotlin 提供了 lateinit 修饰符来解决属性的延迟初始化。使用 lateinit 修饰的属性,可以在定义该属性时和在构造器中都不指定初始值。

lateinit 修饰符有以下限制。
  • lateinit 只能修饰在类体中声明的可变属性(使用val声明的属性不行,在主构造器中声明的属性也不行)
  • lateinit 修饰的属性不能有自定义的getter、setter方法
  • lateinit 修饰的属性必须是非空类型
  • lateinit 修饰的属性不能是原生类型(即 Java 种基本类型对应的类型)
Java 不同的是, Kotlin 不会为属性执行默认初始化。因此,如果在 lateinit 属性赋初始值之前访问它,程序将会引发“ lateinit property name has not been initialized 异常。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/334015.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PHP反序列化漏洞之pop链2

目录 题目&#xff1a; 题目代码&#xff1a; 分析&#xff1a;代码审计 通过以上分析&#xff0c;最终我们构建这个payload&#xff1a; 结果&#xff1a; 目标达到&#xff01; 题目&#xff1a; 这个题目分析就有难度了&#xff0c;需要掌握php的魔法方法的使用以及调用…

算法刷题打卡第85天:设计一个验证系统

设计一个验证系统 难度&#xff1a;中等 你需要设计一个包含验证码的验证系统。每一次验证中&#xff0c;用户会收到一个新的验证码&#xff0c;这个验证码在 currentTime 时刻之后 timeToLive 秒过期。如果验证码被更新了&#xff0c;那么它会在 currentTime &#xff08;可…

你评论,我赠书~【哈士奇赠书 - 13期】-〖Python程序设计-编程基础、Web开发及数据分析〗参与评论,即可有机获得

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…

100 行 shell 写个 Docker

作者&#xff1a;vivo 互联网运维团队- Hou Dengfeng 本文主要介绍使用shell实现一个简易的Docker。 一、目的 在初接触Docker的时候&#xff0c;我们必须要了解的几个概念就是Cgroup、Namespace、RootFs&#xff0c;如果本身对虚拟化的发展没有深入的了解&#xff0c;那么很…

java全栈知识点[面试篇](一)

jjava全栈知识点[面试篇]&#xff08;一&#xff09;阻塞与等待的状态转变⭐Synchronized本质上是通过什么保证线程安全的?volatile、synchronized和Lock如何保证可见性⭐Synchronized使得同时只有一个线程可以执行&#xff0c;性能比较差&#xff0c;有什么提升的方法?⭐syn…

Unity 进阶 之 AR/VR 3D空间场景中Laser镭射线拖拽UI实现问题的简单整理

Unity 进阶 之 AR/VR 3D场景中Laser镭射线拖拽UI实现问题的简单整理 目录 Unity 进阶 之 AR/VR 3D场景中Laser镭射线拖拽UI实现问题的简单整理 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、简单实现步骤 常规拖拽 常规拖拽在3D空间拖拽位置跳动问题 解决…

C++003-C++变量和数据类型2

文章目录C003-C变量和数据类型2C数据类型数据类型及定义数据类型及类型大小浮点数据的使用**题目描述**&#xff1a;求阴影面积**题目描述**&#xff1a;计算园的周长和面积如何取消科学计数法表示浮点数iomanip的作用比较多:布尔变量的使用隐式转换与显式转换**题目描述**&…

JAVA环境变量配置步骤及测试(JDK的下载 安装 环境配置教程)

一&#xff1a;JDK的下载、安装和配置1、输入下载地址&#xff1a;https://www.oracle.com/downloads/往下滑&#xff0c;看到Developer Downloads &#xff0c;点击 java点击 Java (JDK) for Developers选择你想要下载的jdk版本4、 点击 JDK Downloads &#xff0c;往下拉&…

树莓派系统创建指南

无意中发现一个落灰的树莓派 故事便开始了…… 准备工作 树莓派 3B一张大于 8G 的 micro SD 卡一个读卡器HDMI 显示器及连接线、键盘、鼠标等外围设备 系统镜像下载 推荐两个树莓派镜像下载网站 树莓派官方网站&#xff1a;https://www.raspberrypi.com/software/树莓派实…

python+request+pytest+pytest-html集成的API自动化测试框架

对于框架任何问题&#xff0c;欢迎联系我&#xff01; 需要框架源码的&#xff0c;请私聊我&#xff01; 一、框架架构 二、项目目录结构 ├────.gitignore ├────case_utils/ 测试用例相关的工具类&#xff0c;包括HTTP请求封装及用例数据处理&#xff0c;用例文件生…

常用的辅助类2(StringBuilder、StringBuffer、处理时间相关的类、对象比较器)

Java知识点总结&#xff1a;想看的可以从这里进入 目录7.7、字符串相关类7.8、时间处理7.8.1、JDK8前7.8.2、JDK8后1、时间日期类2、格式化日期3、其他7.9、对象比较器7.7、字符串相关类 String&#xff1a;JDK1.0出现&#xff0c;字符串类&#xff0c;被final修饰其值不可改。…

30个HTML+CSS前端开发案例(三)

30个HTMLCSS前端开发案例&#xff08;11-15&#xff09;小米上称右侧悬浮菜单实现代码效果图自动轮播图效果实现代码效果图小米商城二级下拉菜单效果实现代码效果图时间轴效果实现代码效果图QQ音乐排行榜效果实现代码效果图资源包获取小米上称右侧悬浮菜单 实现代码 <!DOC…

idea中使用Git

目录 一、在idea中配置Git 1、打开settings&#xff0c;搜索git&#xff0c;找到本地上的git安装目录&#xff0c;选择git.exe 2、本地git安装目录 二、获取Git 1、本地初始化仓库 2、选中项目这层目录&#xff0c;点击确定 2、从远程仓库克隆 三、本地仓库操作 1、将文…

阶段二4_常用API之StringBuilder

一. StringBuilder类概述 概述 : StringBuilder 是一个可变的字符串类&#xff0c;我们可以把它看成是一个容器&#xff0c;这里的可变指的是 StringBuilder 对象中的内容是可变的。 作用&#xff1a; 提高供字符串的操作效率 案例&#xff1a; /**证明StringBuilder提高供字…

api接口详解大全(看这篇就足以了)

api接口详解大全?优秀的设计是产品变得卓越的原因设计API意味着提供有效的接口&#xff0c;可以帮助API使用者更好地了解、使用和集成&#xff0c;同时帮助人们有效地维护它每个产品都需要使用手册&#xff0c;API也不例外在API领域&#xff0c;可以将设计视为服务器和客户端之…

函数/任意波形发生器 DG5072 技术资料

函数/任意波形发生器 DG5072 DG5000人性化的界面设计和键盘布局&#xff0c;给用户带来非凡体验&#xff1b;丰富的标准配置接口&#xff0c;可轻松实现仪器远程控制&#xff0c;为用户提供更多解决方案。 产品特性 4.3英寸16M真彩TFT液晶显示屏 350 MHz、250MHz、100 MHz或70…

Pacemaker详解、pcs命令详解和参数说明、centos8或bclinux8.2离线安装pcs以及搭建pcs、pcs的使用说明

文章目录Pacemaker详解一、前言二、 Pacemaker概述1、Pacemaker介绍2、pacemaker的服务模式。3、Pacemaker的架构4、Pacemake内部组件三、Pacemaker集群管理工具pcspcs说明最为常用的管理命令四、Pacemaker集群资源管理1、集群资源代理常用的命令方法2、集群资源约束3、集群资源…

国家政策鼓励使用电子保函和银行函证,君子签助推函证数字化建设

近日&#xff0c;国家发改委发文&#xff0c;推动电子保函应用&#xff0c;降低电子保函费用&#xff1b;财政部会同银保监会发文&#xff0c;开展数字化函证&#xff0c;有效提升函证效率和效果。政策的出台有助于加快推进普及电子函证应用。 发改委&#xff1a;鼓励使用电子…

PMP考试前两个月开始备考时间足够吗?

简单不代表报名费便宜&#xff0c;但报名费贵是肯定会难的&#xff0c;不然从何而来的含金量一说&#xff1f;花钱就能买到的话估计现在全中国持有pmp的一抓一大把。 时间完全足够的。 相信很多朋友都了解过&#xff0c;pmp的备考时间基本上是在2~3个月&#xff0c;2个月最为…

shell的变量和引用

文章目录二、变量和引用2.1 什么是变量2.2变量的命名2.3 变量的类型2.3.1 根据数据类型分类2.3.2 根据作用域分类2.4 变量的定义2.5 shell中的引用2.6 变量的运算练习&#xff1a;二、变量和引用 在程序设计语言中&#xff0c;变量是一个非常重要的概念。也是初学者在进行Shel…