Kotlin笔记(基本类型)
在 Kotlin 中,一切都是对象,因此我们可以在任何变量上调用对象的成员函数和属性。一些类型可以有特殊的内部表示——例如,数字、字符和布尔值可以在运行时表示为原始值,但对用户来说,它们看起来像普通的类。为什么这些类型会在运行时被表示为原始类型呢? 因为用引用类型去代替基本数据类型效率是很低。 在本节中,我们将描述 Kotlin 中使用的基本类型:数字、布尔值、字符、字符串和数组。 Numbers(包括整数类型和浮点类型)
整数类型(包括Byte、Short、Int、Long)
Kotlin 提供了一组表示数字的内置类型。对于整数,有四种不同大小的类型,因此也有不同的取值范围。
类型
大小(位)
最小值
最大值
Byte
8
-128
127
Short
16
-32768
32767
Int
32
-2,147,483,648 ()
2,147,483,647 ()
Long
64 -9,223,372,036,854,775,808
() 9,223,372,036,854,775,807
()
在使用整数类型初始化变量的时候,如果初始值不超过Int类型最大值,那么所有变量都具有推断类型Int。如果初始值超过此值,则推断类型为Long。要显式指定Long值,请将后缀附加L到值。 val one = 1 // Int(字面常量在Int范围内,变量的类型推断为Int) val threeBillion = 3000000000 // Long(字面常量超过了Int范围,推断类型为Long) val oneLong = 1L // Long(字面常量显式指定了类型为Long) val oneByte: Byte = 1(变量类型直接指定为Byte类型)
浮点类型(包括Float、Double)
对于实数,Kotlin 提供浮点类型Float和Double. 根据 IEEE 754 标准,浮点类型的 区别在于它们的小数位 不同,即它们可以存储多少位小数。
Type
Size (bits)
Significant bits
Exponent bits
Decimal digits
Float
32
24
8
6-7
Double
64
53
11
15-16
您可以使用具有小数部分的数字来初始化Float和Double变量。对于用小数初始化的变量,编译器会推断Double类型。 val oneDouble = 1.0 // Double // val one: Double = 1 // Error: type mismatch(声明了是Double类型,但是字面常量是整数类型)
要显式给Float类型的变量指定值,需要给初始值添加后缀f或F。如果初始值包含超过 6-7 位小数位数,它将被四舍五入。 val e = 2.7182818284 // Double val eFloat = 2.7182818284f // Float, actual value is 2.7182817 // val oneFloat: Float = 2.7182818284// Error: type mismatch(变量是float,但是字面常量是double) // val oneDouble :Double = 2.7182818284f // Error: type mismatch(变量是Double,但是字面常量是float)
字面常量
整数值有以下几种字面常量: 十进制:123( Long 类型 写 L 标记: 123 ) 十六进制:0x0F 二进制文件:0b00001011 注意: 不支持八进制
浮点值有以下几种字面常量 : 默认是Double类型:123.5,123.5e10 Float类型由f或F标记:123.5f
可以使用下划线使数字常量更具可读性: val oneMillion = 1_000_000 val creditCardNumber = 1234_5678_9012_3456L val socialSecurityNumber = 999_99_9999L val hexBytes = 0xFF_EC_DE_5E val bytes = 0b11010010_01101001_10010100_10010010
显式转换
由于表示方式不同,较小的类型 不是 较大类型的子类型。如果是这样,我们将遇到以下问题: // 假设的代码,实际上不能编译: 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, literals are checked statically // val i: Int = b // ERROR val i1: Int = b.toInt()
所有数字类型都支持转换为其他类型: toByte(): Byte toShort(): Short toInt(): Int toLong(): Long toFloat(): Float toDouble(): Double toChar(): Char
有些情况下也是可以使用自动类型转化的,前提是可以根据上下文环境推断出正确的数据类型而且数学操作符会做相应的重载。例如下面是正确的: val l = 1L + 3 // Long + Int => Long
运算
Kotlin 支持标准的数字算术运算集:+, -, *, /, %. 它们被声明为相应类的成员。您还可以为自定义类覆盖这些运算符。有关详细信息,请参阅 运算符重载。 println(1 + 2) println(2_500_000_000L - 1L) println(3.14 * 2.71) println(10.0 / 3)
整数除法
整数之间的除法总是返回一个整数。任何小数部分都将被丢弃。 val x = 5 / 2 //println(x == 2.5) // ERROR: Operator "==" cannot be applied to "Int" and "Double" println(x == 2)
位运算
Kotlin 提供了一组对整数的 按位运算。 它们直接在数字表示的二进制位上进行操作。 但对于位运算,没有特殊字符来表示, 只能用中缀函数表示,它们只能应用于Int和Long。 val x = (1 shl 2) and 0x000FF000
以下是按位运算的完整列表: shl(bits)– 有符号左移 shr(bits)– 有符号右移 ushr(bits)– 无符号右移 and(bits)– 按位 和 or(bits)– 按位 或 xor(bits)– 按位 异或 inv()– 位反转 布尔值
布尔用 Boolean 类型表示,它有两个值:true 和 false。若需要可空引用布尔会被装箱。内置的布尔运算有: || – 短路逻辑或&& – 短路逻辑与! – 逻辑 非 字符
字符类型由 Char表示。字符文字放在单引号中:"1"。 特殊字符可以用反斜杠转义 ,持以下转义序列: , b, , r, ", ",和$。要对任何其他字符进行编码,请使用 Unicode 转义序列语法:" "。 当需要可空引用时,像数字、字符会被装箱。装箱操作不会保留同一性。 val aChar: Char = "a" println(aChar) println(" ") //prints an extra newline character println(" ")字符串
Kotlin 中的字符串类型由String表示。通常,字符串值是双引号 ( ") 中的字符序列。字符串的元素是字符,您可以通过索引操作访问:s[i]。也可以使用循环遍历这些字符for: for (c in str) { println(c) }
字符串是不可变的。初始化字符串后,您将无法更改其值或为其分配新值。所有改变字符串的操作都在一个新String对象中返回它们的结果,而原始字符串保持不变。 val str = "abcd" println(str.uppercase()) // Create and print a new String object println(str) // the original string remains the same
要连接字符串,请使用+运算符。这也适用于将字符串与其他类型的值连接,只要表达式中的第一个元素是字符串: val s = "abc" + 1 println(s + "def")
请注意,在大多数情况下,使用 字符串模板或原始字符串优于字符串连接。
字符串字面量
Kotlin 有两种类型的字符串文字: 可能包含转义字符的转义字符串 可以包含换行符和任意文本的原始字符串
这是一个转义字符串的示例: val s = "Hello, world! "
原始字符串由三引号 ( """) 分隔,不包含转义,并且可以包含换行符和任何其他字符: val text = """ for (c in "foo") print(c) """
要从原始字符串中删除前导空格,请使用以下 trimMargin()函数: val text = """ |Tell me and I forget. |Teach me and I remember. |Involve me and I learn. |(Benjamin Franklin) """.trimMargin()
默认情况下,|用作边距前缀,但您可以选择另一个字符并将其作为参数传递,例如trimMargin(">")。
字符串模板
字符串可以包含模板表达式 ,即一些小段代码,会求值并把结果合并到字符串中。 模板表达式以美元符($)开头,由一个简单的名字构成: val i = 10 println("i = $i") // prints "i = 10"
或者用花括号扩起来的任意表达式: val s = "abc" println("$s.length is ${s.length}") // prints "abc.length is 3"
原生字符串和转义字符串内部都支持模板。 如果你需要在原生字符串中表示字面值 $ 字符(它不支持反斜杠转义),你可以用下列语法: val price = """ ${"#39;}_9.99 """数组
Kotlin 中的数组由Array类表示, 并且还有一个 size 属性及 get 和 set 方法,由于使用 [] 重载了 get 和 set 方法,所以我们可以通过下标很方便地获取或者设置数组对应位置的值。 class Array private constructor() { val size: Int operator fun get(index: Int): T operator fun set(index: Int, value: T): Unit operator fun iterator(): Iterator // ... }
数组的创建有两种方式:一种是使用函数arrayOf();另外一种是使用工厂函数。如下所示,我们分别是两种方式创建了两个数组: //[1,2,3] val a = arrayOf(1, 2, 3) //[0,2,4] val b = Array(3, { i -> (i * 2) }) //读取数组内容 println(a[0]) // 输出结果:1 println(b[1]) // 输出结果:2
正如我们上面所说,该[]操作代表对成员函数的调用get()和set()。Kotlin 中的数组是 不变 的。这意味着 Kotlin 不允许我们将Array分配给Array,这可以防止可能的运行时失败(但您可以使用Array,请参阅Type Projections)。
原始类型数组
Kotlin 也有表示基本类型数组, 省去了装箱操作,因此效率更高 :ByteArray、ShortArray、IntArray等等。这些类与Array类没有继承关系,但它们具有相同的方法和属性集。它们中的每一个也都有对应的工厂函数: val x: IntArray = intArrayOf(1, 2, 3) x[0] = x[1] + x[2] // Array of int of size 5 with values [0, 0, 0, 0, 0] val arr = IntArray(5) // e.g. initialise the values in the array with a constant // Array of int of size 5 with values [42, 42, 42, 42, 42] val arr = IntArray(5) { 42 } // e.g. initialise the values in the array using a lambda // Array of int of size 5 with values [0, 1, 2, 3, 4] (values initialised to their index value) var arr = IntArray(5) { it * 1 }