Kotlin 快速入门

268 阅读8分钟

kotlin 基础语法

Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。

一门新的面向对象的编程语言无外乎都是这些的东西

1.基础语法 包含包的导入 类型申明 关键字 合法标识符 ...

2.基本类型  

3.条件控制  

4.循环控制

5.类和对象

6.面向对象语言的编程技巧和思想,离不开 抽象. 封装. 继承. 多态 

kotlin 文件以 ==.kt== 为文件结尾

包的申明和导包

    //导包和java一样的
    pakage com.xx.xx
    
    improt android.content.Context 

注释

    kotlin 和java  一样
    
    //  单行注释
    
    /**
     *  多行
     *  注释
     */
     

常量与变量的定义

    kotlin  可变量关键字  "var"  不可变量 关键字 "val"  常量关键字 "const"
    
    结构  var <标识符>: <类型> = <初始值>
    结构  val <标识符>: <类型> = <初始值>
    
    var a: Int = 1
    var conext: Context?    //问号代表可为 null 
    var b = 2.0f            // 自动推断b 为Float 类型
    var c: Int          // 申明 的时候不进行初始化,必须显示类型
    
    val d:Int
    d = 2                   // 只能初始化一次
    
    "const" 声明常量 只允许在Top-Level 中(也就是归属于 文件内)和 object 声明的类中使用。
    类似java中的 public static final String TAG = "tag" 
    
    
    
    
    *********************** a.kt文件开始************************
    
    const val TAG ="tag"  // Top-Level
    
    object AA{
        const  val MY_PI = 3.14159
        
        fun print(s:String){
            Log.e(TAG,s)
        }
    }
    
    class BB{
        
        // 不可申明  const val  xx = xx 
        
    }
    ********************* a.kt文件结束*************************
    

字符串模板

    "$xx" 符号表示变量的名或值 
    var a = 1
    var s = " a is  $a "   // 结果 a is  1 
    
    "${函数、表达}" 表示函数返回值或者表达式的值
    var m = "${s.replace("is","value")} " // 结果  a value 1 
    

空检查机制

    var age:String? = "18"
 
    age = null 
    var result = age!!.toInt() // 运行时报错,控制针
    var result = age?.toInt() // 不会报异常,result = null 
    
    //若果 这样声明  
    var result: Int   // result 是非空类型
    result = age?.toInt() // 编译期报错,有利于编写高质量代码
    
    var result:Int? // result 是可空类型
    result = age?.toInt() 

数据类型

kotlin 类型kotlin 位宽java 类型java 包装类型java 位宽
Double64doubleDouble64
Float32floatFloat32
Long64longLong64
Int32intInt32
Short16shortShort16
Byte8byteByte8

Boolean   中取值 true/ false

Char  kotlin 与java 中的区别是,char 不能和 数字直接操作,需要显示转换为Int 类型

Char型值加、减一个 整型值:Kotlin会先将该Char型值对应的字符编码进行加、减该整数,然后将计算结果转换为Char型值。
两个Char型值进行相减:Kotlin将用两个Char型值对应的字符编码进行减法运算,最后返回Int类型的值。两个Char型值不能相加。


var m:Char ='A'
var n:Char ='B'

val c =m+n // 报错
val c=m+n.toInt() // Ok (Char 类型中 对 + 进行了重载只能 和整数相加)
val c=m+n.toFloat() //错误 
val c =m - n  // OK   C 为Int 


每种数据类型都有下面的这些方法,可以转化为其它的类型:
toByte(): Byte

toShort(): Short

toInt(): Int

toLong(): Long

toFloat(): Float

toDouble(): Double

toChar(): Char

// 这些方法都是Number 类型中的抽象方法, Double,Float 等都是继承Number


类型转换


Kotlin中FloatDouble之间需要进行显式转换,浮点型 与整型,整型与整型之间也要进行显式转换。

将Double类型或Float类型的值、变量或常量转换为整型时,浮点值的小数部分会被截断。

当进行类型转换时,应尽量向表数范围大的数据类型转换,这样程序会更加安全。

表达式类型的自动提升
当一个算术表达式中包含多个数值型的值时,整个算术表达式的数据类型将发生自动提升。(与Java基本相似的自动提升规则)

所有的ByteShort类型将被提升到Int类型
整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型。

    var b: Byte = 40
    var c: Short = 97
    var i: Int = 23
    var d: Double = 0.314

    val result = b + c + i * d  //result 是Double 类型
    

"is" 关键字
    1.判断是 A 是否是某种类型,或者属于某种类型
    2.类似java 中的 instanceof
    
	println("abc" is String)  // true
    println("abc" !is String) // false

    println(null is Any)      // fase
    println(null is Any?)     // true
    

    
"as" 关键字 强制类行转换

val manager = context.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager

条件控制

    1. "if 表达式"
    
    var a = 10 
    var b = 20
    val max = if( a>b) a else b   // 类似于 java 中的三目运算   (a>b)? a : b
    
    
    2. "when 表达式" (类似 java switch  casevar x :Int? =10
    
    when(x){
    
        1->{ printf("x==1") }
        2->{printf("x==2") }
        in 3..10 -> { }
        else->{
            ....
        }
        
    }



    var a:Any?  
    
    when(a){
        is Boolean ->{ }
        is String ->{ }
        else -> { }
    }
    

kotlin 循环控制


Note: kotlin 中的 List, Map ,Set    以Mutable为前缀的代表是可变长的

例如:
    val a :MutableList<Int> = mutableListof(1,2,3)
    
    a.add(4)    // 可行
    a.remove(1)  // 可行
    
    val b:List<Int> = listof(1,2,3) // 长度只能是 3 
    
 
1、for 循环可以对任何提供迭代器(iterator)的对象进行遍历,语法如下:

for (item in collection) print(item)

如果你想要通过索引遍历一个数组或者一个 list

val m:MutableList<Int> = mutableListOf(1,2,3,4) 

 for (i in m.indices){
      print("i--$i  value --${m[i]}")
 }

 for (i in m.withIndex()){
    print("i--$i  value --${m.get($}")
 }

 通过forEach 循环
 
 m.forEach{
    print(" $it ")
 }

对Map 循环遍历
val m : HashMap<Int,Int>f = mapOf(1 to 1, 2 to 2, 3 to 3 )
// mapOf( Pair(1,1) , Pair(2,2) ,  Pair(3,3) )

for( (k,v) in m){
    print("k--$k  v --$v")
}

m.forEach{
    k,v->  print("k--$k  v --$v")
}


正常循环:
for (i in 1..4) print(i) // 打印结果为: "1234

如果你需要按反序遍历整数可以使用标准库中的 downTo() 函数:
for (i in 4 downTo 1) print(i) // 打印结果为: "4321" 也支持指定步长:

for (i in 1..4 step 2) print(i) // 打印结果为: "13"

for (i in 4 downTo 1 step 2) print(i) // 打印结果为: "42"

如果循环中不要最后一个范围区间的值可以使用 until (左闭右开)函数:
for (i in 1 until 10) { // i in [1, 10), 不包含 10
     println(i)
}


kotlin 中的函数

kotlin 中的函数用 "fun" 关键字声明

fun  add( x: Int , y: Int) : Int {
    return x+y
}

参数是以 <参数名>:<类型> 格式指定的,函数中的参数类型必须显示指定

可以简写为 单表达式函数

fun add(x:Int, y: Int) = x + y 
返回Unit的函数

如果一个函数不返回任何有用的值,那么它的返回值是Unit,这个值不需要显式返回,就是可以省略 (类似java 中的 ==void==)

    fun printHello(str: String? ): Unit {
        
        if(str!=null)   println(str)   else   printlv("str is null ")
        return  Unit
    }
    
    或者
     fun printHello(str: String? )  {
        
        if(str!=null) println(str) else printlv("str is null ")
        //return  Unit
     }

可变长参数

函数的参数(通常是最后一个)可以用 vararg 修饰符标记( 类似Java中的 ==...== )

kotlin:

  fun printSome(   vararg   ints: Int) {
      ints.forEach(::println)
  }
  
  printSome(1,2,3,4,5)


java:
    
 public void printSome( Int...  ints){
    ...
 }

默认参数

函数参数可以有默认值,当省略相应的参数时使用默认值。这可以减少重载数量。 默认值通过类型后面的 = 及给出的值来定义。


fun reformat(str: String,
             normalizeCase: Boolean = true,
             upperCaseFirstLetter: Boolean = true,
             divideByCamelHumps: Boolean = false,
             wordSeparator: Char = ' ') {
    /*……*/
}

//使用默认参数调用
refromat("ab_cd")

// 参数全部调用
reformat("ab_cd" ,
        false,
        false,
        true,
        "_"
    )

//或者 可读性更好
    reformat(
        "ab_cd",
        normalizeCase = false,
        upperCaseFirstLetter = false,
        divideByCamelHumps = true,
        wordSeparator = "_"
        )
        
// 我只需要用到两个参数的时候 
    
    reformat(
    "ab_cd",
     upperCaseFirstLetter =false 
    )



高阶函数

Kotlin 函数都是==头等公民==,这意味着==它们可以存储在变量与数据结构中、作为参数传递给其他高阶函数以及从其他高阶函数返回==。可以像操作任何其他非函数值一样操作函数。 为促成这点,作为一门静态类型编程语言的 Kotlin 使用一系列==函数类型==来表示函数并提供一组特定的语言结构,例如 lambda 表达式。 简单点==高阶函数就是以函数作为参数或者返回值的函数==


// 函数作为变量
 val aa:  ()->Unit ={ printf("-aa-->") }

 val bb: ()->Unit  ={ printf("-bbb-->") }
 // 匿名函数作为变量
 val aa6 = fun(x: Int, y: Int): Int { return x + y }
 // 函数保存在 容器当中
 val arry: ArrayList< ()->Unit >  = arrayListOf(aa,bb)
 
  • 函数类型

//定义一个简单的高阶函数:  函数类型的参数 (当然可以有多个函数类型的参数)
fun twoAndThree (operation: (Int, Int) -> Int) {
    val result = operation(2,3)
  //  val result = operation.invoke(2,3)  等同于上面写法
    println("result is $result")
}

twoAndThree{ a,b -> a + b }  // result is 5
twoAndThree{ a, b -> a * b} // result is 6
//operation 这是个参数类型为函数类型 (Int,Int)->Int 


  • 函数类型的表示

    () -> Unit // 无参无返

    () -> A // 无参有返

    (A) -> Unit // 有参无返回

    (A,B) -> c // 有参有返回

    A.(B)->C // 带有接收者的函数类型 类似给A 类型定义了一个扩展函数

如需将函数类型指定为可空,请使用圆括号:((Int, Int) -> Int)?。

函数类型可以使用圆括号进行接合:(Int) -> ((Int) -> Unit)

箭头表示法是右结合的,(Int) -> (Int) -> Unit 与前述示例等价,但不等于 ((Int) -> Int) -> Unit。

  • 函数类型的 实例化

1.用Lambda表达式赋值

var add1 : (Int, Int) -> Int = {a : Int, b : Int -> a + b}

2.用匿名函数赋值

var add2 : (Int, Int) -> Int = fun(x,y) :Int {
 return   x+y
}

3.用已声明的函数辅助

fun add(a:Int, b:Int) : Int ={return a+b}

var add3: (Int, Int) -> Int  = :: add 
// 如果 add 定义在 AA 类中  ,那么获取的时候   AA::add
// 如果 add 定义在 文件中,那么获取的时候   ::add

4.用函数类型变量

var add : (Int, Int) -> Int = {a : Int, b : Int -> a + b}

// 将已经定义好的函数类型变量重新赋值给 另外一个函数类型明亮
var add4 : (Int, Int) -> Int = add

5.函数类型 派生类 : 函数类型可以看做一个接口 , 类可以实现该接口 , 在实现类中实现具体的函数操作 , 该 函数类型接口的实现类 , 可以赋值给函数类型变量

class AddOperation : (Int, Int) -> Int{
    override fun invoke(p1: Int, p2: Int): Int {
        return p1 + p2
    }
}

// 将 函数类型 接口派生类对象赋值给 函数类型变量
var add5 : (Int, Int) -> Int = AddOperation()

  • 函数类型的 调用
  1. invoke 调用 : 可以通过 函数类型变量名.invoke(参数列表) 调用该函数 ;

  2. 直接调用 : 也可以通过 函数类型变量名(参数列表) 直接调用该函数 , 将该变量名称当做函数名称来使用 ;

类可以包含:

 构造函数与初始化块
 
 函数
 
 属性
 
 嵌套类与内部类
 
 对象声明

 类的继承
 
  • 类声明

kotlin 声明类由 ==class== 关键字来声明,类声明由类名、类头(指定其类型参数、主构造函数等)以及由花括号包围的类体构成。类头与类体都是可选的; 如果一个类没有类体,可以省略花括号。

class Invoice { /*……*/ }

calss Empty  

  • 构造函数

在 Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。 主构造函数是类头的一部分:它跟在类名(与可选的类型参数)后。

class Person  constructor(firstName: String) { /*……*/ }

如果主构造函数没有任何注解或者可见性修饰符, 关键字 ==constructor== 可以省略

class Person(firstName: String) { /*……*/ }

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

在实例初始化期间,初始化块按照它们出现在类体中的顺序执行:

class InitOrderDemo(name: String) {
//1
    val firstProperty = "First property: $name".also(::println)
//2  
    init {
        println("First initializer block that prints ${name}")
    }
//3
    val secondProperty = "Second property: ${name.length}".also(::println)
//4
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

Note: 跟java  static{} 代码块儿不一样的

声明属性 和初始化可直接在主构造器中

class Person(val firstName: String, val lastName: String, var age: Int) { /*……*/ }


等同于
class Person( a:String, b:String, c:Int){
    
    val firstName = a
    val lastName = b
    var age = c
    
    ...
    
}




次构造函数

类也可以声明前缀有 ==constructor==的次构造函数:

class Person {
    var children: MutableList<Person> = mutableListOf<>()
    
    constructor(parent: Person) {
    
        parent.children.add(this)
        
    }
}

如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字

// 有主构造函数
class Person(val name: String) {
    var children: MutableList<Person> = mutableListOf<>()
    
    // 直接委托主构造函数
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

如果一个非抽象类没有声明任何(主或次)构造函数,它会有一个生成的不带参数的主构造函数。构造函数的可见性是 public。如果你不希望你的类有一个公有构造函数,你需要声明一个带有非默认可见性的空的主构造函数:


class DontCreateMe private constructor () { /*……*/ }

Note: 可见性修饰符 Kotlin 中有这四个可见性修饰符:==private==、 ==protected==、 ==internal== 和 ==public==。 如果没有显式指定修饰符的话,默认可见性是 public。 在文件中进行声明的:

// 文件名:example.kt
package foo

private fun baz() { …… }  
class Bar { …… }

var  name = "TAG"

public  -->     这意味着你的声明将随处可见;(没有显示申明默认  public 可见性)
private -->     它只会在声明它的文件内可见;
internal -->     它会在相同模块内随处可见;  (模块:一个项目, 编译在一起的一套Kotlin 文件)
protected -->    不适用于顶层声明;

类中进行声明的:

open class Outer {
   private val a = 1
   protected open val b = 2
   internal val c = 3
   val d = 4  // 默认 public
   
   protected class Nested {
       public val e: Int = 5
   }
}

private -->   意味着只在这个类内部(包含其所有成员)可见;
protected-->   本类和 在子类中可见;
internal --> 能见到类声明的 本模块内 的任何客户端都可见其 internal 成员;
public-->  能见到类声明的任何客户端都可见其 public 成员;

++在Kotlin 中,外部类不能访问内部类的 private 成员。++

  • 类的创建实例

跟调用普通函数一样(不存在 类似java中 new 关键字的)

val invoice = Invoice()

val customer = Customer("Joe Smith")

kotlin中是所有类的超类 ==Any== (类似java 中的 ==Object== 类) kotlin 默认的类是不能被继承的, 需要用关键字==open== 去标识

// 不可被继承
class Base(){/***/} 

open class Base(){/**/}

class BaseImplement :Base(){ /***/}

如果派生类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数:


class MyView : View {
    constructor(ctx: Context) : super(ctx)

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
    
    // 默认参数去简化操作 
  //  constructor( ctx:Context , attrs : AttributeSet?= null) :super( ctx, attrs)
  
}

覆盖的方法必须是开放的==open== 修饰的,覆盖的函数需要在函数前用 ==override==关键字修饰

open class Shape {
    open fun draw() { /*……*/ }
    fun fill() { /*……*/ }
}

class Circle() : Shape() {
    override fun draw() { /*……*/ }
}

  • 数据类

我们经常创建一些只保存数据的类。在 Kotlin 中,这叫做 数据类 并用==data==标记 (java 中习惯命名这些类为xxBean,xxEntity)

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

编译器自动根据主构造函数中的参数生成下面的方法

  1. equal() / hashCode()

  2. toString() // 格式 User(name="xx",age=xx)

  3. copy()

  4. componentN // componet1 .. componentN 取决于参数的多少

数据类有以下要求

  1. 主构造函数必须 至少有一个参数3

  2. 主构造函数中所有的参数需要 ==var== ==val== 标记

  • 密封类

官方定义:密封类用来表示受限的类继承结构:当一个值为有限几种的类型、而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。

要声明一个密封类,需要在类名前面添加 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` 子句,因为我们已经覆盖了所有的情况
}



  • 枚举类

枚举类最基本的用法是实现一个类型安全的枚举。 枚举常量用逗号分隔,每个枚举常量都是一个对象。 每一个枚举都是枚举类的实例,它们可以被初始化

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

  • 对象申明和对象表达式

Kotlin 用对象表达式和对象声明来实现创建一个对某个类做了轻微改动的类的对象,且不需要去声明一个新的子类。 简而言之 我创建了个修改过的类的对象,但是不去声明新的类型

//通过对象表达式实现一个匿名内部类的对象用于方法的参数中:
mTv.setOnClickListener(   object :View.OnClickListener{
            override fun onClick(v: View?) {

            }
        })

另一种用法

open class A(x: Int) {
    public open val y: Int = x
}

interface B {……}

val ab: A = object : A(1), B {
    override val y = 15
}

// java 中的 我就需要创建个新类  C extends A implement B 来使用

对象表达式作用:可以越过类的定义直接得到一个对象

其作用域:

var m:Int = 0
mTv.setOnClickListener(   object :View.OnClickListener{
            override fun onClick(v: View?) {
                m++  // 可以访问m 
            }
        })


注意事项: 匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的 返回类型或者用作公有属性的类型,那么该函数或属性的实际类型 会是匿名对象声明的超类型,如果你没有声明任何超类型,就会是 Any。在匿名对象 中添加的成员将无法访问

class C {
    // 私有函数,所以其返回类型是匿名对象类型
    private fun foo() = object {
        val x: String = "x"
    }

    // 公有函数,所以其返回类型是 Any
    fun publicFoo() = object {
        val x: String = "x"
    }

    fun bar() {
        val x1 = foo().x        // 没问题
        val x2 = publicFoo().x  // 错误:未能解析的引用“x”
    }
}

对象声明:

Kotlin 使用 object 关键字来声明一个对象。 Kotlin 中我们可以方便的通过对象声明来获得一个单例。(多用于创建工具类)

object L {
    
     val TAG ="-->"

    fun e(msg:String){
        Log.e(TAG,msg)
    }

    fun i(msg:String){
        Log.i(TAG,msg)
    }

}

// 引用的时候直接  L.e("打印些什么")

伴生对象: 类内部的对象声明可以用 companion 关键字标记,这样它就与外部类关联在一起,我们就可以直接通过外部类访问到对象的内部元素。


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

val instance = MyClass.create()   // 访问到对象的内部元素

我们可以省略掉该对象的对象名,然后使用 Companion 替代需要声明的对象名:

class MyClass {
    companion object {
    }
}

val x = MyClass.Companion

Note: ++一个类里面只允许存在一个伴生对象++ (伴生对象可以看做 为了创建静态成员而存在的)

  • 类型别名

类型别名为现有类型提供替代名称。 (起个代号并不会真正创建类型) 使用关键字 ==typealias==,必须定义在顶层

1.给函数类型起别名

typealias  IntPlus =  (Int,Int) -> Int

typealias Predicate<T> = (T) -> Boolean

扩展

Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式。

扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。

  • 扩展函数

扩展函数可以在已有类中添加新的方法,不会对原类做修改,扩展函数定义形式:

fun receiverType.functionName(params){
   /***/
}

recieverType : 表示函数的接收者,也就是函数扩展的对象

functionName: 函数名

params :参数 可以为空

例子

class User(var name:String)

/**扩展函数**/
fun User.Print(){
   print("用户名 $name")
}

fun main(arg:Array<String>){
   var user = User("Lee")
   user.Print()  // 结果: 用户名 Lee
}

若扩展函数和成员函数签名一致,则使用该函数时,会优先使用成员函数。

class C {

   fun foo() { 
     println("成员函数")
   }
    
}

fun C.foo() { println("扩展函数") }

fun main(arg:Array<String>){
   var c = C()
   c.foo() // 走的是成员函数
}

  • 扩展属性

扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。初始化属性因为属性没有后端字段(backing field),所以不允许被初始化,只能由显式提供的 getter/setter 定义。

val <T> List<T>.lastIndex: Int
    get() = size - 1

  • 伴生对象扩展
class MyClass {
    companion object { }  // 将被称为 "Companion"
}

fun MyClass.Companion.foo() {
    println("伴随对象的扩展函数")
}

val MyClass.Companion.no: Int
    get() = 10

fun main(args: Array<String>) {
    println("no:${MyClass.no}")
    MyClass.foo()
}

// 调用的时候  类名.函数/属性

委托

委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。 Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托。

以下实例中派生类 Derived 继承了接口 Base 所有方法,并且委托一个传入的 Base 类的对象来执行这些方法。

  1. 类委托
// 创建接口
interface Base {   
    fun print()
}

// 实现此接口的被委托的类
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

// 通过关键字 by 建立委托类
class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // 输出 10
}

  1. 属性委托 指的是一个类的某个属性值不是在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理。
import kotlin.reflect.KProperty
// 定义包含属性委托的类
class Example {
    var p: String by Delegate()
}

// 委托的类
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$thisRef${property.name} 属性赋值为 $value")
    }
}
fun main(args: Array<String>) {
    val e = Example()
    println(e.p)     // 访问该属性,调用 getValue() 函数

    e.p = "Lee"   // 调用 setValue() 函数
    println(e.p)
}

Kotlin 的泛型

待补充...