Android笔试面试题AI答之Kotlin(9)
文章目录
- 39.Kotlin中List与MutableList的区别?
- List
- MutableList
- 使用场景
- 示例
- 40. Kotlin中实现单例的几种常见方式?
- 1. 懒汉式(线程不安全)
- 2. 懒汉式(线程安全)
- 3. 饿汉式
- 4. 双重校验锁(DCL, Double-Checked Locking)
- 5. 使用Kotlin的`by lazy`实现懒加载单例
- 41. 简述Kotlin中的 data 关键字的理解?
- 一、基本概念
- 二、特点
- 三、使用场景
- 四、示例
- 42. 简述Kotlin 委托属性?请简要说说其使用场景和原理?
- 原理
- 使用场景
- 示例
- 43. 请举例说明Kotlin中with与apply函数的应用场景和区别?
- with函数的应用场景
- apply函数的应用场景
- with与apply的区别
39.Kotlin中List与MutableList的区别?
在Kotlin中,List 和 MutableList 都是接口,它们都定义了对集合(即一系列元素)的基本操作,但它们在可变性(mutability)方面存在关键区别。
List
List是一个不可变(immutable)集合的接口,或者更准确地说,它代表一个不可变的列表。这意味着一旦一个列表被创建并初始化,你就不能添加、删除或修改列表中的元素。List接口继承自Collection<T>接口,提供了一系列操作列表的方法,如size()、isEmpty()、contains(element: T)、indexOf(element: T)、subList(int fromIndex, int toIndex)等,但这些操作都不会改变列表本身。- 由于
List代表了不可变性,它通常用于那些你不希望被修改的集合,或者当你需要一个可以安全地传递给多个线程而不担心并发修改问题的集合时。
MutableList
MutableList是一个可变(mutable)列表的接口,它继承自List<T>并添加了修改列表内容的方法,如add(element: T)、remove(element: T)、set(index: Int, element: T)等。- 通过这些方法,你可以添加新元素到列表中,从列表中删除元素,或者替换列表中特定位置的元素。
MutableList通常用于那些需要频繁修改集合内容的场景。
使用场景
- 当你的数据集合在创建后不需要改变时,使用
List。这有助于避免不必要的修改,并可能提高代码的安全性。 - 当你的数据集合需要在程序执行过程中被修改时,使用
MutableList。
示例
// List 使用示例
val immutableList: List<Int> = listOf(1, 2, 3)
// immutableList.add(4) // 这将编译错误,因为 List 是不可变的// MutableList 使用示例
val mutableList: MutableList<Int> = mutableListOf(1, 2, 3)
mutableList.add(4) // 正确,MutableList 是可变的
总之,List 和 MutableList 的主要区别在于它们的可变性。选择哪个取决于你的具体需求,即你是否需要修改集合的内容。
40. Kotlin中实现单例的几种常见方式?
在Kotlin中,实现单例模式有几种常见且简洁的方式。单例模式确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。以下是几种在Kotlin中实现单例的常用方法:
1. 懒汉式(线程不安全)
这种方式在第一次使用时才创建实例,但在多线程环境下可能不安全。
class Singleton {private var instance: Singleton? = nullcompanion object {fun getInstance(): Singleton {if (instance == null) {instance = Singleton()}return instance!!}}// 私有构造函数防止外部直接创建实例private constructor() {}
}
2. 懒汉式(线程安全)
通过加锁实现线程安全,但效率较低。
class Singleton {private var instance: Singleton? = nullcompanion object {@Synchronizedfun getInstance(): Singleton {if (instance == null) {instance = Singleton()}return instance!!}}private constructor() {}
}
或者使用synchronized代码块来优化性能(仅锁定需要同步的代码部分)。
3. 饿汉式
类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快,且线程安全。
object Singleton {// 这里直接定义对象,无需显式的构造函数
}
这是Kotlin中最简单、最常用的单例实现方式,利用了Kotlin的object关键字。
4. 双重校验锁(DCL, Double-Checked Locking)
这种方式既保证了线程安全,又避免了同步带来的性能影响。
class Singleton {private var instance: Singleton? = nullprivate val lock = Any()companion object {fun getInstance(): Singleton {if (instance == null) {synchronized(lock) {if (instance == null) {instance = Singleton()}}}return instance!!}}private constructor() {}
}
然而,在Kotlin中,由于object关键字的存在,我们几乎不需要手动实现双重校验锁这种复杂的单例模式。
5. 使用Kotlin的by lazy实现懒加载单例
这种方式结合了懒加载和线程安全的特性。
class Singleton private constructor() {companion object {val instance: Singleton by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {Singleton()}}
}
这里,by lazy用于延迟初始化,而LazyThreadSafetyMode.SYNCHRONIZED确保在多线程环境下懒加载是线程安全的。但是,对于大多数应用来说,直接使用object关键字提供的单例已经足够。
总结:在Kotlin中,由于object关键字的强大功能,实现单例模式变得非常简单且优雅。但在某些特殊场景下,你可能仍然需要手动实现单例模式,比如需要控制单例的初始化时机或需要更复杂的单例行为时。
41. 简述Kotlin中的 data 关键字的理解?
Kotlin中的data关键字用于声明数据类(Data Classes),这是一种特殊的类,旨在存储数据并自动生成一些常用的方法,以减少样板代码的编写量。以下是对data关键字的详细理解:
一、基本概念
在Kotlin中,数据类通过data关键字来修饰。数据类主要用于存储数据,而不是执行复杂的逻辑。通过在类声明前添加data关键字,Kotlin编译器会自动为该类生成一些实用的方法,如equals()、hashCode()、toString()和copy()等。
二、特点
-
自动生成方法:
- equals():用于比较两个数据类实例是否相等,基于它们的属性进行比较。
- hashCode():生成该数据类实例的哈希码,同样基于其属性。
- toString():返回数据类实例的字符串表示,格式为“类名(属性1=值1, 属性2=值2, …)”。
- copy():用于创建一个当前实例的浅拷贝,但允许修改部分属性值。
-
属性要求:
- 数据类的主构造函数必须至少有一个参数。
- 主构造函数中的所有参数必须声明为
val(只读)或var(可变),但通常推荐使用val以保持数据类的不变性。 - 数据类不能是抽象(abstract)、开放(open)、密封(sealed)或内部类。
-
解构声明:
- Kotlin支持解构声明,允许将数据类实例的属性解构为单独的变量。这种语法糖在处理数据类时特别有用,因为它可以使代码更加简洁。
-
componentN()方法:
- 对于包含N个属性的数据类,Kotlin会自动生成N个
componentN()方法(N为1到N的数字)。这些方法按属性声明的顺序返回相应的属性值,支持解构声明和其他相关操作。
- 对于包含N个属性的数据类,Kotlin会自动生成N个
三、使用场景
数据类非常适合用于那些仅包含数据的场景,如模型类(Model Classes)、数据传输对象(DTOs)等。通过使用数据类,可以减少样板代码的编写量,提高代码的可读性和可维护性。
四、示例
data class Person(val name: String, val age: Int)fun main() {val person = Person("Alice", 30)println(person) // 输出:Person(name=Alice, age=30)val anotherPerson = person.copy(name = "Bob")println(anotherPerson) // 输出:Person(name=Bob, age=30)val (name, age) = person // 解构声明println("Name: $name, Age: $age") // 输出:Name: Alice, Age: 30
}
在这个示例中,我们定义了一个名为Person的数据类,它包含两个属性:name和age。然后,我们创建了一个Person实例,并使用println打印它。接着,我们使用copy()方法创建了一个新的Person实例,但修改了name属性的值。最后,我们使用解构声明将person对象的属性解构为两个变量name和age,并打印它们。
42. 简述Kotlin 委托属性?请简要说说其使用场景和原理?
Kotlin中的委托属性是一种强大的语言特性,它允许一个类的属性不直接在该类中定义,而是将属性的获取和设置逻辑委托给另一个对象来处理。这种机制通过by关键字实现,使得属性的管理更加灵活和模块化。
原理
委托属性的原理基于Kotlin的委托模式,即一个对象(委托对象)将某些操作(如属性的获取和设置)委托给另一个对象(被委托对象)来处理。在Kotlin中,这通过实现特定的接口(如ReadOnlyProperty或ReadWriteProperty)并在这些接口的方法中定义属性的行为来实现。编译器会自动生成必要的辅助代码,以确保属性的访问被正确地转发给被委托对象。
具体来说,当定义一个委托属性时,你需要指定一个实现了ReadOnlyProperty(对于只读属性)或ReadWriteProperty(对于可读写属性)接口的对象。这个对象将负责处理属性的获取(通过getValue方法)和设置(通过setValue方法,对于可读写属性)。
使用场景
委托属性在Kotlin中有多种使用场景,包括但不限于:
-
属性值的预处理和后处理:例如,你可能希望在一个属性的值被设置之前进行验证,或者在获取值时对其进行格式化。通过委托属性,你可以将这些逻辑封装在被委托对象中,使主类保持简洁。
-
延迟初始化:使用
lazy委托可以实现属性的延迟初始化,即属性只在首次被访问时初始化。这对于那些初始化开销较大或仅在特定条件下才需要的属性非常有用。 -
属性监听:通过自定义的委托类,你可以实现属性的监听功能,即在属性值发生变化时执行特定的操作。这类似于Java中的观察者模式,但Kotlin的委托属性提供了一种更简洁的实现方式。
-
属性映射:在某些情况下,你可能希望将类的属性映射到另一个对象(如Map)中的键。通过委托属性,你可以轻松实现这种映射,而无需在每个属性的getter和setter方法中编写重复的代码。
-
简化Fragment参数传递:在Android开发中,Fragment之间经常需要传递参数。使用委托属性可以简化这一过程,使Fragment的代码更加清晰和易于维护。
示例
以下是一个简单的委托属性示例,展示了如何使用自定义的委托类来验证字符串属性的长度:
class LengthValidator(private val maxLength: Int) : ReadWriteProperty<Any?, String?> {private var value: String? = nulloverride fun getValue(thisRef: Any?, property: KProperty<*>): String? {return value}override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {if (value != null && value.length <= maxLength) {this.value = value} else {throw IllegalArgumentException("String too long")}}
}class User {var name: String? by LengthValidator(10)
}fun main() {val user = User()user.name = "Kotlin" // 正常赋值// user.name = "Kotlin is awesome" // 这将抛出IllegalArgumentException
}
在这个示例中,LengthValidator类是一个实现了ReadWriteProperty接口的委托类,它负责验证字符串属性的长度。User类中的name属性通过by关键字委托给LengthValidator实例来处理。这样,当尝试为name属性设置值时,如果值太长,就会抛出异常。
43. 请举例说明Kotlin中with与apply函数的应用场景和区别?
Kotlin中的with和apply函数都是作用域函数,它们提供了一种便捷的方法来对对象执行代码块,但它们在应用场景和具体行为上存在一些差异。以下将分别举例说明这两个函数的应用场景和区别。
with函数的应用场景
with函数不是扩展函数,它接受一个对象和一个扩展函数体(lambda表达式)作为参数,并在该对象的上下文中执行lambda表达式中的代码块。最后,它返回lambda表达式中最后一个表达式的结果。with函数的主要应用场景包括:
- 对同一对象执行多个操作:当你需要对一个对象执行多个操作时,但又不想在每次调用时都重复引用该对象名时,
with函数非常有用。 - 需要返回代码块执行结果:如果代码块中的最后一个表达式是一个有意义的返回值,且你需要这个返回值,那么
with函数是一个好的选择。
示例:
val person = Person()
val info = with(person) {printName()increaseAge()"Name: $name, Age: $age" // 返回字符串,包含了修改后的姓名和年龄
}
println(info) // 输出修改后的信息
在这个例子中,with函数接受person对象和一个lambda表达式,在person的上下文中执行了打印姓名、增加年龄和返回一个字符串描述信息的操作,最后返回了这个字符串。
apply函数的应用场景
apply函数是一个扩展函数,它在其接收者的上下文中执行代码块,并返回接收者对象本身。apply函数的主要应用场景包括:
- 对象初始化或配置:当你需要初始化或配置一个对象,并希望最后返回该对象以便进行链式调用或其他操作时,
apply函数非常合适。 - 链式调用:
apply函数允许你在配置对象时进行链式调用,使代码更加简洁和易于阅读。
示例:
val person = Person().apply {name = "Alice"age = 25// 可以继续链式调用其他方法或属性设置
}
println(person.name) // 输出 Alice
在这个例子中,apply函数在Person()新创建的实例上执行了设置姓名和年龄的操作,并返回了该实例。这使得我们可以立即在apply调用之后使用该实例,或者继续进行链式调用。
with与apply的区别
- 返回值:
with函数返回的是lambda表达式中最后一个表达式的结果,而apply函数返回的是其接收者对象本身。 - 调用方式:
with函数需要将对象作为第一个参数显式传递,而apply函数是扩展函数,直接作用于对象实例上。 - 适用场景:
with函数更适合于对同一对象执行多个操作并需要返回操作结果的情况;而apply函数则更适合于对象初始化或配置,以及链式调用等场景。
综上所述,with和apply函数各有其适用场景和优势,开发者可以根据具体需求灵活选择使用。
答案来自文心一言,仅供参考
相关文章:
Android笔试面试题AI答之Kotlin(9)
文章目录 39.Kotlin中List与MutableList的区别?ListMutableList使用场景示例 40. Kotlin中实现单例的几种常见方式?1. 懒汉式(线程不安全)2. 懒汉式(线程安全)3. 饿汉式4. 双重校验锁(DCL, Doub…...
C# 不一样的洗牌算法---Simd指令
洗牌算法,以随机打乱数组中元素的位置 测试数据创建 int[] _data; Random rng new Random(); protected override void CreateData() {_data new int[_size];for (int i 0; i < _data.Length; i){_data[i] i;} } 普通打乱数组元素位置 protected overrid…...
LVGL系列3--纯物理(外部)按键,数字键盘控制控件
LVGL系列 一、LVGL移植 LVGL系列1–AT32移植LVGL_V8具体步骤 LVGL系列2–linux lvglv8 vscode 移植 LVGL系列3–纯物理(外部)按键,数字键盘控制控件 文章目录 LVGL系列一、LVGL移植 一、背景方式一:自定义事件发送与处理函数方式二:利用l…...
FPGA开发——UART回环实现之接收模块的设计
一、简介 因为我们本次进行串口回环的实验的对象是FPGA开发板和PC端,所以在接收和发送模块中先编写接收模块,这样可以在后面更好的进行发送模块的验证。(其实这里先编写哪个模块)都不影响,这里看自己心情,反…...
Debezium系列之:记录一次SQLServer数据库数据不采集,恢复采集造成下游承压的情况,以及相对应的详细解决方案
Debezium系列之:记录一次SQLServer数据库数据不采集,恢复采集造成下游承压的情况,以及相对应的详细解决方案 一、背景二、查看CDC表情况三、 排查数据库是否开启代理四、排查表是否开启CDC五、下游承压情况六、解决方案一、背景 Connector状态正常,但几十台SQLServer数据库…...
Linux线程基础学习记录
0.线程特点 (1).线程共享资源:一个进程下的多个线程共享以下资源 可执行的指令 静态数据 进程中打开的文件描述符 当前工作目录 用户ID 用户组ID (2).线程私有资源: 线程ID PC(程序计数器)和相…...
【Python学习-UI界面】PyQt5 小部件12-QStackedWidget 多页显示
功能和 QTabWidget 类似,它也有助于高效利用窗口的客户区域。 QStackedWidget 提供了一个窗口堆栈,每次只能查看一个窗口。它是建立在 QStackedLayout 之上的一个有用的布局。 样式如下: 右键可以变型为QTabWidget...
Mybatis中好用的元对象反射工具类 - MetaObject
一、前言 在获取map对象或者是其他深层嵌套对象,如果你的做法是挨个取出判空然后继续再向下查找,那么可以看看本文的方案,它或许能让你打开新的思路。 作为一名java开发人员,Mybatis几乎是我们无法避开的ORM框架,如果你…...
javaEE WebServlet、SpringWebMVC、SpringBoot实现跨域访问的4种方式及优先级,nginx配置跨域
文章目录 1. 前置知识2. 原理和解决方案总结2.1. 跨域不通过原理流程图2.2. 实现原理:添加以下http响应头2.3. 四种跨域实现方式及优先级(从高到低) 3. 具体实现代码3.1. 跨域全局配置方式-Filter(全适用)3.2. 跨域全局配置方式-SpringMvc3.3…...
深入理解JavaScript性能优化:从基础到高级
引言 在当今快速发展的Web世界中,性能已经成为衡量应用质量的关键指标。随着Web应用复杂度的不断提升,JavaScript作为前端开发的核心语言,其性能优化变得尤为重要。本文旨在全面深入地探讨JavaScript性能优化的各个方面,从基础概念到高级技巧,帮助开发者构建高效、流畅的Web应用…...
java+springboot实现定时任务
由于是初级程序员,基于注解的形式实现了一个简单的定时任务; 1. 使用Scheduled注解 Spring的Scheduled注解是一种非常简单和便捷的实现定时任务的方式。通过在方法上添加Scheduled注解,我们可以指定方法在特定的时间间隔或固定的时间点执行…...
1.3 数据库的发展历史与演变
欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 工💗重💗hao💗:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题.…...
The field file exceeds its maximum permitted size of 1048576 bytes
场景: 再系统后台上传解析对账文件时大小超过1M就会报错 分析: 排查错误时了解MultipartFile默认上传大小就是1M,但是发现项目配置文件配置了上传大小100M,但是这个大小没有生效 因为项目启动并没有使用到这个配置大小并把他应用到file配置里面,经过测试发现只需要增加配置…...
【Es】python es操作
表 因为es是集群所以es_hosts是列表 from elasticsearch import Elasticsearch ES_HOSTS ["127.0.0.1:9200"] ES_HTTP_AUTH "******************"# 连接Es es Elasticsearch(hostsES_HOSTS ,http_authES_HTTP_AUTH ,maxsize60,timeout30,max_retries3…...
吃透前端文件上传与文件相关操作 多文件上传 大文件切片上传 拖拽上传 后续还会更新 断点续传等等
最近在学文件上传的操作,所以想把学习到东西写成一文章 这片文章是我以小白视角 慢慢学习并熟悉前端文件相关操作的流程总结出来的 前端文件上传 我首先想到是 <input type"file">**选择文件**</input>如果我们想限制上传文件的格式,大小或进行裁剪分片…...
用python制作88键赛博钢琴(能用鼠标键盘进行弹奏)
用python制作88键赛博钢琴 前言 恭喜这位博主终于想起了自己的账号密码! 时光荏苒,转眼间已逾一年未曾在此留下墨香。尽管这一年间,博主投身于无尽的忙碌与挑战之中,但令人欣慰的是,那份初心与热情似乎并未因岁月的流…...
zdpgo_gin_login 框架20240815更新,增加注册路由的功能,一个方法自动拥有注册和登录两个API接口
zdpgo_gin_login 适配gin框架的登录注册功能组件,通过本框架轻松拥有登录注册相关的API接口 特性: 自动生成注册接口,具备密码加密的功能自动生成登录接口,具备JWT Token生成的功能 安装 go get github.com/zhangdapeng520/z…...
搭配Intel第13代酷睿处理器
高性能内存硬盘这么买 intel第13代酷睿已经于2022年10月底正式上市。相比于第12代酷睿性能大涨,内置20条PCle通道(16条PCle 5.0和4条PCle 4.0)、可最多支持128GB DDR5 5600/DDR4 3200双通道内存,搭配Z790系列主板组建高端性能平台,满足未来设计、游戏、专业应用等需求。如…...
uniapp快速回顾,新学websocket连接和BLE连接
Uni APP的学习 官方文档 uni-app官网 (dcloud.net.cn) 任何的博客都不如官方文档 一、快速复习 文件结构 main.js 功能:项目的入口文件,初始化 Vue 实例。 App.vue功能:根组件,包含应用的基本结构和全局样式。 manifest.js…...
激光测距传感器
系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 前言一、产品原理:二、产品介绍:三、应用特点四、应用案例:1.冶金钢铁板卷材开卷工…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
