Kotlin基础知识

本文翻译自Kotlin官方学习文档:https://kotlinlang.org/docs/kotlin-docs.pdf

基础类型

在Kotlin语言中,可以从任何变量调用成员方法和属性,从这一点来说,任何事物都是对象。一些类型是内置对象,因为它们的实现经过优化,但对于用户来说,它们就和普通的类一样。在这一节中,我们将这些类型的大部分描述为:数字类型,字符类型,布尔类型和数组类型

  • 数字类型

Kotlin处理数字的方式和Java很接近,但是不完全相同。比如,没有数字的隐式拓宽类型转换,在一些情况下,文字也有稍微的不同

Kotlin提供了以下几种内置的类型表示数字(这点和Java类似):

类型 位宽
——————
Double 64
——————
Float 32
——————
Long 64
——————
Int 32
——————
Short 16
——————
Byte 8

注意在Kotlin中字符不是数字类型

  • 字面常量

整数值有以下几种字面常量:

—十进制数: 123
—Long类型的数用大写L标识 : 123L
—十六进制数: 0x0F
—二进制数: 0b00001011

注意:不支持八进制字面量

Kotlin也支持传统的符号表示浮点型数字:

—默认为Double类型: 123.5 , 123.5e10
—Float类型使用f或F标识 : 123.5f

  • 在数字字面量上加下划线(从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
  • 表示法

在Java平台上,数字是作为JVM的原始类型进行物理存储的,除非需要一个非空的数字引用(例如:Int?)或有泛型包含在内。在后一种情况下,是将数字进行装箱。

注意装箱的数字没有必要保持一致:

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) // 打印'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // 打印'true'
  • 显式转换

由于不同的表示法,小的类型不是大类型的子类型。如果是的话,就没有下面这些麻烦了:

// 假设代码,没有实际编译:
val a: Int? = 1 // 装箱为Int (java.lang.Integer)
val b: Long? = a // 隐式转换装箱为Long (java.lang.Long)
print(a == b) // 意外! 当equals()方法检查其他部分为Long时,也会输入"false"

所以不仅是一致性,就算等同也会在此默认丢失一部分

作为结果,小的类型不可以隐式地转换为较大的类型。这意味着如果没有经过显式转换,我们不能给一个Int类型的变量指定一个Byte类型的值

val b: Byte = 1 // 正确,字面量进行了静态检查
val i: Int = b // 错误

我们可以使用显式转换来拓宽数字型

val i: 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支持一套对数字的标准算数操作,这些算数操作被声明为响应类的成员(但是编译器根据对应的指定对调用进行优化)。详见Operator overloading

对于位运算,没有特殊字符的要求,但是只有命名的函数可以以中缀方式被调用,例如:

val x = (1 shl 2) and 0x000FF000

这是完整的位运算列表:

shl(bits) – 左移位运算 (相当于Java的 << )
shr(bits) – 右移位运算 (相当于Java的 >> )
ushr(bits) – 无符号的右移位运算 (相当于Java的 >>> )
and(bits) – 位运算”与”
or(bits) – 位运算”或”
xor(bits) – 位运算”异或”
inv() – 位运算”取反”

  • 字符型

Char代表字符类型,不可以直接作为数字来对待

fun check(c: Char) {
    if (c == 1) { // 错误:类型不相容
    // ...
}

字符是在单引号中:’1’。特殊字符可以使用反斜线转义。下面的转义序列是支持的:\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() // 显式转换字符为数字
}

和数字一样,当需要null引用时,字符被装箱。装箱时不保证一致性

  • 布尔型

Boolean代表布尔类型,有两个值:true和false

如果需要null引用,布尔值被装箱

内置的布尔操作符包括

— || – 懒惰式分割
— && –懒惰式连接
— ! - 否定

  • 数组

Kotlin中,使用Array类来表示数组,它有get和set方法(通过约定的操作符重载转换为[]),以及合适的长度,和一些其他有用的成员方法:

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)创建了一个数组[1, 2, 3]。另外,库函数arrayOfNulls()可以用来创建一个给定大小,使用null值填充的数组

另一种方法是使用工厂方法获取数组大小,方法中返回每个指定索引位置数组元素的初始值:

// 创建一个Array<String>,元素值为 ["0", "1", "4", "9", "16"]
val asc = Array(5, { i -> (i * i).toString() })

像上面所说的,[]操作表示调用get()和set()成员方法

注意:和Java不一样,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]
  • 字符串

String用来表示字符串。字符串是不可变得。字符串的元素是字符,可以通过索引访问:s[i]。一个字符串可以使用for循环遍历:

for (c in str) {
println(c)
}
  • 字符串文字

Kotlin有两种字符串文字:包含转义字符的转义字符串和可以包含新行、任意文本的原始字符串。转义字符串和Java的字符串很像:

val s = "Hello, world!\n"

转义用传统的方式实现,使用反斜杠。支持的转义序列列表,参见上面的Characters,原始字符串使用三引号(”“”)进行分隔,不包含转义,可以包含新的行和任意字符

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
val s = "i = $i" // 结果为 "i = 10"

或者花括号里的任意表达式:

val s = "abc"
val str = "$s.length is ${s.length}" // 结果为 "abc.length is 3"

模板支持内置原始字符串和内置转义字符串。如果需要在原始字符串(不支持反斜杠转义)中表示”$”字符,可以使用如下语法:

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

源文件以包声明开始:

package foo.bar
fun baz() {}
class Goo {}
// ...

源文件的所有内容(类和方法)都包含在包的声明中。所以,在上面的例子中,baz()的全名为foo.bar.baz,Goo的全名为foo.bar.Goo

如果没有指定包,文件默认属于没有名称的”default”包

  • 默认导入

Kotlin文件默认导入一些包:

—kotlin.*
—kotlin.annotation.*
—kotlin.collections.*
—kotlin.comparisons.* (since 1.1)
—kotlin.io.*
—kotlin.ranges.*
—kotlin.sequences.*
—kotlin.text.*

根据平台会导入一些额外的包:

—JVM:
java.lang.*
kotlin.jvm.*
—JS:
kotlin.js.*

  • 导入包

除默认导入的包,每个文件包含自己的导入准则。导入包的语法在”语法”中已经描述过。

我们也可以导入单个名称,如:

import foo.Bar // Bar类现在可以被使用

或者范围内(包,类,对象等)所有可以访问的内容:

import foo.* // 'foo'内的所有内容可以访问

如果有命名冲突,我们可以使用as关键字进行本地重命名类消除歧义:

import foo.Bar // Bar类可访问
import bar.Bar as bBar // bBar代表访问'bar.Bar'类

import关键字不是被限制于引入类,也可以使用它来引入其他声明:

—顶级函数和属性
—对象中声明的方法和属性
—枚举常量

和Java不同,Kotlin没有单独的”import static”语法,所有的声明使用import关键字引入

  • 顶级声明的可见性

如果一个顶级声明被标记为private,它在被声明的文件里就是private访问权限(详见 Visibility Modifiers)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值