Kotlin 基本数据类型

本文为翻译文本,原文来自Kotlin reference,翻译参考了Kotlin 中文站

Kotlin中,一切皆对象,也就是说我们可以对任意变量访问其对应的方法和属性。有一些类型有特殊的内部表示方法,但对于用户来说他们和普通的类没有区别,例如数值,字符和布尔值能够在运行时用原始值表示。这一部分我们将介绍Kotlin中的基本数据类型:数值、字符、布尔值、数组和字符串。

数值类型

Kotlin处理数值的方法和Java非常类似,但并不完全相同。例如,Kotlin中没有对数值类型的隐式类型提升,在某些情况下对字面数值常量的处理也有一点点不同。

Kotlin提供如下内建数值类型(这个Java很像):

TypeBit width
Double64
Float32
Long64
Int32
Short16
Byte8

 
特别地,Kotlin中的字符不是数值类型。

字面常量

以下是一些 Int 字面常量的例子:

  • 十进制:123
    • Long类型需要用 L 标识:123L
  • 十六进制:0x0F
  • 二进制:0b00001011

注意,Kotlin不支持八进制字面整型常量。

Kotlin还支持浮点数标识:

  • 默认的Double类型:123.5123.5e10
  • fF 标识的 Float 类型:123.5f

在数值常量中使用下划线 (Kotlin 1.1)

你可以使用下划线增强数值常量的可读性:

val onoMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010111_01011010

数值的表示

在Java平台上,数值类型物理存储为JVM的原生类型,除非我们需要一个可能为null的(nullable)数值引用(例如:Int?)或者涉及到泛型。当不是原生类型时,数值会被包装(boxed)。

注意,包装后的数值不保证同一性(identity):

val a: Int = 10000
print(a === a) // 此处输出 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!此处输出 'false'!!!

但另一方面,包装会保留值的相等性质:

val a: Int = 10000
print(a == a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // Prints 'true'

显式类型转换

由于表示方法的不同,较小类型不是较大类型的子类型。如果是的话就会有如下的问题:

// 假想代码,无法通过编译
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // implicit conversion yields a boxed Long (java.lang.Long)
print(a == b) // 由于Java中Long类的equals()函数还会检查参数是否为Long类型,这里输出"false",很令人疑惑。

这样一来,不仅是同一性,相等性也会悄然丢失。

基于以上原因,较小类型不会隐式转化为较大类型。这就意味着,在没有显式类型转化的前提下,我们不能将一个 Byte 类型的值赋值给一个 Int 型变量

val b: Byte = 1 // OK,字面常量是静态检查的
val i: Int = b // ERROR

但是,我们可以显示执行类型提升

val i:Int = b.toInt() //OK,显式类型转化

所有的数值类型都支持以下类型转化方法:

  • toByte(): Byte

  • toShort(): Short

  • toInt(): Int

  • toLong(): Long

  • toFloat(): Float

  • toDouble(): Double

  • toChar(): Char

省略隐式类型转化很少被注意到,因为这种转化可以通过上下问推断。重载的算数运算符能够实现适当的类型转化,例如:

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

数值运算

Kotlin支持标准的数值运算,他们被定义为相应类的成员函数(但是编译器会将他们优化为对应的运算符),参考运算符重载

对于位运算虽然没有相应的运算符,但是有相应的可以用中缀形式调用的方法。例如:

val x = (1 shl 2) and 0x000FF000

以下是位完整的位操作列表:

  • shl(bits) –有符号左移,等价与Java中的 <<

  • shr(bits) –有符号右移,等价与Java中的 >>

  • ushr(bits) –无符号右移,等价与Java中的 >>>

  • and(bits) –按位与

  • or(bits) –按位或

  • xor(bits) –按位异或

  • inv() –按位取反

左移操作有无符号都一样,符号位不保留,低位补零。

字符类型

字符使用 Char 表示,Kotlin中不能将字符直接当作数值类型对待。

fun check(c: Char) {
    if (c == 1) { // ERROR: incompatible types
        // ...
    }
}

字符字面常量用单引号标识:'1'。特殊字符使用反斜杠转义。Kotlin支持以下转义字符:\t, \b, \n, \r, \', \", \\\$。如果需要编码其他字符则需要使用Unicode转义语法:\uFF00

我们可以使用 toInt() 将字符显式转化为 Int 类型数值:

fun decimalDigitalValue(c: Char): Int {
    if(c !in '0'..'9') {
        throw IllegalArgumentException("Out of range")
    }
    return c.toInt() - '0'.toInt() // 显式转化为数值类型
}

布尔类型

关键字 Boolean 表示布尔类型。布尔类型具有 truefalse 两个值。

如果布尔类型值是nullable,那么就会被包装。

布尔类型的内建操作包括:

  • || 或逻辑。惰性判断(如果前者为 true 结果为 true,不判断后者)
  • && 与逻辑。惰性判断(如果前者为 false 结果为 false,不判断后者)
  • ! 非逻辑

数组类型

Kotlin中数组使用包含 getset 方法(操作符 [] 会被重载为调用这些方法),size 属性,以及其他方法的 Array 类表示:

class Array<T> private constructor() {
    val size: Int
    operator fun get(index: Int): T
    operator fun set(index: Int, value: T): Unit

    operator fun iterator(): Iterator<T>
    // ...
}

我们可以使用库函数 arrayOf() 并传递元素值来创建数组。例如,arrayOf() 创建数组 [1, 2, 3]。另外,arrayOfNulls() 库函数可以用来创建一个包含给定数量的null元素的数组。

另一个创建数组的方法是使用工厂方法(factory function)。该工厂方法接受两个参数,一个用于指定数组大小;另一个参数为函数,该函数能够根据数组下标计算对应的元素值。

// Creates an Array<String> with values ["0", "1", "4", "9", "16"]
val asc = Array(5, { i -> (i * i).toString() })

正如我们上面提到的,运算符 [] 表示调用 get()set() 方法。

注意:不同于Java,在Kotlin中的数组是不型变的。这就意味着我们不能将一个 Array<String> 赋值给 一个 Array<Any> 类型变量(在Java中我们可以将Integer[] 对象赋值给 Object[] 变量),这避免了某些运行时错误(但我们可以使用 Array<out Any>, 参考类型投影)。

Kotlin还提供 ByteArray, ShortArray, IntArray等,表示内建类型数组的特例化数组类,这能够避免包装开销。虽然这些类和 Array 类没有继承关系,但仍然拥有 Array 类所具有的所有属性和方法。他们中的每一个都还有一个相应的工厂函数:

val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]

字符串

字符串类型用 String 表示。字符串是不可变类型,字符串由字符构成,且字符可以通过下标运算访问: s[i]。字符串的字符可以使用 for 循环迭代访问:

for(c in str) {
    println(c)
}

字符串字面常量

Kotlin有两种字符串字面常量:包含转义字符的转义字符串;包含换行以及其他任意文本的原始字符串(raw string)。转义字符串和Java中的字符串常量非常类似:

val s = "Hello World!\n"

转义通过传统的方法实现,即反斜杠。参考前文中Kotlin支持的转义字符列表。

原始字符串(raw string)使用三引用(""")表示,它不包含任何转义字符,并且能够包含换行和任意其他的字符:

val test = """
    for(c in "foo")
        print(c)
"""

前置空格可以使用 trimMargin() 方法去除:

val test = """
    |Tell me and I forget.
    |Teach me and I remember.
    |Involve me and I learn.
    |(Benjamin Franklin)
    """.trimMargin()

默认的边缘标志是 | ,但是,可以通过传递参数来设置其他的字符,比如:trimMargin('>')

字符串模版

字符串能够包含模版表达式。例如,一段可执行代码,其结果需要表示在字符串中。一个模版表达式起始于 $ 符,其后紧跟一个变量名:

val i = 10
val s = "i = $i" // evaluates to "i = 10"

这个在 $ 后紧跟一个由大括号包裹的表达式:

val s = "abc"
val str = "$s.length is ${ s.length }" // evaluates to "abc.length is 3"

模版表达式支持转义字符串也支持原始字符串,如果你需要在原始字符串(不支持反斜杠转义)中输出一个 $ 字符,那么可以使用一下的语法:

val price = """
${ '$' }9.99
"""

TODO list:
  完善文中链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值