写在前面:Kotlin的起始篇其实还有一篇讲Kotlin的编码规范,实在太长我就不翻译了,其实规范大多和Java编码规范类似,当然也有不一样的地方。如果想了解不妨看 Kotlin编码规范-官方文档 。或者看中文版 Kotlin编码规范-kotlin中文站文档 。
Kotlin中,一切皆对象,从这个意义上来说,可以调用任何成员变量的方法和属性。有些数据类型具有特殊的内部表示,例如:数字
,字符
和布尔值
能表示为运行时的原始值,虽然对于用户来说它们看起来没什么特殊。这一节我们将讲述Kotlin中的这些基本的数据类型:数字
,字符
,布尔值
,数组
和字符串
。
1. 数字
Kotlin处理数字的方式和Java类似,但并不完全相同。例如,数字之间不能像Java那样隐式转换。
Kotlin提供了以下内建类型来表示数字(和Java类似)
类型 | 位数 |
---|---|
Double | 64 |
Float | 32 |
Long | 64 |
Int | 32 |
Short | 16 |
Byte | 8 |
注意:char
类型在Kotlin中不是数字
1.1 字面常量
数字有以下几种字面值
- 十进制
– 比如Long类型通常以L为标记:123L
- 十六进制:0x0F
- 二进制: 0b00001011
注意:Kotlin不支持八进制
Kotlin也支持浮点数的简便写法:
- Double
默认写法: 123.5,1.235e2
- Float
用f
或F
标记:123.5f
1.2 数字文字中的下划线
可以使用下划线来使数字更易读,而不会改变数字大小:
val oneMillion = 1_000_000
val creditCardNumber = 123_5678_2344_1233L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
如果把上面的下划线都去掉,数值的大小不会有任何改变,加下划线只是为了格式更清楚更易读而已。
1.3 表现方式
在Java平台上,数字被物理存储为JVM的原始类型,除非我们需要一个可空的数字引用或者泛型。在后一种情况下,数字将被封装。
注意:数字封装后不一定会保持相等性。
val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!
先有必要说下运算符===
,在Java里面,并没有这个运算符,只有==
。在Kotlin里===
表示引用相等,即当a
和b
都指向同一个对象时,a === b
才为true
。如果用===
来比较原始类型数据
,比如Int
,那么其作用相当于==
。
上面代码中boxedA === anotherBoxedA
为什么会返回false呢? 首先,我们已经知道,可空引用数字将会使数字被封装,因此这个比较并不是原始类型数据的比较,而是封装后的数字对象的比较,即引用相等性比较。
在Java中,对数字封装时,值大小在 -128
到127
之间的数字封装会被缓存起来,如下:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
可以看到,调用valueOf
方法对数字封装时,如果值大小在-128
到 IntegerCache.high
之间,会返回缓存中的对象,否则返回一个新的对象。这个IntegerCache.high
是由系统来决定的,也可以自己设置。所以如果一个数字的数值在-128
到 IntegerCache.high
之间,不管对它封装多少次,其引用地址都是同一个。而数值在此之外的数字,每次对其进行封装都会产生一个新的对象,其引用地址当然也不相同。
因此,如果把上面代码中的常量a
的大小改为-128
到127
之间的数字boxedA === anotherBoxedA
将返回true
。
val a: Int = 10000
print(a == a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // Prints 'true'
封装后的数字将保持结构相等,上述代码中boxedA == anotherBoxedA
将返回true
。在Kotlin中==
可以称之为结构相等,其作用类似于方法equals
,可以用以下代码表示:
a?.equals(b) ?: (b === null)
如果a
不为null
,则调用equals
方法比较a
和b
,如果a
为null
,则检查b
是否也为null
。
1.4 显示转换
在Java中,小的数字类型可以隐式转换为大的数字类型,比如:
byte b = 10;
int i = b;
double d = i;
byte
可以隐式转int
,int
可以隐式转double
。
但Kotlin中不支持这种转换,如果要转换只能显示地调用相关的方法,目前各种数字类型都有以下转换方法:
- toByte(): Byte
- toShort(): Short
- toInt(): Int
- toLong(): Long
- toFloat(): Float
- toDouble(): Double
- toChar(): Char
缺少隐式转换并没有多大影响,因为数值的类型可以根据上下文自动推断,而算术运算符已经被重载以在运算时作适当的转换,例如:
val l = 1L + 3 //Long + Int => Long
上面这句代码是ok的,因为算术运算符在运算过程中对数字的类型做了相应的转换。
1.5 运算
Kotlin支持标准的算术运算。但是对于位运算,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
和a != b
- 比较操作符:
a < b
,a > b
,a <= b
,a >= b
- 范围及范围检查:
a..b
,x in a..b
,x !in a..b
2. 字符
字符类型由Char来表示,字符不能直接作为数字使用。
字符字面量要加单引号表示:'1'
。特殊字符可以使用反斜杠转义,Kotlin支持以下转义序列:
\t
, \b
, \n
, \r
, \'
, \"
, \\
以及 \$
。要编码其它字符,可使用Unicode
转义序列语法:\uFF00
。
我们可以显式地将一个字符转成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. 布尔值
Boolean
类型代表布尔值,有true
和false
两种取值。
如果布尔值被可空引用,将被自动封装。
内置的逻辑操作符包括:
- || -短路逻辑或
- && - 短路逻辑与
- ! - 逻辑非
4. 数组
Kotlin中数组用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>
// ...
}
要创建一个数组,可以使用 library
的 arrayOf()
方法,比如arrayOf(1, 2, 3)
会创建一个数组[1, 2, 3]
。此外,libray
的 arrayOfNulls()
方法能用来创建一个指定长度的元素全是null
的数组。比如:arrayOfNulls<Int>(2)
将创建一个size
为2
的Int
数组,数组里元素的值都是null
另一种创建数组的方法是使用Array
的构造方法,如下:
// 创建一个String数组 ["0", "1", "4", "9", "16"]
val asc = Array(5, { i -> (i * i).toString() })
注意:和Java不一样,Kotlin中的数组是不可变的,这意味着Kotlin不允许我们将一个字符串数组Array<String>
直接赋值给数组Array<Any>
,这能防止可能出现的运行时错误。
Kotlin也有一些避免原始类型数组封装消耗的类:ByteArray
, ShortArray
, IntArray
等。这些类和Array
类并没有继承关系,但是它们拥有同样的方法和属性。它们也都有相应的工厂方法:
val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
5. 字符串
字符串类型用String
来表示。字符串是不可变的。字符串的元素(字符
)能够通过索引的方式来访问:s[i]
。字符串可以使用for循环
来迭代:
for(c in str){
println(c)
}
和Java一样,Kotlin能使用加法操作符+
来连接字符串,即使不是字符串类型的数值也可以连接,但和Java有所不同的是,连接表达式中的第一个元素必须是字符串类型。
val s = "abc" + 1
println(s + "def")
打印结果为:
abc1def
注意:在大多数情况下,使用字符串模板或者原始字符串,优于使用字符串连接。
5.1 字符串字面量
Kotlin有两种字符串字面量:包含转义字符的转义字符串 和 包含随意字符或新行的原始字符串。转义字符串和Java的字符串类似:
val s = "Hello, world!\n"
原始字符串由三引号"""
来定义,如下:
val text = """
for (c in "foo")
print(c)
"""
5.2 字符串模板
字符串模板在 Kotlin学习之起始篇—基础语法 已经介绍过了,这里不再赘述。
以上内容参考了 Kotlin官方文档 及 Kotlin中文站文档 。
新手入门,难免有理解错误的地方,请多指教。