Kotlin的那些小知识

不定期更新,记录自己使用中遇到的常用方法

1.可空类型

var test:String?=null

声明变量时候指定可空声明,非空类型则必须赋初始值

2.延迟初始化声明

lateinit var test:String

声明变量在之后的流程中赋值,不能为空

3.非空断言

var test: String? = null
fun test() {
        val length = test!!.length
}

告诉编译器这个值不为空,不需要校验
否则会报可空,不让编译运行
如果执行途中为空,仍然会抛异常

4.可空断言

 var test: String? = null

 fun test() {
        val length = test?.run {
            println("strLength= $length")
        }
    }

当调用的对象为空时,该判定后面的代码都不会执行

fun test(){
 val length = test?.length
 println("$length")
}

这种会打印null

5.懒加载

val test by lazy {
    println("lazy load start")
    "1234"
}

fun test() {
    println("other things")
    test.run {
        println("run start")
        println("$this")
    }
}

by lazy声明的属性只能是val,在具体使用到该属性的时候才会初始化,常和单例配合使用

class Test {
    private object INSTANCE {
        val instance by lazy {
            Test()
        }
    }
    
    companion object {
        @JvmStatic
        fun getInstance(): Test {
            return INSTANCE.instance
        }
    }
}

6.匿名内部类

lateinit var view: View
fun test() {
    view.setOnClickListener(object :View.OnClickListener{
        override fun onClick(v: View?) {
		TODO("not implemented")
        }
    })
}

7.方法上下文

class MyActivity : AppCompatActivity() {

    private val toast: String = "Toast"

    fun test() {
        GlobalScope.launch {
            Toast.makeText(this@MyActivity, this@MyActivity.toast, Toast.LENGTH_LONG).show()
        }
    }
}

内部方法需要通过 this@XXX方法获取到所在的外部环境对象

8.初始化判断

 private lateinit var test: String
    
    fun main() {
        if (!this::test.isInitialized) {
            test = "test"
        }
    }

:: 表示当前上下文内的引用对象,isInitialized是判断是否初始化

9.类引用

Test::class.java

等同于Test.Class

10.继承与方法重写(open)

open class Test1{
    open fun test1(){}
}

class Test2 :Test1(){
    override fun test1(){
        
    }
}

使用open标记被继承的类与需要被重写的方法,因为kotlin默认生成的方法都是final型,需要声明open属性 才能被修改
比如上面不加open生成的是

public final class TestCsdn {
   public final void main() {
   }
}

加了open之后生成的是

public class Test1 {
   public void test1() {
   }
}

public final class Test2 extends Test1 {
   public void test1() {
   }
}

可见open标记的子类方法也是可以被重写的,而子类没声明open生成的还是final类型,不能被继承

11.静态对象(object)

fun main() {
        Test.ObjTest.test
        Test.ObjTest.objTest()
    }

class Test {
    object ObjTest {
        val test: String? = null
        fun objTest() {
        }
    }
}

object声明一个静态对象,里面的所有属性和方法得可以对象类直接调用,但object方法实际是生成了一个静态的单例,调用方法实际是也是调用这个单例的方法

 public final void main() {
      Test.ObjTest.INSTANCE.getTest();
      Test.ObjTest.INSTANCE.objTest();
}

public static final class ObjTest {
      @Nullable
      private static final String test;
      public static final Test.ObjTest INSTANCE;

      @Nullable
      public final String getTest() {
         return test;
      }

      public final void objTest() {
      }

      private ObjTest() {
      }

      static {
         Test.ObjTest var0 = new Test.ObjTest();
         INSTANCE = var0;
      }
   }

12.伴生对象(companion object)

fun main() {
        Test.test
        Test.comObjTest()
    }
}

class Test {
    companion object {
        val test: String? = null
        fun comObjTest(){

        }
    }
}

compain objectobject类似,但这个没有对象声明,并且会在所在的外部类的成员变量中生成一个静态的该对象,我们调用外部类的相关的伴生方法,最终是会调用到这个静态对象的方法;

  @Nullable
   private static final String test;
   public static final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null);
   public final void main() {
      Test.Companion.getTest();
      Test.Companion.comObjTest();
   }

public static final class Companion {
      @Nullable
      public final String getTest() {
         return Test.test;
      }

      public final void comObjTest() {
      }

      private Companion() {
      }

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

objectcompain object 其实原理都一样,只是生产的位置不一样,调用的方式也就不一样;object是生成在自己内部 compain object是生成在所在的外部类中

13.内部类(inner)

class Test1 {

    val test = "test"

    inner class InnnerTest {
        fun test() {
            Log.e("test", this@Test1.test)
        }
    }
}

inner属性声明的内部类可以访问外部类的属性,kotlin里的所有内部类都是静态的,可以减少内存泄露风险,如果我们不加inner属性,生成的类结构是

public final class Test1 {
   @NotNull
   private final String test = "test";

   @NotNull
   public final String getTest() {
      return this.test;
   }

  public static final class InnnerTest {
      public final void test() {
      }
   }
}

可见内部类是静态的,显然不能访问外部类的属性;
这里提一下,所有类属性的get方法都会自动生成的

14.强转换(as)

var textView: TextView? = null
var view: View? = null

    fun main() {
   //   textView = view as TextView
        textView = findViewById(R.id.textView)  as TextView
        textView = findViewById(R.id.textView)  as? TextView

    }

可空转换用 as?

15.类型检查(is)

fun main() {
    var i1 = Test1() is Test1
    var i2 = Test2() !is Test1

    println("$i1  $i2")
}

相当于java里面的 instanceof

16.when选择

fun main() {
    val position = 1;
    when(position){
        1 -> log(1)
        2 -> log(2)
        3 -> log(3)
        else -> log(-1)
    }
}
fun log(value:Int){
    println("$value")
}

17.解构

fun main() {
    val student = Student("Name1",1)
    val(_name,_age) = student
    println("name -> $_name ; age -> $_age")
}

data class Student constructor(var name: String, var age: Int)

就是把一个对象的属性用字段接收,这里用_name和_age去接收了student的两个对应属性,必须是构造方法的格式接收
每个data的属性都会在编译时生成相应的component获取的方法

public final class Student {
   @NotNull
   private String name;
   private int age;

   //这里略去了get和set方法
   
   public Student(@NotNull String name, int age) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
      this.age = age;
   }

   @NotNull
   public final String component1() {
      return this.name;
   }

   public final int component2() {
      return this.age;
   }
}

而在调用结构操作之后,会自动拆成单个属性返给我们,比如上面拆成的是

fun main(){
   Student student = new Student("Name1", 1);
   String _name = student.component1();
   int _age = student.component2();
   String var3 = "name -> " + _name + " ; age -> " + _age;
   System.out.println(var3);
}

注意,结构的格式必须安装构造方法来

18.事务处理

主要的链式处理有applyletalsorunwith

fun main() {
    val mCode = Code(1)

    mCode?.also {
        println("${it.code}")
    }

    mCode?.run {
        println("$code")
    }

    mCode?.apply {
        println("$code")
    }

    mCode?.let {
        println("${it.code}")
    }

    with(mCode) {
        println("$code")
    }
}

data class Code constructor(var code: Int)

总体来说,如果没有返回类型,其实用法都差不多,只是letalso的方法的上下文环境得用it,而其他的上下文环境都是this,此外,with需要把变量传进去

18.1 apply

val result = mCode?.apply {
       code = 2
       "insert message"
    }
    println("${result}")

输出结果是

Code(code=2)

appy可以直接调用对象内属性,而且返回值是本身

18.2 let

val result = mCode?.let {
       it.code = 2
       "insert message"
    }
    println("${result}")

输出结果是

insert message

let需要用it去调用内部属性,返回值是执行中最后的返回值

18.3 also

val result = mCode?.also {
       it.code = 2
       "insert message"
    }
    println("${result}")

输出结果是

Code(code=2)

also需要用it去调用内部属性,返回值是本身

18.4 run

val result = mCode?.run {
       code = 2
       "insert message"
    }
    println("${result}")

输出结果是

insert message

run可以直接调用对象内属性,返回值是执行中最后的返回值

18.5 with

 val result = with(mCode) {
       code = 2
       "insert message"
    }
    println("${result}")

输出结果是

insert message

with可以直接调用对象内属性,返回值是执行中最后的返回值

方法说明返回
apply返回当前的上下文对象T -> T this
let返回计算后的T -> R it
also返回当前的上下文对象T -> T it
run返回计算后的T -> R this
with返回计算后的T -> R this

19.多行字符串(""")

 var testStr =
            """||第一行
      ||第二行
  ||第三行"""
println(testStr)
println(testStr.trimMargin("||"))

输出结果是

||第一行
      ||第二行
  ||第三行
  
第一行
第二行
第三行

20.拓展函数

kotlin支持对类的方法进行推展,拓展类未定义的方法,拓展本身支持自定义的或者android库中的类

class Student {
    val name = "s_name"
    val age = 10
}
fun Student.test() = println("name -> ${this.name} \nage -> ${this.age}")

fun File.aaa() = println("file extends path ->>${path} : ${exists()}")

fun main() {
     var stu = Student()
    stu.test()

    var file = File("E:/test.test")
    file.aaa()
}

上面我定义了一个类Student,然后对这个类进行方法拓展,可以获取到类中的属性,可以通过类对象直接调用;这个对系统类库同样适用,比如这里定义的File也是可以进行拓展的
输出结果是

name -> s_name 
age -> 10
file extends path ->>E:\test.test : false

21.复数声明(vararg)

在java中,我们定义复数声明的格式一般是 int... values,kotlin中也有类似的结构声明,使用vararg关键字进行复数声明

fun main() {
    test("start", 1, 3, 5)
}

fun test(str: String, vararg values: Int) {
    println(str)
    for (i in values) {
        println("value -> $i")
    }
}

输出结果

start
value -> 1
value -> 3
value -> 5
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 要从小白到大牛,学习Kotlin需要掌握一些基本的知识和技能。首先,你可以使用交互式方式运行Kotlin代码,这可以通过使用REPL(Read-Eval-Print Loop)实现。REPL允许你逐行输入和执行Kotlin代码,这对于学习和测试代码非常有用。你可以使用Kotlin编译器提供的kotlin命令来启动REPL。\[3\] 另外,你还可以使用文本编辑工具编写Kotlin源文件,然后使用Kotlin编译器提供的kotlinc命令在命令提示行中编译Kotlin源程序。编译成功后,你可以使用kotlin命令或JDK提供的java命令来运行编译后的Kotlin程序。\[3\] 如果你想使用IntelliJ IDEA或Eclipse等集成开发环境来开发Kotlin项目,你可以创建一个新的Kotlin项目,并在项目中创建文件,编写代码,然后通过IDE提供的编译和运行功能来执行你的程序。这种方式更适合实际项目的开发。\[2\] 总之,要从小白到大牛,你需要不断学习和实践Kotlin编程,掌握基本的语法和概念,并熟悉常用的开发工具和技巧。通过不断的练习和项目实践,你可以逐渐提升自己的Kotlin编程能力,成为一名Kotlin大牛。 #### 引用[.reference_title] - *1* *2* *3* [《Kotlin从小白到大牛》第3章:第一个Kotlin程序](https://blog.csdn.net/weixin_38072116/article/details/106554349)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值