修饰符
在Kotlin源码工程中的kotlin/grammar/src/modifiers.grm文件中,描述了Kotlin语言的修饰符,我们在此作简要注释说明:
/** ## Modifiers */ modifiers : (modifier | annotations)* ; typeModifiers : (suspendModifier | annotations)* ; modifier : classModifier : accessModifier : varianceAnnotation : memberModifier : parameterModifier : typeParameterModifier : functionModifier : propertyModifier ; classModifier 类修饰符 : "abstract" 抽象类 : "final" 不可被继承final类 : "enum" 枚举类 : "open" 可继承open类 : "annotation" 注解类 : "sealed" 密封类 : "data" 数据类 ; memberModifier : "override" 重写函数 : "open" 可被重写 : "final" 不可被重写 : "abstract" 抽象函数 : "lateinit" 后期初始化 ; accessModifier 访问权限控制, 默认是public : "private" : "protected" : "public" : "internal" 整个模块内(模块(module)是指一起编译的一组 Kotlin 源代码文件: 例如,一个 IntelliJ IDEA 模块,一个 Maven 工程, 或 Gradle 工程,通过 Ant 任务的一次调用编译的一组文件等)可访问 ; varianceAnnotation 泛型可变性 : "in" : "out" ; parameterModifier : "noinline" : "crossinline" : "vararg" 变长参数 ; typeParameterModifier : "reified" ; functionModifier : "tailrec" 尾递归 : "operator" : "infix" : "inline" : "external" : suspendModifier ; propertyModifier : "const" ; suspendModifier : "suspend" ;
这些修饰符的完整定义,在kotlin/compiler/frontend/src/org/jetbrains/kotlin/lexer/KtTokens.java源码中:
KtModifierKeywordToken[] MODIFIER_KEYWORDS_ARRAY = new KtModifierKeywordToken[] { ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, INNER_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, OUT_KEYWORD, IN_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, REIFIED_KEYWORD, COMPANION_KEYWORD, SEALED_KEYWORD, LATEINIT_KEYWORD, DATA_KEYWORD, INLINE_KEYWORD, NOINLINE_KEYWORD, TAILREC_KEYWORD, EXTERNAL_KEYWORD, ANNOTATION_KEYWORD, CROSSINLINE_KEYWORD, CONST_KEYWORD, OPERATOR_KEYWORD, INFIX_KEYWORD, SUSPEND_KEYWORD, HEADER_KEYWORD, IMPL_KEYWORD }; TokenSet MODIFIER_KEYWORDS = TokenSet.create(MODIFIER_KEYWORDS_ARRAY); TokenSet TYPE_MODIFIER_KEYWORDS = TokenSet.create(SUSPEND_KEYWORD); TokenSet TYPE_ARGUMENT_MODIFIER_KEYWORDS = TokenSet.create(IN_KEYWORD, OUT_KEYWORD); TokenSet RESERVED_VALUE_PARAMETER_MODIFIER_KEYWORDS = TokenSet.create(OUT_KEYWORD, VARARG_KEYWORD); TokenSet VISIBILITY_MODIFIERS = TokenSet.create(PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD);
关键字(保留字)
TokenSet KEYWORDS = TokenSet.create(PACKAGE_KEYWORD, AS_KEYWORD, TYPE_ALIAS_KEYWORD, CLASS_KEYWORD, INTERFACE_KEYWORD, THIS_KEYWORD, SUPER_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, FUN_KEYWORD, FOR_KEYWORD, NULL_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, IS_KEYWORD, IN_KEYWORD, THROW_KEYWORD, RETURN_KEYWORD, BREAK_KEYWORD, CONTINUE_KEYWORD, OBJECT_KEYWORD, IF_KEYWORD, ELSE_KEYWORD, WHILE_KEYWORD, DO_KEYWORD, TRY_KEYWORD, WHEN_KEYWORD, NOT_IN, NOT_IS, AS_SAFE, TYPEOF_KEYWORD ); TokenSet SOFT_KEYWORDS = TokenSet.create(FILE_KEYWORD, IMPORT_KEYWORD, WHERE_KEYWORD, BY_KEYWORD, GET_KEYWORD, SET_KEYWORD, ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, INNER_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, CATCH_KEYWORD, FINALLY_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, REIFIED_KEYWORD, DYNAMIC_KEYWORD, COMPANION_KEYWORD, CONSTRUCTOR_KEYWORD, INIT_KEYWORD, SEALED_KEYWORD, FIELD_KEYWORD, PROPERTY_KEYWORD, RECEIVER_KEYWORD, PARAM_KEYWORD, SETPARAM_KEYWORD, DELEGATE_KEYWORD, LATEINIT_KEYWORD, DATA_KEYWORD, INLINE_KEYWORD, NOINLINE_KEYWORD, TAILREC_KEYWORD, EXTERNAL_KEYWORD, ANNOTATION_KEYWORD, CROSSINLINE_KEYWORD, CONST_KEYWORD, OPERATOR_KEYWORD, INFIX_KEYWORD, SUSPEND_KEYWORD, HEADER_KEYWORD, IMPL_KEYWORD );
其中,对应的关键字如下:
KtKeywordToken PACKAGE_KEYWORD = KtKeywordToken.keyword("package"); KtKeywordToken AS_KEYWORD = KtKeywordToken.keyword("as"); KtKeywordToken TYPE_ALIAS_KEYWORD = KtKeywordToken.keyword("typealias"); KtKeywordToken CLASS_KEYWORD = KtKeywordToken.keyword("class"); KtKeywordToken THIS_KEYWORD = KtKeywordToken.keyword("this"); KtKeywordToken SUPER_KEYWORD = KtKeywordToken.keyword("super"); KtKeywordToken VAL_KEYWORD = KtKeywordToken.keyword("val"); KtKeywordToken VAR_KEYWORD = KtKeywordToken.keyword("var"); KtKeywordToken FUN_KEYWORD = KtKeywordToken.keyword("fun"); KtKeywordToken FOR_KEYWORD = KtKeywordToken.keyword("for"); KtKeywordToken NULL_KEYWORD = KtKeywordToken.keyword("null"); KtKeywordToken TRUE_KEYWORD = KtKeywordToken.keyword("true"); KtKeywordToken FALSE_KEYWORD = KtKeywordToken.keyword("false"); KtKeywordToken IS_KEYWORD = KtKeywordToken.keyword("is"); KtModifierKeywordToken IN_KEYWORD = KtModifierKeywordToken.keywordModifier("in"); KtKeywordToken THROW_KEYWORD = KtKeywordToken.keyword("throw"); KtKeywordToken RETURN_KEYWORD = KtKeywordToken.keyword("return"); KtKeywordToken BREAK_KEYWORD = KtKeywordToken.keyword("break"); KtKeywordToken CONTINUE_KEYWORD = KtKeywordToken.keyword("continue"); KtKeywordToken OBJECT_KEYWORD = KtKeywordToken.keyword("object"); KtKeywordToken IF_KEYWORD = KtKeywordToken.keyword("if"); KtKeywordToken TRY_KEYWORD = KtKeywordToken.keyword("try"); KtKeywordToken ELSE_KEYWORD = KtKeywordToken.keyword("else"); KtKeywordToken WHILE_KEYWORD = KtKeywordToken.keyword("while"); KtKeywordToken DO_KEYWORD = KtKeywordToken.keyword("do"); KtKeywordToken WHEN_KEYWORD = KtKeywordToken.keyword("when"); KtKeywordToken INTERFACE_KEYWORD = KtKeywordToken.keyword("interface"); // Reserved for future use: KtKeywordToken TYPEOF_KEYWORD = KtKeywordToken.keyword("typeof"); ... KtKeywordToken FILE_KEYWORD = KtKeywordToken.softKeyword("file"); KtKeywordToken FIELD_KEYWORD = KtKeywordToken.softKeyword("field"); KtKeywordToken PROPERTY_KEYWORD = KtKeywordToken.softKeyword("property"); KtKeywordToken RECEIVER_KEYWORD = KtKeywordToken.softKeyword("receiver"); KtKeywordToken PARAM_KEYWORD = KtKeywordToken.softKeyword("param"); KtKeywordToken SETPARAM_KEYWORD = KtKeywordToken.softKeyword("setparam"); KtKeywordToken DELEGATE_KEYWORD = KtKeywordToken.softKeyword("delegate"); KtKeywordToken IMPORT_KEYWORD = KtKeywordToken.softKeyword("import"); KtKeywordToken WHERE_KEYWORD = KtKeywordToken.softKeyword("where"); KtKeywordToken BY_KEYWORD = KtKeywordToken.softKeyword("by"); KtKeywordToken GET_KEYWORD = KtKeywordToken.softKeyword("get"); KtKeywordToken SET_KEYWORD = KtKeywordToken.softKeyword("set"); KtKeywordToken CONSTRUCTOR_KEYWORD = KtKeywordToken.softKeyword("constructor"); KtKeywordToken INIT_KEYWORD = KtKeywordToken.softKeyword("init"); KtModifierKeywordToken ABSTRACT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("abstract"); KtModifierKeywordToken ENUM_KEYWORD = KtModifierKeywordToken.softKeywordModifier("enum"); KtModifierKeywordToken OPEN_KEYWORD = KtModifierKeywordToken.softKeywordModifier("open"); KtModifierKeywordToken INNER_KEYWORD = KtModifierKeywordToken.softKeywordModifier("inner"); KtModifierKeywordToken OVERRIDE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("override"); KtModifierKeywordToken PRIVATE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("private"); KtModifierKeywordToken PUBLIC_KEYWORD = KtModifierKeywordToken.softKeywordModifier("public"); KtModifierKeywordToken INTERNAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("internal"); KtModifierKeywordToken PROTECTED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("protected"); KtKeywordToken CATCH_KEYWORD = KtKeywordToken.softKeyword("catch"); KtModifierKeywordToken OUT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("out"); KtModifierKeywordToken VARARG_KEYWORD = KtModifierKeywordToken.softKeywordModifier("vararg"); KtModifierKeywordToken REIFIED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("reified"); KtKeywordToken DYNAMIC_KEYWORD = KtKeywordToken.softKeyword("dynamic"); KtModifierKeywordToken COMPANION_KEYWORD = KtModifierKeywordToken.softKeywordModifier("companion"); KtModifierKeywordToken SEALED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("sealed"); KtModifierKeywordToken DEFAULT_VISIBILITY_KEYWORD = PUBLIC_KEYWORD; KtKeywordToken FINALLY_KEYWORD = KtKeywordToken.softKeyword("finally"); KtModifierKeywordToken FINAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("final"); KtModifierKeywordToken LATEINIT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("lateinit"); KtModifierKeywordToken DATA_KEYWORD = KtModifierKeywordToken.softKeywordModifier("data"); KtModifierKeywordToken INLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("inline"); KtModifierKeywordToken NOINLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("noinline"); KtModifierKeywordToken TAILREC_KEYWORD = KtModifierKeywordToken.softKeywordModifier("tailrec"); KtModifierKeywordToken EXTERNAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("external"); KtModifierKeywordToken ANNOTATION_KEYWORD = KtModifierKeywordToken.softKeywordModifier("annotation"); KtModifierKeywordToken CROSSINLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("crossinline"); KtModifierKeywordToken OPERATOR_KEYWORD = KtModifierKeywordToken.softKeywordModifier("operator"); KtModifierKeywordToken INFIX_KEYWORD = KtModifierKeywordToken.softKeywordModifier("infix"); KtModifierKeywordToken CONST_KEYWORD = KtModifierKeywordToken.softKeywordModifier("const"); KtModifierKeywordToken SUSPEND_KEYWORD = KtModifierKeywordToken.softKeywordModifier("suspend"); KtModifierKeywordToken HEADER_KEYWORD = KtModifierKeywordToken.softKeywordModifier("header"); KtModifierKeywordToken IMPL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("impl");
this 关键字
this
关键字持有当前对象的引用。我们可以使用this
来引用变量或者成员函数,也可以使用return this
,来返回某个类的引用。
代码示例
class ThisDemo { val thisis = "THIS IS" fun whatIsThis(): ThisDemo { println(this.thisis) //引用变量 this.howIsThis()// 引用成员函数 return this // 返回此类的引用 } fun howIsThis(){ println("HOW IS THIS ?") } }
测试代码
@Test fun testThisDemo(){ val demo = ThisDemo() println(demo.whatIsThis()) }
输出
THIS IS HOW IS THIS ? com.easy.kotlin.ThisDemo@475232fc
在类的成员中,this 指向的是该类的当前对象。
在扩展函数或者带接收者的函数字面值中, this 表示在点左侧传递的 接收者参数。
代码示例:
>>> val sum = fun Int.(x:Int):Int = this + x >>> sum kotlin.Int.(kotlin.Int) -> kotlin.Int >>> 1.sum(1) 2 >>> val concat = fun String.(x:Any) = this + x >>> "abc".concat(123) abc123 >>> "abc".concat(true) abctrue
如果 this 没有限定符,它指的是最内层的包含它的作用域。如果我们想要引用其他作用域中的 this,可以使用 this@label 标签。
代码示例:
class Outer { val oh = "Oh!" inner class Inner { fun m() { val outer = this@Outer val inner = this@Inner val pthis = this println("outer=" + outer) println("inner=" + inner) println("pthis=" + pthis) println(this@Outer.oh) val fun1 = hello@ fun String.() { val d1 = this // fun1 的接收者 println("d1" + d1) } val fun2 = { s: String -> val d2 = this println("d2=" + d2) } "abc".fun1() fun2 } } }
测试代码:
@Test fun testThisKeyWord() { val outer = Outer() outer.Inner().m() }
输出
outer=com.easy.kotlin.Outer@5114e183 inner=com.easy.kotlin.Outer$Inner@5aa8ac7f pthis=com.easy.kotlin.Outer$Inner@5aa8ac7f Oh! d1abc
super 关键字
super关键字持有指向其父类的引用。
代码示例:
open class Father { open val firstName = "Chen" open val lastName = "Jason" fun ff() { println("FFF") } } class Son : Father { override var firstName = super.firstName override var lastName = "Jack" constructor(lastName: String) { this.lastName = lastName } fun love() { super.ff() // 调用父类方法 println(super.firstName + " " + super.lastName + " Love " + this.firstName + " " + this.lastName) } }
测试代码
@Test fun testSuperKeyWord() { val son = Son("Harry") son.love() }
输出
FFF Chen Jason Love Chen Harry
操作符和操作符的重载
Kotlin 允许我们为自己的类型提供预定义的一组操作符的实现。这些操作符具有固定的符号表示(如 +
或 *
)和固定的优先级。这些操作符的符号定义如下:
KtSingleValueToken LBRACKET = new KtSingleValueToken("LBRACKET", "["); KtSingleValueToken RBRACKET = new KtSingleValueToken("RBRACKET", "]"); KtSingleValueToken LBRACE = new KtSingleValueToken("LBRACE", "{"); KtSingleValueToken RBRACE = new KtSingleValueToken("RBRACE", "}"); KtSingleValueToken LPAR = new KtSingleValueToken("LPAR", "("); KtSingleValueToken RPAR = new KtSingleValueToken("RPAR", ")"); KtSingleValueToken DOT = new KtSingleValueToken("DOT", "."); KtSingleValueToken PLUSPLUS = new KtSingleValueToken("PLUSPLUS", "++"); KtSingleValueToken MINUSMINUS = new KtSingleValueToken("MINUSMINUS", "--"); KtSingleValueToken MUL = new KtSingleValueToken("MUL", "*"); KtSingleValueToken PLUS = new KtSingleValueToken("PLUS", "+"); KtSingleValueToken MINUS = new KtSingleValueToken("MINUS", "-"); KtSingleValueToken EXCL = new KtSingleValueToken("EXCL", "!"); KtSingleValueToken DIV = new KtSingleValueToken("DIV", "/"); KtSingleValueToken PERC = new KtSingleValueToken("PERC", "%"); KtSingleValueToken LT = new KtSingleValueToken("LT", "<"); KtSingleValueToken GT = new KtSingleValueToken("GT", ">"); KtSingleValueToken LTEQ = new KtSingleValueToken("LTEQ", "<="); KtSingleValueToken GTEQ = new KtSingleValueToken("GTEQ", ">="); KtSingleValueToken EQEQEQ = new KtSingleValueToken("EQEQEQ", "==="); KtSingleValueToken ARROW = new KtSingleValueToken("ARROW", "->"); KtSingleValueToken DOUBLE_ARROW = new KtSingleValueToken("DOUBLE_ARROW", "=>"); KtSingleValueToken EXCLEQEQEQ = new KtSingleValueToken("EXCLEQEQEQ", "!=="); KtSingleValueToken EQEQ = new KtSingleValueToken("EQEQ", "=="); KtSingleValueToken EXCLEQ = new KtSingleValueToken("EXCLEQ", "!="); KtSingleValueToken EXCLEXCL = new KtSingleValueToken("EXCLEXCL", "!!"); KtSingleValueToken ANDAND = new KtSingleValueToken("ANDAND", "&&"); KtSingleValueToken OROR = new KtSingleValueToken("OROR", "||"); KtSingleValueToken SAFE_ACCESS = new KtSingleValueToken("SAFE_ACCESS", "?."); KtSingleValueToken ELVIS = new KtSingleValueToken("ELVIS", "?:"); KtSingleValueToken QUEST = new KtSingleValueToken("QUEST", "?"); KtSingleValueToken COLONCOLON = new KtSingleValueToken("COLONCOLON", "::"); KtSingleValueToken COLON = new KtSingleValueToken("COLON", ":"); KtSingleValueToken SEMICOLON = new KtSingleValueToken("SEMICOLON", ";"); KtSingleValueToken DOUBLE_SEMICOLON = new KtSingleValueToken("DOUBLE_SEMICOLON", ";;"); KtSingleValueToken RANGE = new KtSingleValueToken("RANGE", ".."); KtSingleValueToken EQ = new KtSingleValueToken("EQ", "="); KtSingleValueToken MULTEQ = new KtSingleValueToken("MULTEQ", "*="); KtSingleValueToken DIVEQ = new KtSingleValueToken("DIVEQ", "/="); KtSingleValueToken PERCEQ = new KtSingleValueToken("PERCEQ", "%="); KtSingleValueToken PLUSEQ = new KtSingleValueToken("PLUSEQ", "+="); KtSingleValueToken MINUSEQ = new KtSingleValueToken("MINUSEQ", "-="); KtKeywordToken NOT_IN = KtKeywordToken.keyword("NOT_IN", "!in"); KtKeywordToken NOT_IS = KtKeywordToken.keyword("NOT_IS", "!is"); KtSingleValueToken HASH = new KtSingleValueToken("HASH", "#"); KtSingleValueToken AT = new KtSingleValueToken("AT", "@"); KtSingleValueToken COMMA = new KtSingleValueToken("COMMA", ",");
操作符优先级(Precedence)
优先级 | 标题 | 符号 |
---|---|---|
最高 | 后缀(Postfix ) |
++ , -- , . , ?. , ?
|
前缀(Prefix) |
- , + , ++ , -- , ! , labelDefinition @
|
|
右手类型运算(Type RHS,right-hand side class type (RHS) ) |
: , as , as?
|
|
乘除取余(Multiplicative) |
* , / , %
|
|
加减(Additive ) |
+ , -
|
|
区间范围(Range) | .. |
|
Infix函数 | 例如,给Int 定义扩展 infix fun Int.shl(x: Int): Int {...} ,这样调用 1 shl 2 ,等同于1.shl(2)
|
|
Elvis操作符 | ?: |
|
命名检查符(Named checks) |
in , !in , is , !is
|
|
比较大小(Comparison) |
< , > , <= , >=
|
|
相等性判断(Equality) |
== , \!==
|
|
与 (Conjunction) | && |
|
或 (Disjunction) | ll |
|
最低 | 赋值(Assignment) |
= , += , -= , *= , /= , %=
|
注:Markdown表格语法:ll
是||
。
为实现这些的操作符,Kotlin为二元操作符左侧的类型和一元操作符的参数类型,提供了相应的函数或扩展函数。
例如在kotlin/core/builtins/native/kotlin/Primitives.kt代码中,对基本类型Int的操作符的实现代码如下
public class Int private constructor() : Number(), Comparable<Int> { ... /** * Compares this value with the specified value for order. * Returns zero if this value is equal to the specified other value, a negative number if it's less than other, * or a positive number if it's greater than other. */ public operator fun compareTo(other: Byte): Int /** * Compares this value with the specified value for order. * Returns zero if this value is equal to the specified other value, a negative number if it's less than other, * or a positive number if it's greater than other. */ public operator fun compareTo(other: Short): Int /** * Compares this value with the specified value for order. * Returns zero if this value is equal to the specified other value, a negative number if it's less than other, * or a positive number if it's greater than other. */ public override operator fun compareTo(other: Int): Int /** * Compares this value with the specified value for order. * Returns zero if this value is equal to the specified other value, a negative number if it's less than other, * or a positive number if it's greater than other. */ public operator fun compareTo(other: Long): Int /** * Compares this value with the specified value for order. * Returns zero if this value is equal to the specified other value, a negative number if it's less than other, * or a positive number if it's greater than other. */ public operator fun compareTo(other: Float): Int /** * Compares this value with the specified value for order. * Returns zero if this value is equal to the specified other value, a negative number if it's less than other, * or a positive number if it's greater than other. */ public operator fun compareTo(other: Double): Int /** Adds the other value to this value. */ public operator fun plus(other: Byte): Int /** Adds the other value to this value. */ public operator fun plus(other: Short): Int /** Adds the other value to this value. */ public operator fun plus(other: Int): Int /** Adds the other value to this value. */ public operator fun plus(other: Long): Long /** Adds the other value to this value. */ public operator fun plus(other: Float): Float /** Adds the other value to this value. */ public operator fun plus(other: Double): Double /** Subtracts the other value from this value. */ public operator fun minus(other: Byte): Int /** Subtracts the other value from this value. */ public operator fun minus(other: Short): Int /** Subtracts the other value from this value. */ public operator fun minus(other: Int): Int /** Subtracts the other value from this value. */ public operator fun minus(other: Long): Long /** Subtracts the other value from this value. */ public operator fun minus(other: Float): Float /** Subtracts the other value from this value. */ public operator fun minus(other: Double): Double /** Multiplies this value by the other value. */ public operator fun times(other: Byte): Int /** Multiplies this value by the other value. */ public operator fun times(other: Short): Int /** Multiplies this value by the other value. */ public operator fun times(other: Int): Int /** Multiplies this value by the other value. */ public operator fun times(other: Long): Long /** Multiplies this value by the other value. */ public operator fun times(other: Float): Float /** Multiplies this value by the other value. */ public operator fun times(other: Double): Double /** Divides this value by the other value. */ public operator fun div(other: Byte): Int /** Divides this value by the other value. */ public operator fun div(other: Short): Int /** Divides this value by the other value. */ public operator fun div(other: Int): Int /** Divides this value by the other value. */ public operator fun div(other: Long): Long /** Divides this value by the other value. */ public operator fun div(other: Float): Float /** Divides this value by the other value. */ public operator fun div(other: Double): Double /** Calculates the remainder of dividing this value by the other value. */ @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING) public operator fun mod(other: Byte): Int /** Calculates the remainder of dividing this value by the other value. */ @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING) public operator fun mod(other: Short): Int /** Calculates the remainder of dividing this value by the other value. */ @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING) public operator fun mod(other: Int): Int /** Calculates the remainder of dividing this value by the other value. */ @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING) public operator fun mod(other: Long): Long /** Calculates the remainder of dividing this value by the other value. */ @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING) public operator fun mod(other: Float): Float /** Calculates the remainder of dividing this value by the other value. */ @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING) public operator fun mod(other: Double): Double /** Calculates the remainder of dividing this value by the other value. */ @SinceKotlin("1.1") public operator fun rem(other: Byte): Int /** Calculates the remainder of dividing this value by the other value. */ @SinceKotlin("1.1") public operator fun rem(other: Short): Int /** Calculates the remainder of dividing this value by the other value. */ @SinceKotlin("1.1") public operator fun rem(other: Int): Int /** Calculates the remainder of dividing this value by the other value. */ @SinceKotlin("1.1") public operator fun rem(other: Long): Long /** Calculates the remainder of dividing this value by the other value. */ @SinceKotlin("1.1") public operator fun rem(other: Float): Float /** Calculates the remainder of dividing this value by the other value. */ @SinceKotlin("1.1") public operator fun rem(other: Double): Double /** Increments this value. */ public operator fun inc(): Int /** Decrements this value. */ public operator fun dec(): Int /** Returns this value. */ public operator fun unaryPlus(): Int /** Returns the negative of this value. */ public operator fun unaryMinus(): Int /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Byte): IntRange /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Short): IntRange /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Int): IntRange /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Long): LongRange /** Shifts this value left by [bits]. */ public infix fun shl(bitCount: Int): Int /** Shifts this value right by [bits], filling the leftmost bits with copies of the sign bit. */ public infix fun shr(bitCount: Int): Int /** Shifts this value right by [bits], filling the leftmost bits with zeros. */ public infix fun ushr(bitCount: Int): Int /** Performs a bitwise AND operation between the two values. */ public infix fun and(other: Int): Int /** Performs a bitwise OR operation between the two values. */ public infix fun or(other: Int): Int /** Performs a bitwise XOR operation between the two values. */ public infix fun xor(other: Int): Int /** Inverts the bits in this value. */ public fun inv(): Int public override fun toByte(): Byte public override fun toChar(): Char public override fun toShort(): Short public override fun toInt(): Int public override fun toLong(): Long public override fun toFloat(): Float public override fun toDouble(): Double }
从源代码我们可以看出,重载操作符的函数需要用 operator
修饰符标记。中缀操作符的函数使用infix
修饰符标记。
一元操作符(unary operation)
前缀操作符
表达式 | 翻译为 |
---|---|
+a |
a.unaryPlus() |
-a |
a.unaryMinus() |
!a |
a.not() |
例如,当编译器处理表达式 +a
时,它将执行以下步骤:
- 确定
a
的类型,令其为T
。 - 为接收者
T
查找一个带有operator
修饰符的无参函数unaryPlus()
,即成员函数或扩展函数。 - 如果函数不存在或不明确,则导致编译错误。
- 如果函数存在且其返回类型为
R
,那就表达式+a
具有类型R
。
编译器对这些操作以及所有其他操作都针对基本类型做了优化,不会引入函数调用的开销。
以下是如何重载一元减运算符的示例:
package com.easy.kotlin class OperatorDemo { } data class Point(val x: Int, val y: Int) operator fun Point.unaryMinus() = Point(-x, -y)
测试代码:
package com.easy.kotlin import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class OperatorDemoTest { @Test fun testPointUnaryMinus() { val p = Point(1, 1) val np = -p println(np) //Point(x=-1, y=-1) } }
递增和递减
表达式 | 翻译为 |
---|---|
a++ |
a.inc() 返回值是a
|
a-- |
a.dec() 返回值是a
|
++a |
a.inc() 返回值是a+1
|
--a |
a.dec() 返回值是a-1
|
inc()
和 dec()
函数必须返回一个值,它用于赋值给使用
++
或 --
操作的变量。
编译器执行以下步骤来解析后缀形式的操作符,例如 a++
:
- 确定
a
的类型,令其为T
。 - 查找一个适用于类型为
T
的接收者的、带有operator
修饰符的无参数函数inc()
。 - 检查函数的返回类型是
T
的子类型。
计算表达式的步骤是:
- 把
a
的初始值存储到临时存储a_
中 - 把
a.inc()
结果赋值给a
- 把
a_
作为表达式的结果返回
( a--
同理分析)。
对于前缀形式 ++a
和 --a
解析步骤类似,但是返回值是取的新值来返回:
- 把
a.inc()
结果赋值给a
- 把
a
的新值a+1
作为表达式结果返回
( --a
同理分析)。
二元操作符
算术运算符
表达式 | 翻译为 |
---|---|
a + b |
a.plus(b) |
a - b |
a.minus(b) |
a * b |
a.times(b) |
a / b |
a.div(b) |
a % b |
a.rem(b) 、 a.mod(b)
|
a..b |
a.rangeTo(b) |
代码示例
>>> val a=10 >>> val b=3 >>> a+b 13 >>> a-b 7 >>> a/b 3 >>> a%b 1 >>> a..b 10..3 >>> b..a 3..10
字符串的+
运算符重载
先用代码举个例子:
>>> ""+1 1 >>> 1+"" error: none of the following functions can be called with the arguments supplied: public final operator fun plus(other: Byte): Int defined in kotlin.Int public final operator fun plus(other: Double): Double defined in kotlin.Int public final operator fun plus(other: Float): Float defined in kotlin.Int public final operator fun plus(other: Int): Int defined in kotlin.Int public final operator fun plus(other: Long): Long defined in kotlin.Int public final operator fun plus(other: Short): Int defined in kotlin.Int 1+"" ^
从上面的示例,我们可以看出,在Kotlin中1+""
是不允许的(这地方,相比Scala,写这样的Kotlin代码就显得不大友好),只能显式调用toString
来相加:
>>> 1.toString()+"" 1
自定义重载的 +
运算符
下面我们使用一个计数类 Counter 重载的 +
运算符来增加index的计数值。
代码示例
data class Counter(var index: Int) operator fun Counter.plus(increment: Int): Counter { return Counter(index + increment) }
测试类
package com.easy.kotlin import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class OperatorDemoTest @Test fun testCounterIndexPlus() { val c = Counter(1) val cplus = c + 10 println(cplus) //Counter(index=11) } }
in 操作符
表达式 | 翻译为 |
---|---|
a in b |
b.contains(a) |
a !in b |
!b.contains(a) |
索引访问操作符
表达式 | 翻译为 |
---|---|
a[i] |
a.get(i) |
a[i] = b |
a.set(i, b) |
方括号转换为调用带有适当数量参数的 get
和 set
。
调用操作符
表达式 | 翻译为 |
---|---|
a() |
a.invoke() |
a(i) |
a.invoke(i) |
圆括号转换为调用带有适当数量参数的 invoke
。
计算并赋值
表达式 | 翻译为 |
---|---|
a += b |
a.plusAssign(b) |
a -= b |
a.minusAssign(b) |
a *= b |
a.timesAssign(b) |
a /= b |
a.divAssign(b) |
a %= b |
a.modAssign(b) |
对于赋值操作,例如 a += b
,编译器会试着生成 a = a + b
的代码(这里包含类型检查:a + b
的类型必须是 a
的子类型)。
相等与不等操作符
Kotlin 中有两种类型的相等性:
- 引用相等
===
!==
(两个引用指向同一对象) - 结构相等
==
!=
( 使用equals()
判断)
表达式 | 翻译为 |
---|---|
a == b |
a?.equals(b) ?: (b === null) |
a != b |
!(a?.equals(b) ?: (b === null)) |
这个 ==
操作符有些特殊:它被翻译成一个复杂的表达式,用于筛选 null
值。
意思是:如果 a 不是 null 则调用 equals(Any?)
函数并返回其值;否则(即 a === null
)就计算 b === null
的值并返回。
当与 null 显式比较时,a == null
会被自动转换为 a=== null
注意:===
和 !==
不可重载。
Elvis 操作符 ?:
在Kotin中,Elvis操作符特定是跟null比较。也就是说
y = x?:0
等价于
val y = if(x!==null) x else 0
主要用来作null
安全性检查。
Elvis操作符 ?:
是一个二元运算符,如果第一个操作数为真,则返回第一个操作数,否则将计算并返回其第二个操作数。它是三元条件运算符的变体。命名灵感来自猫王的发型风格。
Kotlin中没有这样的三元运算符 true?1:0
,取而代之的是if(true) 1 else 0
。而Elvis操作符算是精简版的三元运算符。
我们在Java中使用的三元运算符的语法,你通常要重复变量两次, 示例:
String name = "Elvis Presley"; String displayName = (name != null) ? name : "Unknown";
取而代之,你可以使用Elvis操作符。
String name = "Elvis Presley"; String displayName = name?:"Unknown"
我们可以看出,用Elvis操作符(?:)可以把带有默认值的if/else结构写的及其短小。用Elvis操作符不用检查null(避免了NullPointerException
),也不用重复变量。
这个Elvis操作符功能在Spring 表达式语言 (SpEL)中提供。
在Kotlin中当然就没有理由不支持这个特性。
代码示例:
>>> val x = null >>> val y = x?:0 >>> y 0 >>> val x = false >>> val y = x?:0 >>> y false >>> val x = "" >>> val y = x?:0 >>> y >>> val x = "abc" >>> val y = x?:0 >>> y abc
比较操作符
表达式 | 翻译为 |
---|---|
a > b |
a.compareTo(b) > 0 |
a < b |
a.compareTo(b) < 0 |
a >= b |
a.compareTo(b) >= 0 |
a <= b |
a.compareTo(b) <= 0 |
所有的比较都转换为对 compareTo
的调用,这个函数需要返回 Int
值
用infix函数自定义中缀操作符
我们可以通过自定义infix函数来实现中缀操作符。
代码示例
data class Person(val name: String, val age: Int) infix fun Person.grow(years: Int): Person { return Person(name, age + years) }
测试代码
package com.easy.kotlin import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class InfixFunctionDemoTest { @Test fun testInfixFuntion() { val person = Person("Jack", 20) println(person.grow(2)) println(person grow 2) } }
输出
Person(name=Jack, age=22) Person(name=Jack, age=22)