Kotlin学习(十六): 关键字与操作符(Keywords and Operators)

来源:互联网 发布:男士围巾 知乎 编辑:程序博客网 时间:2024/06/06 15:40

图片来源于网络

本文同步更新于旺仔的个人博客,访问可能有点慢,多刷新几次。

Kotlin中有一些常用的关键字和标识符,同时还有一些操作符和特殊符号,这些都是和Java有不一样的地方的,这里将他们介绍一下,方便记忆和回看。

硬关键字(Hard Keywords)

Kotlin中的硬关键字不能作为标识符

package

与Java一样,Kotlin的源文件同样以包声明开始的。

package foo.barfun baz() {}class Goo {}// ...

interface

interface表示声明一个接口,

interface MyInterface {    fun bar()    fun foo() {      // 可选的方法体    }}

class

Kotlin的类的声明与Java一样,使用class关键字

class Invoice {}

object

object为同时声明一个类及其实例,请看对象表达式。

super

具体内容可看Kotlin学习_类和继承、接口与实现。

引用一个方法或属性的超类实现

open class Foo {    open fun f() { println("Foo.f()") }    open val x: Int get() = 1}class Bar : Foo() {    override fun f() {         super.f()        println("Bar.f()")     }    override val x: Int get() = super.x + 1}

在此构造函数中调用超类构造函数

class MyView : View {    constructor(ctx: Context) : super(ctx)    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)}

null

null是表示不指向任何对象的对象引用的常量。

this

引用当前接收者

在次构造函数(二级构造函数)中调用同一个类中的另一个构造函数。

class Person(val name: String) {    constructor(name: String, paret: Person) : this(name) {        parent.children.add(this)    }    constructor(name: String, parent: Person, count: Int) : this(name) {        parent.children.add(this)    }}

typealias

类型别名为现有类型提供替代名称。如果类型名称太长,您可以引入不同的较短的名称,并使用新的名称。
缩短长泛型类型:

typealias NodeSet = Set<Network.Node>typealias FileTable<K> = MutableMap<K, MutableList<File>>

可以为功能类型提供不同的别名:

typealias MyHandler = (Int, String, Any) -> Unittypealias Predicate<T> = (T) -> Boolean

as

as是一个中缀操作符。
用于类型转换
as是不安全的转换操作符,如果as转换失败,会抛出一个异常,这就是不安全的。

val x: String = y as String

上面的代码表示将y强转为String类型,如果y为null,那么将不能转换成String,因为String是不可空的类型,那么就会抛出一个异常,所以如果y的类型是可空类型的话,那么强转的类型就必须是可空的

val x: String? = y as String?

用于指定导入包的别名
as除了用于类型转换之外,还有一个作用就是可以指定导入包的别名

import foo.Bar // Bar 可访问import bar.Bar as bBar // bBar 代表“bar.Bar”

as?

as?as类似,也是转换操作符,但是与as不同的是,as?是安全的,也就是可空的,可以避免抛出异常,在转换失败是会返回null

val x: String? = y as? String

as后面的类型是个可空的类型,而as?后面的类型确实非空类型,但是as?转换的类型却是可空的,这样是主要的区别。

ifelse

在Kotlin中,if表达式表示返回一个值(truefalse),Kotlin中没有三目运算符。
else与Java定义一样,定义一个if表达式条件为false时执行的分支。

//传统用法var max = aif (a < b)    max = b//带 else var max: Intif (a > b)    max = aelse    max = b//作为表达式val max = if (a > b) a else b

truefalse

指定布尔类型的”真”值和”假”值。

whiledo

while是开始一个while循环(前置条件的循环),而do为开始一个do/while循环(后置条件的循环),do...while 与Java的一样,有一个区别是,语句块里面的变量在外面是可见的

while (x > 0) {    x--}do {    val y = retrieveData()} while (y != null) // y 在这是可见的

for

for表示开始一个for循环

for (item: Int in ints) {    // ...}

when

Kotlin中的when就类似与Java的switch,但是与switch不同的是,when在其它分支都不匹配的时候默认匹配 else 分支,如果没有把所有可能和分支条件列出来,那么else是强制的,这与switchdefault也有区别。

when (x) {    1 -> print("x == 1")    2 -> print("x == 2")    else -> { // 默认        print("x is neither 1 nor 2")    }}

break

break用于终止循环的执行,使用break 跳转到标签处,跳出循环

loop@ for (i in 1..10) {    for (j in i..10) {        if (j == 5)             break@loop // 跳出循环        Log.e(Tag, j.toString()) // j 为5的时候跳出了循环,只打印1、2、3、4    }}

continue

continue用于跳到最近的闭合循环的下一次循环

loop@ for (i in 1..10) {    for (j in i..10) {        if (j == 5)             continue@loop // 跳出本次循环,进行下一次循环        Log.e(Tag, j.toString()) // j 为5的时候跳出了循环,所有不会打印5    }}

return

return默认从最直接包围它的函数或者匿名函数返回。

fun foo() {    ints.forEach {        if (it == 0) return // 跳出forEach        print(it)    }}

fun

fun表示声明一个函数

fun test() {}

in

用于指定for循环中迭代的对象

for (item in collection) print(item)

用作中缀操作符以检查一个值属于一个区间、一个集合或者其他定义contains方法的实体。

if (i in 1..10) { // 等同于 1 <= i && i <= 10    println(i)}if(a in b){ // a in b等同于b.contains(a)    println("a in b")}

when中使用

when (x) {    in 1..10 -> print("x is in the range")    in validNumbers -> print("x is valid")    else -> print("none of the above")}

将一个类型参数标记为逆变

abstract class Comparable<in T> {    abstract fun compareTo(other: T): Int}fun demo(x: Comparable<Number>) {    x.compareTo(1.0) // 1.0 拥有类型 Double,它是 Number 的子类型    // 因此,我们可以将 x 赋给类型为 Comparable <Double> 的变量    val y: Comparable<Double> = x // OK!}

!in

!in表示与in相反
用作中缀操作符以检查一个值属于一个区间、一个集合或者其他定义contains方法的实体。

if (i !in 1..10) { // 表示i不在110区间    println(i)}if(a !in b){ // a !in b等同于!b.contains(a)    println("a !in b")}

when中使用

when (x) {    in 1..10 -> print("x is in the range")    !in 10..20 -> print("x is outside the range")    else -> print("none of the above")}

is!is

是否符合给定类型

类似与Java的instanceOfis操作符或其否定形式!is来检查对象是否符合给定类型:

if (obj is String) {    print(obj.length)}if (obj !is String) { // 与 !(obj is String) 相同    print("Not a String")}else {    print(obj.length)}

when表达式中用于判定是否符合

fun hasPrefix(x: Any) = when(x) {    is String -> x.startsWith("prefix")    else -> false}

throwtry

throwtry与Java定义一样,throw为抛出一个异常,而try为捕获异常。

throw MyException("Hi There!")try {    // 一些代码}catch (e: SomeException) {    // 处理程序}finally {    // 可选的 finally 块}

val

val表示声明一个只读属性或局部变量

val name: String = ……

var

val表示声明一个可变属性或局部变量

var name: String = ……

软关键字(Soft Keywords)

以下符号在适用的上下文中充当关键字,而在其他上下文中可用作标识符:

import

导入一个包里面的类文件

import foo.Bar // 导入foo包里面的Bar

by

将接口的实现委托给另一个对象

interface Base {    fun print()}class BaseImpl(val x: Int) : Base {    override fun print() { print(x) }}class Derived(b: Base) : Base by bfun main(args: Array<String>) {    val b = BaseImpl(10)    Derived(b).print() // 输出 10}

将属性访问器的实现委托给另一个对象

class Example {    var p: String by Delegate()}class Delegate {    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {        return "$thisRef, thank you for delegating '${property.name}' to me!"    }    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {        println("$value has been assigned to '${property.name} in $thisRef.'")    }}

get

声明属性的getter

val isEmpty: Boolean    get() = this.size == 0

用作注解使用处目标

set

声明属性的setter

var stringRepresentation: String    get() = this.toString()    set (value) {        setDataFormString(value) // 格式化字符串,并且将值重新赋值给其他元素    }

用作注解使用处目标

dynamic

引用一个Kotlin/JS代码中的动态类型

val dyn: dynamic = ……

catch

与Java一样,处理异常

try {    // 一些代码}catch (e: SomeException) {    // 处理程序}

finally

与Java一样,try退出时总会执行的块

try {    // 一些代码}catch (e: SomeException) {    // 处理程序}finally {    // 可选的 finally 块}

constructor

声明一个主构造函数或次构造函数

class Person constructor(firstName: String) {}

init

主构造函数不能包含任何的代码。初始化的代码可以放到以init关键字作为前缀的初始化块中:

class Customer(name: String) {    init {        logger.info("Customer initialized with value ${name}")    }}

paramsetparamdelegatefieldfileproperty

用作注解使用处目标

class Example(@field:Ann val foo,    // 标注 Java 字段              @get:Ann val bar,      // 标注 Java getter              @param:Ann val quux)   // 标注 Java 构造函数参数

使用目标(Use-site Targets)支持的有:
- file
- property使用此目标的注解对Java不可见
- field
- get 属性的getter
- set 属性的setter
- receiver 扩展函数或属性的接收器参数
- param 构造函数参数
- setparam 属性的setter的参数
- delegate 该字段存储代理属性的代理实例

receiver

where

whera用于指定泛型多个类型的上界约束

fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T>    where T : Comparable,          T : Cloneable {  return list.filter { it > threshold }.map { it.clone() }}

修饰词关键字(Modifier Keywords)

out

将类型参数标记为协变

abstract class Source<out T> {    abstract fun nextT(): T}fun demo(strs: Source<String>) {    val objects: Source<Any> = strs // 这个没问题,因为 T 是一个 out-参数    // ……}

annotation

annotation表示声明一个注解类

annotation class Fancy

companion

companion表示声明一个伴生对象

class MyClass {    companion object Factory {        fun create(): MyClass = MyClass()    }}

const

const表示将属性标记为编译期常量,可用于注解当中

const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }

external

external表示将一个声明标记为不是在 Kotlin 中实现(通过JNI访问或者在 JavaScript中实现)

// JNIexternal fun foo(x: Int): Double// JavaScriptexternal fun alert(message: Any?): Unitexternal class Node {    val firstChild: Node    fun append(child: Node): Node    fun removeChild(child: Node): Node    // 等等}external val window: Window

inline

声明一个函数为内联函数

inline fun lock<T>(lock: Lock, body: () -> T): T {    // ……}

crossinline

crossinline表示禁止传递给内联函数的lambda中的非局部返回

inline fun f(crossinline body: () -> Unit) {    val f = object: Runnable {        override fun run() = body()    }    // ……}

noinline

noinline表示一个内联函数如果只有一些被内联,另外的不想内联,可以将函数禁用内联:

inline fun <T> T.one (inlined: () -> Unit, noinline notInlined: () -> Unit) {}

如果一个内联函数没有可内联的函数参数并且没有具体化类型参数,则会产生一个禁告,因为这样的内联函数没有什么用处。

warnning

final

final为禁止成员覆盖。

open class AnotherDerived() : Base() {    final override fun v() {} // v方法不可被重写}

open

允许一个类子类化或覆盖成员,openfinal相反,它允许其他类从这个类继承,默认情况下,在Kotlin中所有的类都是final

open class Base(p: Int)class Derived(p: Int) : Base(p)

data

声明一个类为数据类

data class User(val name: String, val age: Int)

abstract

与Java一样,abstract将一个类或成员标记为抽象

open class Base {    open fun f() {}}abstract class Derived : Base() {    override abstract fun f()}

enum

声明一个枚举类

enum class Color(val rgb: Int) {        RED(0xFF0000),        GREEN(0x00FF00),        BLUE(0x0000FF)}

inner

声明一个内部类,允许在嵌套类中引用外部类实例

class Outer {    private val bar: Int = 1    inner class Inner {        fun foo() = bar    }}val demo = Outer().Inner().foo() // == 1

sealed

声明一个密封类(限制子类化的类)

sealed class Exprdata class Const(val number: Double) : Expr()data class Sum(val e1: Expr, val e2: Expr) : Expr()object NotANumber : Expr()

lateinit

延迟初始化属性,允许在构造函数之外初始化非空属性

public class MyTest {    lateinit var subject: TestSubject    @SetUp fun setup() {        subject = TestSubject()    }    @Test fun test() {        subject.method()  // 直接解引用    }}

operator

将一个函数标记为重载一个操作符,也就是操作符重载

override

与Java类型,override表示重写,Derived.v() 函数上必须加上 override标注。如果没写,编译器将会报错。

open class Base {    open fun v() {}    fun nv() {}}class Derived() : Base() {    override fun v() {}}

private

可见性,将一个声明标记为在当前类或文件中可见

protected

可见性,将一个声明标记为在当前类及其子类中可见

internal

可见性,将一个声明标记为在当前模块中可见

public

可见性,将一个声明标记为在任何地方可见

reified

suspend

将一个函数或lambda表达式标记为挂起式(可用做协程)

suspend fun doSomething(foo: Foo): Bar {    ……}

infix

允许以中缀表示法调用函数

// 给 Int 定义扩展infix fun Int.shl(x: Int): Int {……}// 用中缀表示法调用扩展函数1 shl 2// 等同于这样1.shl(2)

tailrec

tailrec表示将一个函数标记为尾递归(允许编译器将递归替换为迭代)

private fun findFixPoint(): Double {    var x = 1.0    while (true) {        val y = Math.cos(x)        if (x == y) return y        x = y    }}

vararg

vararg表示可变参数(通常是最后一个参数):

fun <T> asList(vararg ts: T): List<T> {    val result = ArrayList<T>()    for (t in ts) // 在这里ts的类型是数组        result.add(t)    return result}

使用:

val list = asList(1, 2, 3)

当我们调用vararg函数,不仅可以接收可以一个接一个传递参数,例如asList(1, 2, 3),也可以将一个数组传递进去,在数组变量前面加spread操作符,就是*号:

val a = arrayOf(1, 2, 3)val list = asList(-1, 0, *a, 4) // 表示(-1, 0, 1, 2, 3, 4)

特殊标识符(Special Identifiers)

field

field为备用字段,Kotlin中的类并不允许使用字段,在自定义gettersetter的时候,可以使用field来起到局部变量的作用。

var counter = 0 //初始化值会直接写入备用字段    get() = field    set(value) {        if (value >= 0)            field  = value    }

编译器会检查访问器的代码,如果使用了备用字段(或者访问器是默认的实现逻辑),就会自动生成备用字段,否则就不会。

// 这种情况并不需要备用字段,所有不会生成备用字段val isEmpty: Boolean    get() = this.size == 0

注意:field标识符只允许在属性的访问器函数内使用.

it

it为单个参数的隐式名称,若函数参数对应的函数只有一个参数,在使用时,可以省略参数定义(连同->),直接使用it代替参数:

val doubled = ints.map { it -> it * 2 }ints.filter { it > 0 } // it表示 '(it: Int) -> Boolean'

这种方式可以写成LINQ-style代码:

strings.filter { it.length == 5 }.sortBy { it }.map { it.toUpperCase() }

操作符和特殊符号(Operators and Special Symbols)

+-*/%

数学操作符,其中*还能用于将数组传给vararg参数

fun <T> asList(vararg ts: T): List<T> {    val result = ArrayList<T>()    for (t in ts) // ts is an Array        result.add(t)    return result}val a = arrayOf(1, 2, 3)val list = asList(-1, 0, *a, 4)

=

=除了作为赋值操作符外,还用于指定参数的默认值

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {}

+=-=*=/=%=

广义赋值操作符

++--

递增递减操作符

&&||!

逻辑“与”、“或”、“非”操作符,对应的中缀函数
- and(bits) – 位与
- or(bits) – 位或
- xor(bits) – 位异或
- inv() – 位非

==!=

相等操作符,对于非原生类型会翻译为调用equals()

===!==

引用相等操作符,引用相等由===(以及其否定形式 !==)操作判断。a === b 当且仅当ab指向同一个对象时求值为true

<><=>=

比较操作符,对于非原生类型会翻译为调用compareTo()

[]

索引访问操作符,会翻译为调用getset

!!

一个表达式非空

val l = b!!.length

?.

执行安全调用,如果接收者非空,就调用一个方法或访问一个属性

b?.length

?:

如果左侧的值为空,就取右侧的值(elvis操作符)

val l = b?.length ?: -1

::

创建一个成员引用或者一个类引用

fun isOdd(x: Int) = x % 2 != 0val numbers = listOf(1, 2, 3)println(numbers.filter(::isOdd)) // 输出 [1, 3]

..

创建一个区间

val s = 1..10

?

将类型标记为可空

val s: String? = null

->

分隔lambda表达式的参数与主体

val sum = { x: Int, y: Int -> x + y }

分隔在函数类型中的参数类型与返回类型声明

// less类型是函数参数fun <T> max(collection: Collection<T>, less: (T, T) -> Boolean): T? {    var max: T? = null    for (it in collection)        if (max == null || less(max, it))            max = it    return max}

分隔 when 表达式分支的条件与代码体

when (x) {    1 -> print("x == 1")    2 -> print("x == 2")    else -> {         print("x is neither 1 nor 2")    }}

@

引入一个注解

@Fancy class Foo {    @Fancy fun baz(@Fancy foo: Int): Int {        return (@Fancy 1)    }}

引入或引用一个循环标签

loop@ for (i in 1..100) {    for (j in 1..100) {        if (……) break@loop    }}

引入或引用一个lambda表达式标签

fun foo() {    ints.forEach lit@ {        if (it == 0) return@lit        print(it)    }}

引用一个来自外部作用域的 this表达式

class A { // 隐式标签 @A    inner class B { // 隐式标签 @B        fun Int.foo() { // 隐式标签 @foo            val a = this@A // A 的 this            val b = this@B // B 的 this            val c = this // foo() 的接收者,一个 Int            val c1 = this@foo // foo() 的接收者,一个 Int            val funLit = lambda@ fun String.() {                val d = this // funLit 的接收者            }            val funLit2 = { s: String ->                // foo() 的接收者,因为它包含的 lambda 表达式                // 没有任何接收者                val d1 = this            }        }    }}

引用一个外部超类

class Bar : Foo() {    override fun f() { /* …… */ }    override val x: Int get() = 0    inner class Baz {        fun g() {            super@Bar.f() // 调用 Foo 实现的 f()            println(super@Bar.x) // 使用 Foo 实现的 x 的 getter        }    }}

;

分隔位于同一行的多个语句

map.forEach { _, value ->     println("$value!");println("$value!") }

$

在字符串模版中引用变量或者表达式

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

_

lambda表达式中代替未使用的参数

map.forEach { _, value ->     println("$value!") }

在解构声明中代替未使用的参数

val (_, status) = getResult()
阅读全文
1 0