基本类型
在Kotlin中,一切皆为对象。也就是说,我们可以在任何变量上调用成员函数和属性。一些类型可以具有特殊的内部表示,例如:数字、字符和布尔值可以做在运行时被表示为原始值,但是对于用户来说,它们看起来像普通类。在本节,我们将描述Kotlin中使用的基本类型:数字,字符,布尔,数组和字符串。
1、 数字类型
Kotlin处理数字和Java很接近,但是并不完全相同.例如, 对于numbers没有隐式扩大转换(如java中int可以隐式变为long),在一些情况下字面量的使用也有些不同。
Kotlin 提供了以下代表数字的内置类型(这与Java相似):
类型 | 位数 |
---|---|
Long | 64 |
Int | 32 |
Short | 16 |
Byte | 8 |
Double | 64 |
Float | 32 |
注意:在Kotlin中,字符不是数字类型。
1.1、 字面常量
下面是一些常量的写法:
整型数值:
Longs类型用大写 L 标记 。如:123L
十六进制写法:0x0101
二进制写法:0b0000 0011
注:Kotlin 不支持8进制
浮点型数值:
默认是Double型:123.5 ,123.5e10
Floats类型用 f 或 F 标记:123.5f,12.5F
1.2、数字使用下划线 ##(1.1 版本起支持)
有时,为了增强数字常量的可读性,我们可以使用下划线。
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
1.3、存储形式
在Java平台上,数字被物理存储为JVM的原始类型,除非我们需要一个可空的数字引用(例如int?)或涉及泛型. 后者情况下数字被装箱。
注意:装箱数字不会保存它的实例:
val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!
但是,它们的值是相等的:
val a: Int = 10000
print(a == a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // Prints 'true'
说明:
=:赋值,在逻辑运算时也有效;
==:等于运算,比较的是值,而不是引用;
===:完全等于运算,不仅比较值,而且还比较引用,只有两者一致才为真。Kotlin 系统类型分为可空和不可空类型,对于数字类型而言:
- 不可空类型类似Java中的基本数字类型,是原始的数字类型,例如:byte,int,long,float,double等。
- 可空类型类似引用的数字类型,例如:Byte,Integer,Long,Float,Double等。
在Java中,从基本数字类型到引用数字类型的转换就是典型的装箱操作,例如int转为Integer。同理,在Kotlin中,非空数字类型到可空数组类型需要进行装箱操作。
val a: Int = 10000
var b: Int = 10000
print(a == b) // Prints 'true'
print(a === b) // prints 'true'
// a,b 都是以原始类型存储的
val a: Int? = 10000
var b: Int? = 10000
print(a == b) // Prints 'true'
print(a === b) // prints 'false'
//a,b 进行了装箱
1.4、显示转换
Kotlin不支持隐士扩大装换,需要显示转换。以下的方式编译会报错:
val b: Byte = 1 // OK, literals are checked statically
val i: Int = b // ERROR
可以通过显示转换:
val i: Int = b.toInt() // OK: explicitly widened
数字类型支持以下显示转换 :
- toByte(): Byte
- toShort(): Short
- toInt(): Int
- toLong(): Long
- toFloat(): Float
- toDouble(): Double
- toChar(): Char
隐式转换可以通过算术操作进行适合的转换。因为类型是可以从上下文中推断出来的:
val a = 1L + 3 // Long + Int => Long
1.5、运算符
Kotlin支持对数字进行算术运算的标准集,它们被声明为相应的类成员(但是编译器将这些调用直接优化为相应的指令)。
对于按位操作,它们没有特殊的字符,只是命名的函数可以以中缀形式调用。例如:
val x = (1 shl 2) and 0x000FF000
下面是完整的按位操作列表(仅适用于 Int 和 Long):
-shl(bits) – signed shift left (Java's << ) (左移)
-shr(bits) – signed shift right (Java's >> ) (右移)
-ushr(bits) – unsigned shift right (Java's >>> )(无符号右移)
-and(bits) – bitwise and (位与)
-or(bits) – bitwise or (位或)
-xor(bits) – bitwise xor (位异或)
-inv() – bitwise inversion(位反转)
负数在内存中是以补码形式存在的。
1.6、浮点数比较
本节讨论的浮点型操作如下:
- 平等检查:a == b and a != b
- 比较运算符:a < b,a > b,a <= b,a >= b
- 范围实例化和范围检查:a..b, x in a..b, x !in a..b
当操作数a 和 b 的类型已知是 Float 或者 Double 或者 它们的可空对应(该类型被声明或者推断或者是智能转换的结果)时,对它们的数字和范围的操作遵循IEEE 754 浮点运算标准。
但是,为了支持通用用例并提供总排序,当操作数不静态输入为浮点数(例如,Any,Comparable <…>,一个类型参数)时,针对Float 和Double 类型,操作会使用equals和compareTo实现,这不符合标准,所以:
- NaN 被认为等同于它自己
- NaN 被认为大于包括POSITIVE_INFINITY在内的任何其它元素
-0.0 被认为小于0.0
这块的内容还没弄明白,欢迎知道的同学给指导下。
2、 字符类型
Characters用Char来表示,字面量使用单引号(如‘1’)。
特殊的字符需要使用反斜杠进行转义。支持以下转义序列: \t, \b, \n, \r, \’, \”, \ and $。对其它字符进行编码,需要使用Unicode转义:‘\uFF00’。
跟数字类型相同,Char类似与java的基本类型char,Char?类似于Java引用类型Character,从非空类型Char到可空类型Char?的转换需要装箱操作。
//#### Characters不能直接作为数字来使用 ####
fun check(c: Char) {
if (c == 1) { // ERROR: incompatible types
// ...
}
}
// #### 可以显式地将Character转换为Int ####
fun decimalDigitValue(c: Char): Int {
if (c !in '0'..'9')
throw IllegalArgumentException("Out of range")
return c.toInt() - '0'.toInt() // Explicit conversions to numbers
}
3、 布尔类型
跟Java一样,Kotlin布尔类型有两种值:true 和 false,支持 || , && ,!三种运算。
如果使用了空引用,Booleans 需要装箱操作的,同Numbers ,Characters。
4、 数组
使用 Array类来表示;它有get、set函数(使用时可以用[],通过符号重载的约定转换)以及其他的有用的成员函数,也有size属性。
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 ()来创建一个包含数值的数组;或者arrayOfNulls()可以创建一个指定大小,元素都为空的数组;或者使用函数来创建一个数组:
var a1: Array<String> = arrayOf("data1", "data2")
var a2 = arrayOfNulls<String>(10)
var a3 = Array(10, {i -> (i + i).toString()})
注意: 与Java不同,Kotlin中的数组是不可变的。也就是说,Kotlin不允许我们将 Array<String>
分配给 Array<Any>
,以防止运行错误(但是你可以使用Array<outAny>
,参考 Type Projections).
此外,Kotlin有专门的类来表示原始类型的数组,避免了装箱开销: ByteArray, ShortArray, IntArray 等等. 这些类和Array并没有继承关系,但是它们有同样的方法属性集. 它们也都有相应的工厂方法:
val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
5、 字符串
字符串用String表示。字符串是不可变的。
字符串的原始字符可以使用操作符访问: str[i]. 字符串可以使用for{: .keyword }循环遍历。
for (c in str) {
println(c)
}
5.1 字面量
Kotlin字符串有两种类型:
- 转义字符串:可能由转义字符,以及包含换行符和任意文本的原生字符串组成。转义字符串很像java字符串:
val s = "Hello, world!\n"
转义方式采用传统的反斜杠。
- 原生字符串:使用三个引号(
"""
)包括,内部没有转义,可以包含换行和任何其他文本。
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()
默认情况下 |
作为 margin
前缀,但是你可以使用其它字符将它作为参数传入,如 trimMargin(">")
.
5.2 字符串模板
字符串可以包含模板表达式,即一些小段代码,会求值并把结果合并到字符串中。模板表达式以 $ 符号开始,包含一个简单的名称($a
);或者用花括号扩起来,内部可以是任意表达式(${s1.replace(“is”, “was”)}
):
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
"""