class 类名 类头(指定类型参数、主构造函数)类体
Class members
classes can contain
constructors and initializer blocks
functions
properties
nested and inner classes
object declarations
As we mentioned before, we stick to making things explicit in kotlin, and unlike Java, kotlin requires explicit modifiers for overridable members(we call them open)
Classes and inheritance
inheritance
overriding methods
overriding properties
derived class initialization order
overriding rules
Companion objects static in Java/C#
Properties and fields
the full syntax for declaring property is
var [: ] [= ] [] []
the full syntax of a read-only property differs from a mutable one in two ways: it starts with val instead of var and does not allow a setter:
val simple: Int?
扩展函数是静态解析的 what does this mean? get
注解
注解声明
注解是将元数据附加到代码的方法。要声明注解,请将annotation修饰符放在类的前面:
annotation class Facy
注解的附加属性可以通过用元注解标注注解类来指定:
- @Target 指定可以用该注解的元素的可能的类型(类、函数、属性、表达式等)
- @Retention指定该注解是否存储在编译后的class文件中,以及在它运行时能否通过反射可见
作用域函数
The kotlin standard library contains serveral functions whose sole purpose is to execute a block of code within the context fo an object. When you call such a function on an object with a lambda experssion provided,it forms a temporary scope. In this scope,you can access the object without its name. such funtions are called scope functions. There are five of them: let, run, with, apply, and also.
Basically,these functions do the same: execute a block of code on an object.what's different is how this object becomes available inside the block and what is the result of the whole expression.
here is a typical usage of scope function:
Person("Alice", 20, "Amsterdam").let {
println(it)
it.moveTo("London")
it.incrementAge()
println(it)
}
if you write the same without let,you'll have to introduce a new variable and repeat its name whenever you use it.
val alice = Person("Alice", 20, "Amsterdam")
println(alice)
alice.moveTo("London")
alice.incrementAge()
println(alice)
The scope functions do not introduce any new technical capabilities, but they can make you code more concise and readable.
Due to the similar nature of scope functions, choosing the right one for your case can be a bit tricky. The choice mainly depends on your intent and the consistency of use in your project.
Below we'll provide detailed descriptions of the distinctions between scope functions and the convertions on their usage.
区别
Because the scope functions are all quite similar in nature, it's inportant to understand the differences between them. There are two main differences between each scope function:
- The way to refer to the context object
- The return value
上下文对象:this还是it
Inside the lambda of a scope function, the context object is available by a short reference instead of its actual name.Each scope function uses one of two ways to access the context object:as a lambda receiver(this) or as a lambda argument(it).Both provide the same capabilities, so we'll describe the pros and cons of each for different cases and provide recommendations on their use.
fun main() {
val str = "Hello"
//this
str.run {
println("The receiver string length: $length")
// println("The receiver string length: ${this.length}) // does the same
}
//it
str.let {
print("The receiver string's length is ${it.length}")
}
}
当lambda表达式用在 调用他的函数和赋值属性的情况下,推荐this
当对象被用来当作函数的变量时,it 是较好的
返回值
apply and also 返回上下文对象
let run with 返回lambda表达式结果
val numberList = mutalbeListOf()
numberList.also { println("Populating the list") }
.apply{
add(1.23)
add(3.14)
add(2.0)
}
.also { println("Sorting the list") }
.sort()
他们也可以用作返回值
let, run, and with 返回lambda表达式结果,所以,你可以用他们把他们赋值给变量。在结果上链式调用
val numbers = mutalbeListOf("one", "two", "three")
val countEndWithE = number.run {
add("four")
add("five")
count { it.endsWith("e") }
}
println("There are $countEndsWithE elements that end with e.")
并且,你可以忽略返回值,使用作用域函数创建临时变量。
let
The context object is available as an argument(it).The return value is the lambda result.
let can used to invoke one or more functions on results of call chains. For example, the following code prints the results of two operations on a collection:
val numbers = mutalbeListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)
用let你可以这样写
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3}.let {
println(it)
//and more function calls if need
}
如果代码块包含单个函数,使用it作为变量,你可以使用方法引用(::)代替lambda表达式
let常用来执行只包含非空值的代码块。
with
推荐使用with,调用上下文对象函数,但是不提供lambda表达式结果。with可以解读为:with this object, do the following.
val numbers = mutableListOf("one", "two", "three")
with(number) {
println(" 'with' is called with argument $this")
println("It contains $size elements")
}
run
The context object is available as a receiver (this).The return value is the lambda result.
run does the same as with but invoke as let - as an extension function of the context object.
val service = MultiprotService("https://example.kotlinlang.org", 80)
val result = service.run {
port = 8080
query(prepareRequest() + "to prot $prot")
}
// the same code written with let() function
val letResult = servuce.let {
it.port = 8080
it.query(it.prepareRequest() + " to port ${it.port}}")
}
apply
The context object is available as a receiver(this),The return value is the object itself.
apply常用在对象配置。这种调用可以read as “应用以下赋值给这个对象”
val adam = Person("Adam").apply {
age = 32
city = "London"
}
also
The context object is available as an argument(it).The return value is the object itself.
also is good for performing some actions that take the context object as an argument. Use also for additional actions that don't alter the object,such as logging or printling debug information.
when you see also in your code, you can read it as "and also do the following".
val number = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")
函数选择
. 执行lambda表达式在非空对象 :let
. 在本地作用域引进表达式作为一个变量: let
. 对象配置 :apply
. 对象配置并计算结果 :run
. 在需要表达式的地方需要执行声明 : run
. 额外的效果 : also
. 在一个对象上调用成组的函数: with
takeIf与takeUnless
fun displaySubstringPosition(input: String, sub: Strnig) {
input.indexOf(sub).takeIf{ it >= 0 }?.let {
println("The substring $sub is found in $niput.")
println("Its start position is $it.")
}
}
displaySubstringPosition("010000011", "11")
displaySubstringPostion("010000011", "12")