Kotlin学习之基础篇—基本数据类型


写在前面: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
- FloatfF标记: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里===表示引用相等,即当ab都指向同一个对象时,a === b才为true。如果用===来比较原始类型数据,比如Int,那么其作用相当于==

上面代码中boxedA === anotherBoxedA为什么会返回false呢? 首先,我们已经知道,可空引用数字将会使数字被封装,因此这个比较并不是原始类型数据的比较,而是封装后的数字对象的比较,即引用相等性比较。

在Java中,对数字封装时,值大小在 -128127 之间的数字封装会被缓存起来,如下:

public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

可以看到,调用valueOf方法对数字封装时,如果值大小在-128IntegerCache.high 之间,会返回缓存中的对象,否则返回一个新的对象。这个IntegerCache.high是由系统来决定的,也可以自己设置。所以如果一个数字的数值在-128IntegerCache.high之间,不管对它封装多少次,其引用地址都是同一个。而数值在此之外的数字,每次对其进行封装都会产生一个新的对象,其引用地址当然也不相同。

因此,如果把上面代码中的常量a的大小改为-128127之间的数字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方法比较ab,如果anull,则检查b是否也为null

1.4 显示转换

在Java中,小的数字类型可以隐式转换为大的数字类型,比如:

byte b = 10;
int i = b;
double d = i;

byte可以隐式转intint可以隐式转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 == ba != 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类型代表布尔值,有truefalse两种取值。
如果布尔值被可空引用,将被自动封装。

内置的逻辑操作符包括:
- || -短路逻辑或
- && - 短路逻辑与
- ! - 逻辑非


4. 数组

Kotlin中数组用Array类表示,数组有getset方法(会通过操作符重载转换为[]),并且拥有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>
    // ...
}

要创建一个数组,可以使用 libraryarrayOf() 方法,比如arrayOf(1, 2, 3)会创建一个数组[1, 2, 3]。此外,librayarrayOfNulls() 方法能用来创建一个指定长度的元素全是null的数组。比如:arrayOfNulls<Int>(2)将创建一个size2Int数组,数组里元素的值都是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中文站文档
新手入门,难免有理解错误的地方,请多指教。

猜你喜欢

转载自blog.csdn.net/chenrenxiang/article/details/80626022