【Kotlin】上手学习之类型篇

一、类型

1.1 基本类型

主要分为

  • 数字及其无符号版
  • 布尔
  • 字符
  • 字符串
  • 数组

1.1.1 数字

整数类型

Kotlin 提供了一组表示数字的内置类型。 对于整数,有四种不同大小的类型,因此值的范围也不同:

类型大小(比特数)最小值最大值
Byte8-128127
Short16-3276832767
Int32-2,147,483,648 (-2 ^ 31)2,147,483,647 (2 ^ 31 - 1)
Long64-9,223,372,036,854,775,808 (-2 ^ 63)9,223,372,036,854,775,807 (2^ 63 - 1)

当初始化一个没有显式指定类型的变量时,编译器会自动推断为自 Int 起足以表示该值的最小类型。 如果不超过 Int 的表示范围,那么类型是 Int。 如果超过了,那么类型是 Long。 如需显式指定 Long 值,请给该值追加后缀 L。 显式指定类型会触发编译器检测该值是否超出指定类型的表示范围。

val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // Long
val oneByte: Byte = 1

这里与Java不同的是,Java里整型有int和Integer两种写法,前者表示的是基本的数据类型,后者表示的是int对象类型, 但是在kotlin里只有Int这一种。

浮点类型

这两个类型的大小不同,并为两种不同精度的浮点数提供存储:

类型大小(比特数)有效数字比特数指数比特数十进制位数
Float322486-7
Double64531115-16

与一些其他语言不同,Kotlin 中的数字没有隐式拓宽转换

例如,具有 Double 参数的函数只能对 Double 值调用,而不能对 FloatInt 或者其他数字值调用:

在这里插入图片描述

运行之后会报错提示:

/Users/dxm/IdeaProjects/KotlinProject/src/main/kotlin/test/Test.kt:16:22
Kotlin: Argument type mismatch: actual type is 'kotlin.Int', but 'kotlin.Double' was expected./Users/dxm/IdeaProjects/KotlinProject/src/main/kotlin/test/Test.kt:18:22
Kotlin: Argument type mismatch: actual type is 'kotlin.Float', but 'kotlin.Double' was expected.

比如Java运行类似上面那串代码的话,就可以正常运行

public class Hello {public static void main(String[] args) {Hello hello = new Hello();int a = 1;float f = 1.0f;double d = 1.0d;hello.printDouble(a);hello.printDouble(f);hello.printDouble(d);}public void printDouble(double num) {System.out.println(num);}
}

运行之后可以正常输出1.0

在这里插入图片描述

JVM 平台的数字表示

在 JVM 平台数字存储为原生类型 intdouble 等。 例外情况是当创建可空数字引用如 Int? 或者使用泛型时。 在这些场景中,数字会装箱为 Java 类 IntegerDouble 等。

对相同数字的可为空引用可能会引用不同的对象:

fun main() {val a: Int = 100val boxedA: Int? = aval anotherBoxedA: Int? = aval b: Int = 10000val boxedB: Int? = bval anotherBoxedB: Int? = bprintln(boxedA === anotherBoxedA) // trueprintln(boxedB === anotherBoxedB) // false
}

第一个相等,是因为值是在[-128,127]之内,所以取的是Integer里缓存中的,指向的是缓存中同一块内存地址,所以会是同一个对象。

第二个不相等,是因为值是在[-128,127]之外,所以取的不是Integer里缓存中的,而是各自申请的一块内存地址,所以不会是同一个对象。

类似的可以参照下面Java代码运行的结果

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // trueInteger e = 128;
Integer f = 128;
System.out.println(e == f); // falseInteger c = new Integer(128);
Integer d = new Integer(128);
System.out.println(c == d); // false
数据的比较

比较两个Int的变量相等,包含两个方面

  • == 是比较两个值是否相等,类似于Java的equals
  • === 是比较两个变量对象是否相等,类似于Java的==
显式数字转换

由于不同的表示方式,较小类型并不是较大类型的子类型。 如果它们是的话,就会出现下述问题:

// 假想的代码,实际上并不能编译:
val a: Int? = 1 // 一个装箱的 Int (java.lang.Integer)
val b: Long? = a // 隐式转换产生一个装箱的 Long (java.lang.Long)
print(b == a) // 惊!这将输出“false”鉴于 Long 的 equals() 会检测另一个是否也为 Long

因此较小的类型不能隐式转换为较大的类型。 这意味着把Byte型值赋给一个Int变量必须显式转换:

val b: Byte = 1 // OK, 字面值会静态检测
// val i: Int = b // 错误
val i1: Int = b.toInt()

所有数字类型都支持转换为其他类型:

  • toByte(): Byte
  • toShort(): Short
  • toInt(): Int
  • toLong(): Long
  • toFloat(): Float
  • toDouble(): Double

很多情况都不需要显式类型转换,因为类型会从上下文推断出来, 而算术运算会有重载做适当转换,例如:

val l = 1L + 3 // Long + Int => Long

1.1.2 布尔

Boolean 类型表示可以有 truefalse 两个值的布尔对象。

布尔值的内置运算有:

  • ||——(逻辑
  • &&——(逻辑
  • !——(逻辑
fun main() {val myTrue: Boolean = trueval myFalse: Boolean = falseval boolNull: Boolean? = nullprintln(myTrue || myFalse)// trueprintln(myTrue && myFalse)// falseprintln(!myTrue)// falseprintln(boolNull)// null
}

1.1.3 字符

如果字符变量的值是数字,那么可以使用 digitToInt() 函数将其显式转换为 Int 数字。

fun main() {val a : Char = '1'val aDigitToInt = a.digitToInt()println(aDigitToInt) // 1
}

1.1.4 字符串

字符串双引号中的字符序列

val str = "abcd 123"

字符串的元素——字符可以使用索引运算符访问:s[i]。 可以使用for循环遍历这些字符:

fun main() {val str = "abcd"for (c in str) {println(c)}
}

字符串是不可变的。 一旦初始化了一个字符串,就不能改变它的值或者给它赋新值。

字符串模板

模板表达式以美元符($)开头,要么由一个变量名构成:

fun main() {val i = 10println("i = $i") // i = 10val letters = listOf("a","b","c","d","e")println("Letters: $letters") // Letters: [a, b, c, d, e]
}

要么是用花括号括起来的表达式:

fun main() {val s = "abc"println("$s.length is ${s.length}") // abc.length is 3
}

1.1.5 数组

数组是一种保存固定数量相同类型或其子类型的值的数据结构。 Kotlin 中最常见的数组类型是对象类型数组,由Array类表示。

如果在对象类型数组中使用原生类型,那么会对性能产生影响,因为原生值都装箱成了对象。 为了避免装箱开销,请改用原生类型数组。

创建数组

创建数组一般有两种方式:

  • 函数,例如 arrayOf()、arrayOfNulls()) 或 emptyArray()。
  • Array 类的构造函数
函数创建数组
  1. 此示例使用 arrayOf() 函数并将项目值传递给它:
fun main() {// Creates an array with values [1, 2, 3]val simpleArray = arrayOf(1, 2, 3)println(simpleArray.joinToString())// 1, 2, 3
}

joinToString 是 Kotlin 中一个非常有用的扩展函数,通常用于将集合或数组中的元素连接成一个字符串。它可以接收多个参数来定制输出字符串的格式。这个函数的作用是将集合中的每个元素按照给定的分隔符连接成一个字符串,可以指定前缀、后缀、分隔符以及如何转换元素。

  1. 此示例使用 arrayOfNulls()) 函数创建一个给定大小的数组,其中填充 null 元素:
fun main() {// Creates an array with values [null, null, null]val nullArray: Array<Int?> = arrayOfNulls(3)println(nullArray.joinToString())// null, null, null
}
  1. 此示例使用emptyArray()函数创建一个空数组:
    var exampleArray = emptyArray<String>()
Array构造函数创建数组

Array 构造函数采用数组大小和一个函数,该函数根据给定索引返回数组元素的值:

fun main() {// Creates an Array<Int> that initializes with zeros [0, 0, 0]val initArray = Array<Int>(3) { 0 }println(initArray.joinToString())// 0, 0, 0// 创建一个 Array<String> 初始化为 ["0", "1", "4", "9", "16"]val asc = Array(5) { i -> (i * i).toString() }asc.forEach { print(it) }// 014916
}
嵌套数组

数组可以相互嵌套以创建多维数组:

fun main() {// Creates a two-dimensional arrayval twoDArray = Array(2) { Array<Int>(2) { 0 } }println(twoDArray.contentDeepToString())// [[0, 0], [0, 0]]// Creates a three-dimensional arrayval threeDArray = Array(3) { Array(3) { Array<Int>(3) { 0 } } }println(threeDArray.contentDeepToString())// [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]
}
数组求和
fun main() {val sumArray = arrayOf(1, 2, 3)// Sums array elementsprintln(sumArray.sum())// 6
}
将数组转换为集合
转换为 List 或 Set

要将数组转换为 List 或 Set,请使用 .toList() 和 .toSet() 函数。

fun main() {val simpleArray = arrayOf("a", "b", "c", "c")// Converts to a Setprintln(simpleArray.toSet())// [a, b, c]// Converts to a Listprintln(simpleArray.toList())// [a, b, c, c]}
转换为 Map
fun main() {val pairArray = arrayOf("apple" to 120, "banana" to 150, "cherry" to 90, "apple" to 140)// Converts to a Map// The keys are fruits and the values are their number of calories// Note how keys must be unique, so the latest value of "apple"// overwrites the firstprintln(pairArray.toMap())// {apple=140, banana=150, cherry=90}}
原生类型数组

如果将 Array 类与原始值一起使用,这些值将被装箱到对象中。作为替代方案,您可以使用基元类型数组,它允许您将基元存储在数组中,而不会产生装箱开销的副作用:

Primitive-type arrayEquivalent in Java
BooleanArrayboolean[]
ByteArraybyte[]
CharArraychar[]
DoubleArraydouble[]
FloatArrayfloat[]
IntArrayint[]
LongArraylong[]
ShortArrayshort[]

这些类与 Array 类没有继承关系,但它们具有相同的函数和属性集。

下面示例创建 IntArray 类的实例:

fun main() {// Creates an array of Int of size 5 with the values initialized to zeroval exampleArray = IntArray(5)println(exampleArray.joinToString())// 0, 0, 0, 0, 0
}
  • 要将原始类型数组转换为对象类型数组,请使用 .toTypedArray() 函数。
  • 要将对象类型数组转换为原始类型数组,请使用 .toBooleanArray()、.toByteArray()、.toCharArray() 等。

1.1.6 无符号整型

除了整数类型,对于无符号整数,Kotlin 还提供了以下类型:

TypeSize (bits)Min valueMax value
UByte80255
UShort16065,535
UInt3204,294,967,295 (2 ^ 32 - 1)
ULong64018,446,744,073,709,551,615 (2 ^ 64 - 1)

1.2 类型检测与类型转换

在 Kotlin 中,可以执行类型检查以在运行时检查对象的类型。类型转换将对象转换为不同的类型。

1.2.1 is 与 !is 操作符

使用 is 操作符或其否定形式 !is 在运行时检测对象是否符合给定类型:

if (obj is String) {print(obj.length)
}if (obj !is String) { // 与 !(obj is String) 相同print("Not a String")
} else {print(obj.length)
}

这个类似于Java的instanceof关键字

1.2.2 智能转换

大多数场景都不需要在 Kotlin 中使用显式转换操作符,因为编译器跟踪不可变值的is-检测以及显式转换,并在必要时自动插入(安全的)转换:

fun demo(x: Any) {if (x is String) {print(x.length) // x 自动转换为字符串}
}

编译器足够聪明,能够知道如果反向检测导致返回那么该转换是安全的:

if (x !is String) returnprint(x.length) // x 自动转换为字符串

或者转换在 &&|| 的右侧,而相应的(正常或否定)检测在左侧:

// `||` 右侧的 x 自动转换为 String
if (x !is String || x.length == 0) return// `&&` 右侧的 x 自动转换为 String
if (x is String && x.length > 0) {print(x.length) // x 自动转换为 String
}

智能转换用于when表达式和while循环也一样:

when (x) {is Int -> print(x + 1)is String -> print(x.length + 1)is IntArray -> print(x.sum())
}

智能转换适用于以下情形:

val 局部变量总是可以,局部委托属性除外。
val 属性如果属性是 privateinternal,或者该检测在声明属性的同一模块中执行。 智能转换不能用于 open 的属性或者具有自定义 getter 的属性。
var 局部变量如果变量在检测及其使用之间未修改、没有在会修改它的 lambda 中捕获、并且不是局部委托属性。
var 属性决不可能,因为该变量可以随时被其他代码修改。

1.2.3 “不安全的”转换操作符

通常,如果转换是不可能的,转换操作符会抛出一个异常。因此,称为不安全的。 Kotlin 中的不安全转换使用中缀操作符 as

val x: String = y as String

请注意,null不能转换为String因该类型不是可空的。 如果y为空,上面的代码会抛出一个异常。 为了让这样的代码用于可空值,请在类型转换的右侧使用可空类型:

val x: String? = y as String?

1.2.4 “安全的”(可空)转换操作符

为了避免异常,可以使用安全转换操作符as?,它可以在失败时返回null

val x: String? = y as? String

请注意,尽管事实上as?的右边是一个非空类型的String,但是其转换的结果是可空的。

比如下面这段代码

fun main() {val x = IntArray(5)val str: String = x as Stringprintln("str is $str")
}

运行之后会抛出异常

Exception in thread "main" java.lang.ClassCastException: class [I cannot be cast to class java.lang.String ([I and java.lang.String are in module java.base of loader 'bootstrap')

如果换成可空的话

fun main() {val x = IntArray(5)val str: String? = x as? Stringprintln("str is $str")
}

至少是可以正常执行的,运行结果是

str is null

所以我们平时如果写代码的时候,如果为了防止异常的话,在类型转换的时候尽量用这种可空的。如果业务中必须要转换过来的类型的话,那就不用可空的。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 高版本如何获取App安装列表?

有个需求需要获取App内的安装列表,但是现在在高版本Android中,只能获取到一部分App效果,我获取的代码如下: val calendar Calendar.getInstance()val packageManager context.packageManagerval usageStatsManager context.getSystemService(Context.USAGE_STATS_SERVICE) …

BIO、NIO、AIO

第一章 BIO、NIO、AIO课程介绍 1.1 课程说明 ​ 在Java的软件设计开发中,通信架构是不可避免的,我们在进行不同系统或者不同进程之间的数据交互,或者在高并发下的通信场景下都需要用到网络通信相关的技术,对于一些经验丰富的程序员来说,Java早期的网络通信架构存在一些缺…

VUE学习笔记4__安装开发者工具

https://chrome.zzzmh.cn/index 安装后需要关闭所有浏览器并重启 再次打开检查会看到vue标签&#xff0c;方便调试修改 如果安装后找不到vue标签&#xff0c;请尝试下载历史版本&#xff0c;这里用的是6.4.5 <!doctype html> <html lang"en"> <head&…

GitLab集成Jira

GitLab与Jira集成的两种方式 GitLab 提供了两种 Jira 集成&#xff0c;即Jira议题集成和Jira开发面板集成&#xff0c;可以配置一个或者两个都配置。 具体集成步骤可以参考官方文档Jira 议题集成&#xff08;极狐GitLab文档&#xff09;和Jira 开发面板集成&#xff08;极狐G…

深入理解计算机系统阅读笔记-第十二章

第12章 网络编程 12.1 客户端-服务器编程模型 每个网络应用都是基于客户端-服务器模型的。根据这个模型&#xff0c;一个应用时由一个服务器进程和一个或者多个客户端进程组成。服务器管理某种资源&#xff0c;并且通过操作这种资源来为它的客户端提供某种服务。例如&#xf…

用css和html制作太极图

目录 css相关参数介绍 边距 边框 伪元素选择器 太极图案例实现、 代码 效果 css相关参数介绍 边距 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>*{margin: 0;padding: 0;}div{width: …

C++算法第十六天

本篇文章我们继续学习动态规划 第一题 题目链接 978. 最长湍流子数组 - 力扣&#xff08;LeetCode&#xff09; 题目解析 从上图可见其实有三个状态 代码原理 注意&#xff1a;我们在分析题目的时候分析出来的是三个状态&#xff0c;分别是上升、下降、平坦&#xff0c;但是…

基于YOLOv8与CGNet的鸟类智能识别系统 深度学习图像分类 鸟类目标检测与分类 图像特征提取 模型优化与应用 数据可视化(源码+指导+定制)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

qml LevelAdjust详解

1、概述 LevelAdjust 是 QML&#xff08;Qt Modeling Language&#xff09;中的一个类型&#xff0c;用于调整源组件的每个色彩通道的颜色级别。通过 LevelAdjust&#xff0c;可以实现对源项目对比度的调节和色彩平衡的改变。LevelAdjust 类型继承自 Item&#xff0c;并提供了…

springMVC实现文件上传

目录 一、创建项目 二、引入依赖 三、web.xml 四、编写上传文件的jsp页面 五、spring-mvc.xml 六、controller 七、运行 一、创建项目 二、引入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.o…

opencv进行人脸识别环境搭建

1. 构建人脸识别环境 1) 下载安装opencv 下载地址&#xff1a;Releases - OpenCV 参考博文&#xff1a;OpenCV下载安装教程&#xff08;Windows&#xff09;-CSDN博客 下载对应系统的opencv&#xff0c;如windows版&#xff0c;opencv-4.5.5-vc14_vc15.exe 2) 然后解压缩到…

[SAP ABAP] 批量导入(BDC)练习案例

业务目的&#xff1a;对采购订单做批量修改&#xff0c;同时需要用报表显示导入结果&#xff0c;Excel上传凭证后&#xff0c;录制BDC&#xff0c;调用BDC对采购订单进行修改 批量修改以下3个采购订单的短文本以及采购订单数量 提示Tips&#xff1a;上述提供的3个采购订单涉及…

《自动驾驶与机器人中的SLAM技术》ch4:预积分学

目录 1 预积分的定义 2 预积分的测量模型 ( 预积分的测量值可由 IMU 的测量值积分得到 ) 2.1 旋转部分 2.2 速度部分 2.3 平移部分 2.4 将预积分测量和误差式代回最初的定义式 3 预积分的噪声模型和协方差矩阵 3.1 旋转部分 3.2 速度部分 3.3 平移部分 3.4 噪声项合并 4 零偏的…

2Spark Core

2Spark Core 1.RDD 详解1) 为什么要有 RDD?2) RDD 是什么?3) RDD 主要属性 2.RDD-API1) RDD 的创建方式2) RDD 的算子分类3) Transformation 转换算子4) Action 动作算子 3. RDD 的持久化/缓存4. RDD 容错机制 Checkpoint5. RDD 依赖关系1) 宽窄依赖2) 为什么要设计宽窄依赖 …

归子莫的科技周刊#2:白天搬砖,夜里读诗

归子莫的科技周刊#2&#xff1a;白天搬砖&#xff0c;夜里读诗 本周刊开源&#xff0c;欢迎投稿。 刊期&#xff1a;2025.1.5 - 2025.1.11。原文地址。 封面图 下班在深圳看到的夕阳&#xff0c;能遇到是一种偶然的机会&#xff0c;能拍下更是一种幸运。 白天搬砖&#xff0c;…

机器学习第一道菜(一):线性回归的理论模型

机器学习第一道菜&#xff08;一&#xff09;&#xff1a;线性回归的理论模型 一、问题&#xff1a;千金买笑1.1 散点图1.2 机器学习能搞啥 二、模型的建立2.1 线性回归2.2 回归模型 前面讲了机器学习的“四大绝技”&#xff0c;今天&#xff0c;开始研究第一绝技“回归”&…

http转化为https生成自签名证书

背景 项目开发阶段前后交互采用http协议&#xff0c;演示环境采用htttps协议 &#xff0c;此处为个人demo案例 组件 后端&#xff1a;springBoot 前端&#xff1a;vue web 服务&#xff1a;tomcat 部署环境&#xff1a;linux 生成自签名证书 创建目录 存储证书位置 # mkdir -p…

【安卓开发】【Android】总结:安卓技能树

【持续更新】 对笔者在安卓开发的实践中认为必要的知识点和遇到的问题进行总结。 一、基础知识部分 1、Android Studio软件使用 软件界面 最新的版本是瓢虫&#xff08;Ladybug&#xff09;&#xff0c;bug的确挺多。笔者更习惯使用电鳗&#xff08;Electric Eel&#xff0…

PT8M2302 触控 A/D 型 8-Bit MCU

1. 产品概述 PT8M2302 是一款可多次编程&#xff08; MTP &#xff09; A/D 型 8 位 MCU &#xff0c;其包括 2K*16bit MTP ROM 、 256*8bit SRAM、 ADC 、 PWM 、 Touch 等功能&#xff0c;具有高性能精简指令集、低工作电压、低功耗特性且完全集 成触控按键功能。为…

HunyuanVideo 文生视频模型实践

HunyuanVideo 文生视频模型实践 flyfish 运行 HunyuanVideo 模型使用文本生成视频的推荐配置&#xff08;batch size 1&#xff09;&#xff1a; 模型分辨率(height/width/frame)峰值显存HunyuanVideo720px1280px129f60GHunyuanVideo544px960px129f45G 本项目适用于使用 N…