Android 之 kotlin 语言学习笔记一
参考官方文档:https://developer.android.google.cn/kotlin/learn?hl=zh-cn
1、变量声明
Kotlin 使用两个不同的关键字(即 val 和 var)来声明变量。
- val 用于值从不更改的变量。使用 val 声明的变量无法重新赋值。
- var 用于值可以更改的变量。
// 可变变量var count: Int = 10count = 15// 不可变变量val name = "kotlin"name = "java" // 报错
2、类型推断
- Kotlin 是一种静态类型的语言。类型将在编译时解析且从不改变。
val languageName= "kotlin"val upperCaseName = languageName.toUpperCase()// Fails to compilelanguageName.inc()
- toUpperCase() 是一个只能对 String 类型的变量调用的函数。由于 Kotlin 编译器已将 languageName 推断为 String,因此可以安全地调用 toUpperCase()。不过,inc() 是一个 Int 运算符函数,因此无法对 String 调用它。利用 Kotlin 的类型推断,既能确保代码简洁,又能确保类型安全。
3、Null 安全
- Kotlin 提供了严格的可为 null 性规则,可在您的整个应用中维护类型安全。在 Kotlin 中,默认情况下,对对象的引用不能包含 null 值。如需为变量赋 null 值,必须通过将变量类型以问号 ? 为后缀,声明变量为可 null 的类型。
// name 的类型为 String,不可为 null,会编译错误val name: String = null// 若要赋 null 值,需加 ? 符号val name: String? = null
4、非 null 断言运算符 !!
5、条件语句
- Kotlin 提供了几种实现条件逻辑的机制,其中最常见的是 if-else 语句。如果 if 关键字后面括在圆括号内的表达式求值为 true,则会执行该分支中的代码(即,紧跟在后面的括在大括号内的代码)。否则,会执行 else 分支中的代码。
if (count == 42) {println("I have the answer.")} else {println("The answer eludes me.")}
- 您可以使用 else if 表示多个条件。这样,您就可以在单个条件语句中表示更精细、更复杂的逻辑。
if (count == 42) {println("I have the answer.")} else if (count > 35) {println("The answer is close.")} else {println("The answer eludes me.")}
- 为了避免重复代码,Kotlin 提供了条件表达式。每个条件分支都隐式地返回其最后一行的表达式的结果,因此无需使用 return 关键字
val answerString: String = if (count == 42) {"I have the answer."} else if (count > 35) {"The answer is close."} else {"The answer eludes me."}println(answerString)
- 随着条件语句的复杂性不断增加,您可以考虑将 if-else 表达式替换为 when 表达式。when 表达式中每个分支都由一个条件、一个箭头 (->) 和一个结果来表示。如果箭头左侧的条件求值为 true,则会返回右侧的表达式结果。
val answerString = when {count == 42 -> "I have the answer."count > 35 -> "The answer is close."else -> "The answer eludes me."}
- Kotlin 的条件语句有一项强大的功能,即智能类型转换。您不必使用安全调用运算符或非 null 断言运算符来处理可为 null 的值,而可以使用条件语句来检查变量是否包含对 null 值的引用。
val languageName: String? = nullif (languageName != null) {// No need to write languageName?.toUpperCase()println(languageName.toUpperCase())}
6、函数
- 使用 fun 关键字声明函数,后跟函数名称,接着在括号内定义函数的输入类型(如果有),最后使用冒号(:)跟着返回值的类型。在声明函数时,可以指定任意数量的参数及其类型。
fun getName(type: Int): String {// 函数体内容}
(1)简化函数声明
- 函数返回单个表达式的结果时,可以通过直接返回函数中包含的 if-else 表达式的结果来跳过声明局部变量。
fun generateAnswerString(countThreshold: Int): String {return if (count > countThreshold) {"I have the answer."} else {"The answer eludes me."}}
- 还可以将 return 关键字替换为赋值运算符。
fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {"I have the answer"} else {"The answer eludes me"}
(2)匿名函数
- 并非每个函数都需要一个名称。某些函数通过输入和输出更直接地进行标识。这些函数称为“匿名函数”。可以保留对某个匿名函数的引用,以便日后使用此引用来调用该匿名函数。与其他引用类型一样,也可以在应用中传递引用。必须像调用命名函数一样调用该函数。
val stringLengthFunc: (String) -> Int = { input ->input.length}val stringLength: Int = stringLengthFunc("Android")
(3)高阶函数
- 一个函数可以将另一个函数当作参数。将其他函数用作参数的函数称为“高阶函数”。此模式对组件之间的通信(其方式与在 Java 中使用回调接口相同)很有用。
fun stringMapper(str: String, mapper: (String) -> Int): Int {// Invoke functionreturn mapper(str)}
- 如果匿名函数是在某个函数上定义的最后一个参数,则可以在用于调用该函数的圆括号之外传递它。
stringMapper("Android") { input ->input.length}
7、类
使用 class 关键字可以定义类。
(1)属性
- 类使用属性来表示状态。属性是类级变量,可以包含 getter、setter 和后备字段。
class Car {val wheels = listOf<Wheel>()}
- 调用类默认构造函数可以获取类的实例,通过实例可以访问它的任何可访问属性。
val car = Car() // construct a Carval wheels = car.wheels // retrieve the wheels value from the Car
- 可以定义一个自定义构造函数,用来指定如何初始化类属性。
class Car(val wheels: List<Wheel>)
(2)类函数和封装
- 类使用函数对行为建模。函数可以修改状态,从而实现只公开希望公开的数据。这种访问控制机制称为“封装”。
class Car(val wheels: List<Wheel>) {private val doorLock: DoorLock = ...fun unlockDoor(key: Key): Boolean {// Return true if key is valid for door lock, false otherwise}}
- 如果希望自定义属性的引用方式,则可以提供自定义的 getter 和 setter。例如,如果希望公开属性的 getter 而限制访问其 setter,则可以将该 setter 指定为 private:
class Car(val wheels: List<Wheel>) {private val doorLock: DoorLock = ...var gallonsOfFuelInTank: Int = 15private setfun unlockDoor(key: Key): Boolean {// Return true if key is valid for door lock, false otherwise}}
8、互操作性
- Kotlin 最重要的功能之一就是它与 Java 之间流畅的互操作性。由于 Kotlin 代码可编译为 JVM 字节码,因此 Kotlin 代码可直接调用 Java 代码,反之亦然。这意味着,可以直接从 Kotlin 利用现有的 Java 库。此外,绝大多数 Android API 都是用 Java 编写的,因此可以直接从 Kotlin 调用它们。
- 可为 null 性是 Java 和 Kotlin 在行为上有所不同的一个主要方面。Java 对可为 null 性语法的要求不那么严格。Kotlin 制定了与可为 null 性有关的规则,Java 没有制定这样的规则,而是依赖于可选的可为 null 性注释明确声明您是否可以赋予 null 值。
private final @Nullable String accessId;public final @NonNull String name;public final String loginName;
- 如果使用 Kotlin 引用在 Java 中定义的不带注释的 loginName 成员,编译器将不知道 String 映射到 Kotlin 中的 String 还是 String?。这种不明确性通过平台类型 String! 表示。
- String! 对 Kotlin 编译器而言没有特殊的含义。String! 可以表示 String 或 String?,编译器可让您赋予任一类型的值。请注意,如果您将类型表示为 String 并赋予 null 值,则系统可能会抛出 NullPointerException。
- 为了解决此问题,每当您用 Java 编写代码时,都应使用可为 null 性注释。这些注释对 Java 和 Kotlin 开发者都有帮助。
- 可为 null 性注释包含在所有新增的 Android API 以及许多现有的 Android API 中。许多 Java 库已添加可为 null 性注释,以便为 Kotlin 和 Java 开发者提供更好的支持。
9、伴生对象(Companion Object)
- 伴生对象(Companion Object) 是一种特殊的对象,它与类相关联,但不属于类的某个具体实例。伴生对象类似于 Java 中的静态成员。
- 伴生对象是通过在类内部使用 companion object 关键字定义的。它允许你在类内部定义一些静态方法或属性,这些方法和属性可以通过类名直接访问,而不需要创建类的实例。
- 伴生对象的成员在编译后会被转换为 Java 的静态成员,因此在 Java 代码中可以直接访问它们。
- 伴生对象常用于实现工厂模式,提供类的创建方法。
class LoginFragment : Fragment() {...companion object {private const val TAG = "LoginFragment"}}
10、属性委托
- 初始化属性时,您可能会重复 Android 的一些比较常见的模式,例如在 Fragment 中访问 ViewModel。为避免过多的重复代码,您可以使用 Kotlin 的属性委托语法。
- 属性委托提供了一种可在您的整个应用中重复使用的通用实现。Android KTX 提供了一些属性委托。例如,viewModels 可检索范围限定为当前 Fragment 的 ViewModel。
- 属性委托使用反射,这样会增加一些性能开销。这种代价换来的是简洁的语法,可让您节省开发时间。
private val viewModel: LoginViewModel by viewModels()
相关文章:
Android 之 kotlin 语言学习笔记一
参考官方文档:https://developer.android.google.cn/kotlin/learn?hlzh-cn 1、变量声明 Kotlin 使用两个不同的关键字(即 val 和 var)来声明变量。 val 用于值从不更改的变量。使用 val 声明的变量无法重新赋值。var 用于值可以更改的变量…...

maven模块化开发
使用方法 将项目安装到本地仓库 mvn install 的作用 运行 mvn install 时,Maven 会执行项目的整个构建生命周期(包括 compile、test、package 等阶段),最终将构建的 artifact 安装到本地仓库(默认路径为 ~/.m2/repos…...
为什么要使用stream流
总的来说就是 它支持链式调用,方便 不会修改原始数据源,而是生成一个新的流或结果 中间操作不会立即执行,只有在终端操作触发时才会真正执行 注意事项 无状态操作:Stream 操作应该是无状态的,不要依赖外部变量的状…...
语义分割的image
假设图像的尺寸为 3x3,并且是 RGB 图像(有 3 个通道)。每个通道的像素值范围为 [0, 1],我们将构造一个 batch_size 2 的图像批次。 Image: tensor([[[[0.1347, 0.4583, 0.7102], # 第一张图像的红色通道[0.1774, 0.0328, 0.308…...

云原生安全之网络IP协议:从基础到实践指南
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 IP协议(Internet Protocol)是互联网通信的核心协议族之一,负责在设备间传递数据包。其核心特性包括&…...

C++——QT 文件操作类
QFile 概述 QFile是Qt框架中用于文件操作的类(位于QtCore模块),继承自 QIODevice,提供文件的读写、状态查询和路径管理功能。它与 QTextStream、QDataStream 配合使用,可简化文本和二进制数据的处理,并具备…...
【排错】kylinLinx环境python读json文件报错UTF-8 BOM
kylin Linux环境python读json文件报错UTF-8 BOM 报错描述: windows环境下,python代码读取json文件正常,但是sftp到linux环境下 报错信息: json.decoder.JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column …...

[spring] spring 框架、IOC和AOP思想
目录 传统Javaweb开发的困惑 loC、DI和AOP思想提出 Spring框架的诞生 传统Javaweb开发的困惑 问题一:层与层之间紧密耦合在了一起,接口与具体实现紧密耦合在了一起 解决思路:程序代码中不要手动new对象,第三方根据要求为程序提…...
LInux—shell编程
一、Shell 编程核心特性 解释型语言 无需编译,直接由 bash、sh 等解释器逐行执行。 类似 PHP 的解释执行,不同于 C 的编译型。 系统命令集成 可直接调用 Linux 命令(如 ls、grep、awk),实现系统管理自动化。 与 C/…...

尚硅谷redis7 37-39 redis持久化之AOF简介
37 redis持久化之AOF简介 AOF 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工…...

GitLab 备份所有仓库(自动克隆)
一、准备工作 1. 环境要求 已安装 Git(版本 2.10)本地磁盘空间充足(根据仓库总大小预估)已配置 SSH 密钥到 GitLab(推荐方式) 2. 获取 GitLab API 访问权限 登录 GitLab,点击右上角头像 → …...

[浏览器]缓存策略机制详解
在做页面性能优化的时候,有一个点容易被忽略,那就是资源缓存优化。 浏览器里缓存策略分为强缓存,协商缓存以及不缓存,每个缓存策略都有其适用的优化场景。 下面为大家详解何为强缓存,协商缓存 先说结论强缓>协商&g…...
Vue修饰符全解析
目录 一、事件修饰符 二、按键修饰符 三、系统修饰键 四、表单修饰符 五、鼠标修饰符 六、特殊修饰符 七、自定义修饰符 使用建议 一、事件修饰符 <!-- 阻止冒泡 --> <button click.stop"handleClick">点击测试</button><!-- 阻止默认行…...

OpenCV CUDA 模块图像过滤-----创建一个计算图像导数的滤波器函数createDerivFilter()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::cuda::createDerivFilter 是 OpenCV CUDA 模块中的一个工厂函数,用于创建一个计算图像导数的滤波器。这个滤波器可以用来计算图像…...
计算机视觉与深度学习 | Python实现CEEMDAN-ABC-VMD-DBO-CNN-LSTM时间序列预测(完整源码和数据)
以下是一个结合CEEMDAN、ABC优化VMD、DBO优化CNN-LSTM的完整时间序列预测实现方案。该方案包含完整的数据生成、算法实现和模型构建代码。 完整实现代码 import numpy as np import pandas as pd from PyEMD import CEEMDAN from vmdpy import VMD from sklearn.preprocessing…...

AWS関連職種向け:日本語面接QA集
1. 自己紹介(じこしょうかい) Q:簡単に自己紹介をお願いします。 A: はい、〇〇と申します。これまで約4年間、主にAWSを基盤としたインフラ設計・構築・運用に従事してまいりました。VPCやEC2、RDS、S3などの基本サービスの設計…...
【Macos】安装前端环境rust+node环境
Macos 安装前端环境 1、findar 新建目录 projects 2、安装brew 使用中科大镜像, 手动配置path 3、brew install git 4、 git clone githttp://10.10.9.201/software/dreame_sorting_app.git 5、安装vscode/hbuilderx/node 6、rustup切换镜像并安装https://rsproxy.cn/#getStart…...

(01)华为GaussDB((基于PostgreSQL))高斯数据库使用记录,dbeaver客户端配置高斯驱动,连接高斯数据库
高斯数据库是华为推出的一款基于PostgreSQL的企业级数据库产品,客户端使用通用的dbeaver dbeaver客户端配置高斯驱动 建议使用 dbeaver24.3.1及以上客户端,选择模式后执行sql会绑定模式名,如果使用dbeaver23.2版本,选择模式后执…...

ARM Linux远程调试
准备 虚拟机既能ping通开发板,又能ping通外网,还要能ping通Windows主机(如果你有上位机通信(tftp、vsftp、ssh)的需求) VMware 添加网络适配器2用作桥接网卡,原有的网络适配器保持为NAT模式 打开虚拟网络编辑器,配置VMnet0为桥接模式,外部连接设置为Realtek PCIe G…...

day24Node-node的Web框架Express
1. Express 基础 1.1 什么是Express node的web框架有Express 和 Koa。常用Express 。 Express 是一个基于 Node.js 的快速、极简的 Web 应用框架,用于构建 服务器端应用(如网站后端、RESTful API 等)。它是 Node.js 生态中最流行的框架之一,以轻量、灵活和易用著称。 …...
Webpack和Vite构建工具有什么区别?各自的优缺点是什么
Webpack 和 Vite 是两种主流的前端构建工具,分别代表了不同的设计理念和技术路线。以下是它们的核心区别和优缺点对比: 一、核心区别 维度WebpackVite设计理念基于打包(Bundle-Based)基于原生 ESM(Native ESM)开发模式全量打包后启动按需编译 + 浏览器直接加载 ESM构建工…...

让MySQL更快:EXPLAIN语句详尽解析
前言 在数据库性能调优中,SQL 查询的执行效率是影响系统整体性能的关键因素之一。MySQL 提供了强大的工具——EXPLAIN 语句,帮助开发者和数据库管理员深入分析查询的执行计划,从而发现潜在的性能瓶颈并进行针对性优化。 EXPLAIN 语句能够模…...
基于谷歌浏览器的Web Crypto API生成一对2048位的RSA密钥(公钥+私钥),并以JSON格式(JWK)打印到浏览器控制台
用Google Chrome 浏览器的Web Crypto API生成RSA密钥对:在浏览器环境中生成一对2048位的RSA密钥(公钥私钥),然后以JSON格式(JWK)将它们打印到控制台,方便开发者查看和使用。 // 控制台生成密钥对 (async () > {// 调用Web Crypto API生成…...

[CSS3]rem移动适配
前言 什么是移动端适配? 让页面的元素在屏幕尺寸变化时, 同比放大或缩小 移动适配的方案 rem:目前多数企业在用的解决方案 vw/vh:未来的解决方案 rem 体验rem适配 目标: 能够使用rem单位设置网页元素的尺寸 网页效果: 屏幕宽度不同,网…...

向量数据库及ChromaDB的使用
什么是向量数据库? 向量数据库(Vector Database),也叫矢量数据库,主要用来存储和处理向量数据。 在数学中,向量是有大小和方向的量,可以使用带箭头的线段表示,箭头指向即为向量的方…...

CodeBuddy实现pdf批量加密
本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前言 在信息爆炸的时代,PDF 格式因其跨平台性和格式稳定性,成为办公、学术、商业等领域传递信息的重要载体。从机密合同到个人隐私文档,…...
编程中优秀大模型推荐:特点与应用场景深度分析
编程中优秀大模型推荐:特点与应用场景深度分析 编程中优秀大模型推荐:特点与应用场景深度分析GPT系列模型模型概述技术特点编程应用场景 DeepSeek系列模型模型概述技术特点编程应用场景 Claude系列模型模型概述技术特点编程应用场景 Llama系列模型模型概…...
orm详解--查询执行
深入解析 Django ORM 查询执行阶段 的核心机制,包括查询集的惰性特性、表达式树构建、SQL 编译过程及优化原理。以下是详细分析: 一、查询集(QuerySet)的惰性执行机制 1. 惰性特性的底层实现 核心类:django.db.mode…...

运行打印Hello World启动了多少线程?
序言 看网上说阿里二面问到了一个看似最简单且没有标准答案的一个问题,所有学习编程都是从打印hello World开始的,那运行打印启动了多少个线程? 启动了多少线程? 在运行一个简单的 “Hello World” 程序时,启动的线…...
C++项目中调用C#DLL的的方式
C项目中调用C#DLL的的方式 方法一:使用COM技术方法二:使用C/CLI方法三:使用P/Invoke(适用于C#导出非托管接口) 在C中调用C#编写的DLL,通常需要借助COM(Component Object Model&#…...