关键字
lateinit :延迟初始化
lateinit var a : String
a = "hello"
println(" lateinit a = $a");
单一抽象方法,可以使用lambda表达式,无需重写方法,直接在大括号中写对应的实现即可。
fun interface SayHello{
fun say(str:String):String
}
fun testSam(){
//普通写法
var str = object : SayHello {
override fun say(str: String): String {
println("$str")
return str;
}
}
//lambda 表达式写法
var str2 = SayHello {
println("$it")
return@SayHello it;
}
str.say("你好")
str2.say("kotlin")
}
拓展函数:直接给一个类后面增加点号和一个函数,就能够在别的地方进行调用这个函数。
拓展函数不会修改原来的类,只是通过点号表达式去调用这个方法。调用拓展函数只取决于函数调用时表达式的类型来决定。
如果成员函数和扩展函数相同,那么优先调用成员函数。
fun MutableList<Int> .swap(i1:Int,i2:Int){
val tmp = this[i1];
this[i1] = this[i2];
this[i2] = tmp;
}
fun testExpand(){
val list = mutableListOf<Int>(1,2,3,4)
list.swap(0,3);
println(list)
}
open class Shape
class Rectangle: Shape()
fun Shape.getName() = "Shape"
fun Rectangle.getName() = "Rectangle"
fun printClassName(s: Shape) {
println(s.getName())
}
printClassName(Rectangle())//会打印 Shape,因为调佣扩展函数时,类型时shape
扩展属性:可以一个类增加属性。但是并没有改变原来的类,只是可以通过点号计算对应的属性。只能显示提供setter、getter,而不能使用构造器。
val <T> List<T>.lastIndext:Int
get()= size-1;
var list = listOf<Int>(11,2,3,4,54)
println(list.lastIndext)
伴生对象也可以使用扩展函数和扩展属性。
class MyClass {
companion object { } // 将被称为 "Companion"
}
fun MyClass.Companion.printCompanion() { println("companion") }
fun main() {
MyClass.printCompanion()
}
扩展函数的作用域在当前包里面,如果在其他包里需要引用
package org.example.declarations
fun List<String>.getLongestString() { /*……*/}
package org.example.usage
import org.example.declarations.getLongestString
fun main() {
val list = listOf("red", "green", "blue")
list.getLongestString()
}
扩展声明为成员
声明为成员的扩展可以声明为 open 并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。
open class Base { }
class Derived : Base() { }
open class BaseCaller {
open fun Base.printFunctionInfo() {
println("Base extension function in BaseCaller")
}
open fun Derived.printFunctionInfo() {
println("Derived extension function in BaseCaller")
}
fun call(b: Base) {
b.printFunctionInfo() // 调用扩展函数
}
}
class DerivedCaller: BaseCaller() {
override fun Base.printFunctionInfo() {
println("Base extension function in DerivedCaller")
}
override fun Derived.printFunctionInfo() {
println("Derived extension function in DerivedCaller")
}
}
fun main() {
BaseCaller().call(Base()) // “Base extension function in BaseCaller”
DerivedCaller().call(Base()) // “Base extension function in DerivedCaller”——分发接收者虚拟解析
DerivedCaller().call(Derived()) // “Base extension function in DerivedCaller”——扩展接收者静态解析
}
密封类:要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明,密封类是抽象的,不能实例化,密封类的间接继承者可以不用在一个文件里面。
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
密封列比较好使用when表达式
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}
类型投影:Array对应于 Java 的Array<? super String>
声明处型变:Array对应于 Java 的 Array<? extends Object>
内部类:
标记为 inner 的嵌套类能够访问其外部类的成员。内部类会带有一个对外部类的对象的引用
匿名内部类
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { …… }
override fun mouseEntered(e: MouseEvent) { …… }
})
枚举
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
伴生对象:
类内部的对象声明可以用 companion 关键字标记:该伴生对象的成员可通过只使用类名作为限定符来调用.可以省略伴生对象的名称,在这种情况下将使用名称 Companion即使伴生对象的成员看起来像其他语言的静态成员,在运行时他们仍然是真实对象的实例成员
如果使用 @JvmStatic 注解,你可以将伴生对象的成员生成为真正的静态方法和字段。
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
class MyClass {
companion object { }
}
val x = MyClass.Companion
内联类 的特殊类,它通过在类的前面定义一个 inline 修饰符来声明,内联类必须含有唯一的一个属性在主构造函数中初始化.
委托:委托模式已经证明是实现继承的一个很好的替代方式, 而 Kotlin 可以零样板代码地原生支持它。
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
Derived 的超类型列表中的 by-子句表示 b 将会在 Derived 中内部存储, 并且编译器将生成转发给 b 的所有 Base 的方法。委托对象的成员只能访问其自身对接口成员实现.
属性委托:属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(与 setValue()——对于 var 属性)
class Example {
var p: String by Delegate()
}
标准委托
- lazy()是接受一个 lambda 并返回一个
Lazy <T>实例的函数,返回的实例可以作为实现延迟属性的委托
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main() {
println(lazyValue)
println(lazyValue)
}
-
Delegates.observable() 接受两个参数:初始值与修改时处理程序(handler)。 每当我们给属性赋值时会调用该处理程序(在赋值后执行)。它有三个参数:被赋值的属性、旧值与新值
class User { var name: String by Delegates.observable("<no name>") { prop, old, new -> println("$old -> $new") } } fun main() { val user = User() user.name = "first" user.name = "second" }委托给另一个属性:为将一个属性委托给另一个属性,应在委托名称中使用恰当的
::限定符,例如,this::delegate或MyClass::delegate。class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) { var delegatedToMember: Int by this::memberInt var delegatedToTopLevel: Int by ::topLevelInt val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt } var MyClass.extDelegated: Int by ::topLevelInt局部函数:Kotlin 支持局部函数,即一个函数在另一个函数内部,局部函数可以访问外部函数(即闭包)的局部变量,所以在上例中,visited 可以是局部变量
fun dfs(graph: Graph) { val visited = HashSet<Vertex>() fun dfs(current: Vertex) { if (!visited.add(current)) return for (v in current.neighbors) dfs(v) } dfs(graph.vertices[0]) }高阶函数:高阶函数是将函数用作参数或返回值的函数。
集合:使用的时候再来查。
内置函数let、also、with、run、apply
let 可以使用it代替当前队形,并且返回最后一行表达式结果。
also 可以使用it代替当前对象,返回当前对象。
with 调用对象的时候省略对象名称, 返回最后一行表达式。
run 可以直接调用方法、属性。返回最后一行表达式。
apply 直接调用属性和方法,返回对象。