Kotlin基础学习-第二篇

Kotlin第二篇

读者学习本篇文章前请先学习之前的文章

Kotlin系列已更新:

Kotlin基础学习-入门篇

Kotlin基础学习-第二篇

Kotlin进阶学习-第三篇

Kotlin进阶学习-第四篇

Kotlin进阶学习-第五篇

as关键字-类型强转

as类型强转,例如

val activity = context as Activity

静态函数的声明

object类中的类似静态方法的调用

使用Kotlin定义Object类,其内部的方法调用类似于static方法的调用,但其并非是真正的静态方法

创建object UtilsKotlin实现如下:

object Utils {
    fun test() {

    }
}

调用如下:

Utils.test()

其对应的java文件如下:

public final class Utils {
   @NotNull
   public static final Utils INSTANCE;

   public final void test() {
   }

   private Utils() {
   }

   static {
      Utils var0 = new Utils();
      INSTANCE = var0;
   }
}

那为何调用类似于静态方法的调用呢,这只是Kotlin提供的语法糖,Utils.test()对应的java代码为Utils.INSTANCE.test();

companion object

使用object则其内部的方法都会变为类似静态方法,那如果只想让某些方法呢,借助companion object则可实现

Kotlin文件如下:

class Test {
    fun test1() {
        
    }
    companion object {
        fun test2() {
            
        }
    }
}

其对应的Java如下:

public final class Test {
   @NotNull
   public static final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null);

   public final void test1() {
   }

   ...
   //静态内部类
   public static final class Companion {
      public final void test2() {
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

可发现其类内部存在一个Companion的静态内部类,还持有一个此类的静态对象,调用test2(),本质调用的是此对象的test2()

Test.test2()   //对应java代码:Test.Companion.test2();

@jvmStatic

若真的想使用静态方法,则必须借助@jvmStatic,其只能注解在companion object内部的方法上

class Test {
    fun test1() {

    }
    companion object {
        @JvmStatic
        fun test2() {

        }
    }
}

其对应的java文件如下:

public final class Test {
   @NotNull
   public static final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null);

   public final void test1() {
   }
	
    
   //声明静态方法
   @JvmStatic
   public static final void test2() {
      Companion.test2();
   }

   ...
   public static final class Companion {
      @JvmStatic
      public final void test2() {
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

发现上面多出来test2()的静态方法,其内部还是会调用Companion对象的非静态test2()

调用上述方法:

Test.test2() //对应的java代码为Test.Companion.test2();

发现其并没有调用生成的静态方法,而是调用的上述静态内部类的非静态方法,如此设计的原因主要是兼容java的调用,如果在纯java中调用此方法则会调用到真正的静态方法,若我们的代码不需要java调用,则没有必要使用@jvmStatic

顶层方法

Kotlin文件直接写方法会编译成静态方法

直接创建Kotlin文件,注意不是类,是纯Kotlin文件,命名为HelloWorld

fun main() {

}
fun test() {
    
}

其反编译的java代码为

public final class HelloWorldKt {
   public static final void main() {
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }

   public static final void test() {
   }
}

此时发现test()为静态方法

调用如下:

Kotlin中直接test()即可

test();

若是java则需使用类调用,Kotlin文件最终会编译成类

HelloWorldKt.test();

静态变量的声明

与静态方法类似的,有三种方式

object类中定义

定义object Test

object Test {
    val value = 1
}

此种方式只能在Kotlin中调用,Java不能调用

查看Test字节码反编译的java文件

public final class Test {
   private static final int VALUE;
   @NotNull
   public static final Test INSTANCE;

   public final int getVALUE() {
      return VALUE;
   }

   private Test() {
   }

   static {
      Test var0 = new Test();
      INSTANCE = var0;
      VALUE = 1;
   }
}

Kotlin中调用

Test.VALUE //其反编译的java代码为Test.INSTANCE.getVALUE();

java没有此语法糖,因此无法调用,想要使用必须使用以下写法

Test.INSTANCE.getVALUE();

若不想使用以上写法,则可借助const

object Test {
    const val VALUE = 1
}

其反编译的value为下,由private变为public

public static final int VALUE = 1;

在任何地方都可调用

注意 const只能在objectcompanion object中使用

companion object定义静态变量

区别和上面不大,读者可自行分析,const可在java中直接调用,无constjava需借助内部的静态对象的getValue方法

顶层定义静态变量

HelloWorld.kt中定义变量

val value = 1

对应反编译的java代码为

public final class HelloWorldKt {
   private static final int value = 1;

   public static final int getValue() {
      return value;
   }
}

Kotlin中调用 直接引用变量名字即可

java中需以下使用:

HelloWorldKt.getValue();

标准函数的使用

let

let主要用于对象的辅助判空操作,前篇文章已经讲述

with

with接收两个参数,一个任意类型的对象,一个Lambda表达式,第一个参数会传给Lambda使用,其Lambda内部执行的方法都是传入的对象所执行的,Lambda的最后一行代码会当成返回值返回,调用withLambda会立即执行。

val result = with(obj) {
    //this则代表obj
    //test() 等价于 this.test() 等价于 obj.test()
    //返回值,result最终为value
    "value"
}

比如存在一个水果列表,现在想吃完所有水果,并打印结果,不借助with如下:

val list = listOf("apple, banana, orange")
val builder = StringBuffer()
builder.append("Start eating fruits.\n")
for (fruit in list) {
    builder.append(fruit).append("\n")

}
builder.append("Ate all fruits")
val result = builder.toString()
println(result)

with实现如下:

val list = listOf("apple, banana, orange")
val result = with(StringBuilder()) {
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits")
    toString()
}
println(result)

可以看出我们可以省略对象去调用方法,使得代码更加简洁

run

runwith的使用场景类似,不同的是run在对象上调用,且只需要一个Lambda参数,其他地方一样。

上述吃水果用run实现如下:

val list = listOf("apple, banana, orange")
val result = StringBuilder().run {  
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits")
    toString()
}
println(result)

apply

applyrun相似,其也需在对象上调用,不同的是他的返回值是调用对象本身。

上述吃水果使用apply实现如下:

val list = listOf("apple, banana, orange")
val result = StringBuilder().apply {
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits")
}
println(result.toString())

Kotlin实现的页面跳转:

val intent = Intent(this, OtherActivity::class.java);
intent.putExtra("param1", "data1");
intent.putExtra("param2", "data2");
startActivity(intent)

借助上述标准函数则可如下:

val intent = Intent(this, OtherActivity::class.java).apply {
    putExtra("param1", "data1");
    putExtra("param2", "data2");
}
startActivity(intent)

kotlin不需要使用findViewById

bulid.gradle 开头导入'kotlin-android-extensions'

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
}

在后续使用时则可直接使用id拿到相应控件,例如activity_main中存在一个idmyButtonButton,使用则可直接引用myButton,但一定要导入import kotlinx.android.synthetic.main.activity_main.*

myButton.setOnClickListener { 
    Log.d("MainActivity", "myButton click")
}

inner关键字-普通内部类的声明

在类的内部使用inner定义类

inner class Test() {

}

生成的反编译java代码为

public final class Test {
    
}

懒加载-lateinit

先看一段代码:

var file: File? = null
fun main() {
    file = File("路径")
    file?.name
    file?.toURI()
}

由于某些原因,我们不会在变量声明的时候直接初始化,此时此对象只能赋为null,由于Kotlin的空指针检查,则必须加上才能编译通过,在后续访问此对象的变量和方法都要加上,很不方便。

想要解决上述问题则需借助lateinit关键字

lateinit var file: File
fun main() {
    file = File("路径")
    file.name
    file.toURI()
}

若未初始化则直接抛出UninitializedPropertyAccessException异常

Kotlin提供了语法检查此对象有无初始化

lateinit var file: File
fun main() {
    if (!::file.isInitialized) {
        file = File("路径")
    }
    file.name
    file.toURI()
}

::为固定语法,记住即可

密封类的使用-sealed

先看一段代码:

获取返回值

定义Result接口

interface Result 
class Success(val msg: String) : Result
class Failure(val msg: String) : Result

定义一个方法

fun getResultMsg(result: Result) = when(result) {
    is Success -> result.msg
    is Failure -> result.error.message
    else -> throw IllegalArgumentException()
}

由于Kotlin的性质,else必须写,但以上代码只可能由两种情况else纯属多余。若程序员疏忽传入了UnKown类则APP必崩溃。

要想解决上述问题则需借助sealed,密封类及其子类只能定义在同一个文件的顶层位置,不可嵌套在其它类中

修改上述代码:

sealed class Result
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()

方法修改如下:

fun getResultMsg(result: Result) = when(result) {
    is Success -> result.msg
    is Failure -> result.error.message
}

此时去掉else即可,当when扫描到传入参数为密封类时,则分支必须包括其全部子类,否则编译不通过。

原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下}

👍 点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{green}{点赞,你的认可是我创作的动力!}

⭐️ 收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{green}{收藏,你的青睐是我努力的方向!}

✏️ 评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!}

  • 15
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值