数值类型
Kotlin 的数值类型表示:
使用数值类型来存储和处理数值数据, 例如算术运算, 计数器, 测量值, 以及其他计算.
选择数值类型
在大多数情况下, 可以参考以下规则, 为你的任务确定正确的数值类型:
对整数使用
Int.对超出
Int范围的整数使用Long.对小数使用
Double.当可以接受或需要较低精度时使用
Float.当 API 或数据格式要求时使用
Byte和Short.
整数类型
Kotlin 提供了 4 种整数类型, 有着不同的大小和数值范围:
类型 | 大小(bits) | 最小值 | 最大值 |
|---|---|---|---|
| 8 | -128 | 127 |
| 16 | -32768 | 32767 |
| 32 | -2,147,483,648 (-231) | 2,147,483,647 (231 - 1) |
| 64 | -9,223,372,036,854,775,808 (-263) | 9,223,372,036,854,775,807 (263 - 1) |
声明整数值
Kotlin 对整数值支持以下字面值(literal)形式:
10 进制数:
12316 进制数:
0x0F2 进制数:
0b00001011
要声明一个数值, 请明确指定类型:
也可以添加 L 后缀, 声明一个 Long 类型的值:
当你明确声明数值类型时, 编译器会检查值是否在该类型的范围内:
当你没有指定数值类型时, 如果值在 Int 范围内, Kotlin 推断类型为 Int. 否则推断类型为 Long:
如果值可以为空, 请使用可为 null 的类型:
浮点类型
对于带小数部分的数值, Kotlin 提供了 Float 和 Double 类型.
浮点类型遵循 IEEE 754 标准. Float 代表 单精度(Single Precision). Double 代表 双精度(Double Precision).
浮点类型的大小和精度有所不同:
类型 | 大小(bits) | 有效位数 | 指数位数 | 十进制位数 |
|---|---|---|---|---|
| 32 | 24 | 8 | 6-7 |
| 64 | 53 | 11 | 15-16 |
声明浮点值
要声明浮点数字面值, 请包含小数点 (.), 或使用指数表示法:
默认情况下, Kotlin 将浮点数字面值推断为 Double. 要声明 Float, 请添加 f 或 F 后缀:
如果值可以为空, 请使用可为 null 的类型:
算术运算
Kotlin 对数值支持标准的算术运算: +, -, *, /, 以及 %.
使用这些运算符来进行常见的计算:
结果类型取决于操作数的类型. 详情请参见 混合数值表达式.
整数除法
整数值之间的除法返回的永远是整数结果. 编译器会舍弃小数部分:
要返回浮点结果, 请将至少一个操作数转换为 Float 或 Double:
类型转换
数值类型互相之间不是子类型(subtype). Kotlin 要求明确的转换, 以免在不知情的情况下丢失数据, 或发生预想之外的行为.
例如, 期望 Double 类型的函数, 如果不进行转换, 不能接受 Int 或 Float 值:
所有的数值类型都支持转换为其他数值类型. 要将数值转换为其他类型, 请使用明确转换的函数:
toByte()toShort()toInt()toLong()toFloat()toDouble()
例如, 以下代码将 Int 值转换为 Double:
将浮点值转换为整数类型时, 编译器会舍弃小数部分:
混合数值表达式
Kotlin 不支持对赋值语句或函数参数进行隐式类型转换. 但是, 你可以在算术表达式中组合不同的数值类型. 在这种情况下, Kotlin 根据操作数类型确定结果类型, 算术运算符会自动处理转换:
如果你尝试将结果赋给较小的类型, 编译器会报告错误:
数据溢出
数值类型只能表示其定义范围内的值.
如果运算结果超出该范围, 就会发生溢出. 如果将值转换为较小的数值类型, 转换后的值可能无法保留原来的数值.
即使编译器允许这样的代码, 这种行为也可能影响你的代码的运行结果.
运算中的溢出
每种整数类型只能存储其定义范围内的值. 当算术运算的结果超过该范围时, 就会发生_数据溢出_:
这里, 结果发生了回绕(wrap around), 因为值超过了 Int 的表达范围.
取反中的溢出
取反操作也可能发生溢出. 例如, Int.MIN_VALUE 的正数对应值, 无法用 Int 表示.
窄化转换
当你将值转换为较小的整数类型时, 结果可能无法保留原来的数值:
但是, 由于浮点类型遵循 IEEE 754 标准, 非常大的结果可能变为 Infinity:
位运算
Kotlin 为 Int 和 Long 提供了 位运算. 这些运算由一组 中缀函数 和 inv() 表示.
位运算包括:
shl()– 带符号左移shr()– 带符号右移ushr()– 无符号右移and()– 按位与(AND)or()– 按位或(OR)xor()– 按位异或(XOR)inv()– 按位取反
浮点值的比较
在 Kotlin 中, 浮点数的比较取决于操作数的静态类型.
当操作数静态的判定为 Float 或 Double 类型时, 对这些数值的操作以及由它们构成的范围, 将遵循 IEEE 754 浮点数值运算标准.
但是, 在使用泛型的情况下 (例如 Any, Comparable<...>, 或 Collection<T>), 对于没有静态的判定为浮点值类型的操作数, 行为有所不同. 在这种情况下, Kotlin 使用 Float 和 Double 的 equals() 和 compareTo() 实现.
因此判定结果是:
NaN会被判定为等于它自己NaN会被判定为大于任何其他数值, 包括正无穷大(POSITIVE_INFINITY)-0.0会被判定为小于0.0
以下示例演示静态的判定为浮点值类型的操作数, 与通过泛型类型使用的操作数之间的差别:
JVM 上数值的装箱(Box)和缓存
在 JVM 平台, 非 null 的数值通常使用基本类型存储, 例如 int, long, 或 double. 但是, 当你使用 泛型, 或可为 null 的数值类型(例如 Int?) 时, 值会被装箱(box), 并以对象的形式表示.
JVM 通过缓存小数值的装箱表示, 使用一种 内存优化技术. 因此, 具有相同值的装箱数值, 可以是 引用相等的.
例如, JVM 缓存了 -128 到 127 范围内的装箱 Integer 值. 因此, 以下代码返回 true:
对于缓存范围之外的值, 装箱值是不同的对象. 在这种情况下, 即使它们的值 结构相等, 它们也不是引用相等的. 因此, 请使用 == 来比较数值: