Kotlin

作者: 疯狂的兔子666 | 来源:发表于2021-01-16 00:42 被阅读0次

    一、基础语法

    Kotlin中可变变量、只读变量、静态变量、常量
    格式:修饰符 名称:类型 = 默认值

    var num: Int = 10
    

    空安全的声明方式

    var str: String ?= null
    

    可变变量:
    var: var是一个可变变量,这是一个可以通过重新分配来更改为另一个值的变量,这种声明变量的方式和Java中声明变量的方式一样。

    特点:
    可以重写set和get方法,注意在set和get方法中,变量用field表示,不能用变量本身,否则会出现循环调用。

    var num2 = 10
        set(value) {
            field = value + 5
        }
    
        get() {
            return field + 5
        }
    

    只读变量:
    val: val是一个只读变量,这种声明变量的方式相当于java中的final变量,一个val创建的时候必须初始化,因为以后不能被改变。

    特点:
    只能重写get方法,不能重写set方法

    val num3 = 10
        get() {
            return field + 5
        }
    

    静态变量:
    Kotlin中声明静态变量的方法是将对象放在对象中声明。

    /**
    *  静态类
    */
    object StaticData {
        /**
         * 静态变量(private)
         */
        var num6 = 10
    
    }
    

    如果把变量放到一个普通对象中,声明出来的变量是私有的,外部调用不到,推荐使用伴生对象来声明静态变量。

    /**
    * 伴生对象
    */
    companion object {
        /**
         * 静态变量
         */
    
        var num4 = 10
    
    }
    

    伴生对象相当于是外部类的对象,我们可以使用类直接调用,在伴生对象中声明的变量,实际上编译成java代码后对象都声明在了伴生对象的外部类里面了,伴生对象里面只是生成的set和get方法。

    常量:
    常量值是在编译时期就确定下来的,因此常量值可以直接赋值,也可以赋值为其他常量值,但不能赋值为非常量值,即不可以用没有被const修饰的变量给它赋值,
    const只能修饰val,不能修饰var。
    const val 常量值的名字 = 常量值

    声明一个常量可以在伴生对象中声明

    object StaticData {
        /**
         * 常量:const val
         */
        const val num7 = 10
    
    }
    

    也可以在类外面声明,用这种方法声明的常量,相当与创建了一个 类名称 + Kt(KotlinTestActivitykt)的对象,常量属于这个对象

    const val num8 = 10
    
    open class KotlinTestActivity : BaseActivity(), View.OnClickListener
    

    二、Kotlin中的方法

    Kotlin中声明方法的格式:

    fun  [方法名] ( [参数名] : [参数类型] ) : [返回类型]{
        ...
        return [返回值]
    }
    

    有返回值:

    fun add(num1: Int, num2: Int): Int {
        return num1 + num2
    }
    

    无返回值,Unit代表为空,可以省略:

    fun log(msg: String): Unit {
        print(msg)
    }
    
    fun log(msg: String) {
        print(msg)
    }
    

    静态方法:需要声明在对象中object

    /**
    * 伴生对象
    */
    companion object {
        /**
         * 静态方法
         */
    
        fun getData(): Int {
            return 1
        }
    
        /**
         * 静态方法
         */
        @JvmStatic
        fun getNewData(): Int {
            return 2
        }
    }
    

    在Java中调用需要加companion

    KotlinTestActivity.Companion.getNum4()
    

    可以通过注解@JvmStatic省略Companion直接调用

    KotlinTestActivity.getNewData()
    

    Kotlin中的方法重载:

    Java中不同参数,类型的方法重写需要写多个方法,在Kotlin中只需要声明一个方法就可以解决。

    /**
    * @param arg1 必传
    * @param arg2 必传
    * @param arg3 必传
    * @param arg4 可不传,不传时默认值 2
    * @param arg5 可不传,不传时默认值 test
    */
    
    fun test(arg1: String?, arg2: Int?, arg3: String?, arg4: Int? = 2, arg5: String? = "test") {
    
    }
    

    方法中的参数可以设置默认值,在外部没有传值得情况就可以用默认值来代替,上面那个方法中后两个参数有默认值,所有在调用这个方法的时候是可以不传那两个参数的,如果参数没有默认值,是必传的。

    test("arg1", 2, "arg3", 4, "arg5")
    
    test("arg1", 2, "arg3")
    

    Kotlin方法中的参数也可以不一设定的顺序传递,需要指定传递的哪个参数

    test(arg1 = "arg1", arg2 = 2, arg3 = "arg3")
    
    test(arg3 = "arg3", arg1 = "arg1", arg2 = 2)
    

    三、Kotlin中的null安全

    Kotlin将变量分为可以为Nullable类型和Non-Null类型,变量默认Non-Null类型,如果想声明Nullable的变量,需要用“?”修饰,

    加?表示该变量可能为空,不加则表示一定不会指向一个空引用。

    声明Nullable类型变量

    var name: String? = null
    

    声明Non-Null类型变量

    var name1: String = ""
    

    name1可以直接赋值给name

    name = name1
    

    但是name要赋值给name1,必须加!!

    name1 = name!!
    

    如果name为空,就会抛出KotlinNullPointerException异常,所以Nullable类型变量要赋值给Non-Null类型变量时,要先判断是否为空,不为空才可以赋值,并且不建议使用!!。

    四、Kotlin中的 data class

    在 Kotlin 中,不需要自己动手去写一个 JavaBean,可以直接使用 DataClass,使用 DataClass 编译器会默默地帮我们生成以下方法

    set()
    get()
    equals()
    hashCode()
    toString()
    componentN()
    copy()
    

    定义一个 data class 类:

    data class UserData(
            var name: String,
            var age: Int = 20,
            var avatar: String? = null,
            var userInfo: UserInfo? = null
    
    )
    

    虽然data class为我们生成了很多方法,减少了我们的很多代码量,但是data class 存在两个问题,没有无参数的构造方法,而且是被final修饰不能被继承,不过可以利用官方给出的插件来解决这些问题(noarg、allopen)。

    https://www.jianshu.com/p/90a3233b0a8a?utm_campaign=maleskine&utm_content=note&utm_medium=reader_share&utm_source=weibo

    buildscript {
        dependencies {
            classpath "org.jetbrains.[kotlin:kotlin-noarg:$kotlin_version](http://kotlinkotlin-noarg%24kotlin_version/)"
            classpath "org.jetbrains.[kotlin:kotlin-allopen:$kotlin_version](http://kotlinkotlin-allopen%24kotlin_version/)"
        }
    }
    

    通过插件可以帮我们去掉class的final关键字,并且生成一个无参的构造方法,但是由于是在编译器做的操作,所以在源代码中还是无法直接使用无参的构造函数,只能通过反射来使用。

    @KotlinData
    data class OneData(var arg: String)
    
    class NewData(var arg2: String, var arg3: Int, arg: String): OneData(arg)
    

    如果需要无参的构造方法,可以给每个变量都设置初始默认,或者采用一般的class

    data class UserInfo(
            var info1: String? = null,
            var info2: String? = null,
            var info3: Int = 0
    
    )
    

    一般的class

    class OtherInfo {
        var info1: String? = null
        var info2: String? = null
        var info3: Int = 0
    }
    

    五、Kotlin中扩展函数

    扩展函数实际上就是一个对应Java中的静态函数,这个静态函数参数为接收者类型的对象,然后利用这个对象就可以访问这个类中的成员属性和方法了,并且最后返回一个这个接收者类型对象本身。这样在外部感觉和使用类的成员函数是一样的,它并没有改变类本身。

    扩展函数的使用:

    只需要把扩展的类或者接口名称,放到即将要添加的函数名前面。这个类或者名称就叫做接收者类型,类的名称与函数之间用"."调用连接。this指代的就是接收者对象,它可以访问扩展的这个类可访问的方法和属性。

    fun test(str: String): String {
        return "back$str"
    }
    
    fun TextView.setColor(colorRes: Int) {
        this.setTextColor(context.getColor(colorRes))
    }
    
    fun ImageView.loadImage(drawableRes: Int) {
        Glide.with(this)
                .load(drawableRes)
                .into(this)
    
    }
    

    在外面调用:

    var test = getBack("test")
    tv_age?.setColor(R.color.color_4)
    tv_avatar?.loadImage(R.drawable.head_bg_img)
    

    Kotlin扩展函数允许我们在不改变已有类的情况下,为类添加新的函数,在java要调用扩展函数要将被扩展的对象传进去。

    KotlinExtensionKt.getBack("test");
    KotlinExtensionKt.setColor(tv, R.color.color_0);
    KotlinExtensionKt.loadImage(iv, R.drawable.head_bg_img);
    

    六、Kotlin中的Lambda表达式和高阶函数

    1、Lambda表达式的本质其实是匿名函数,因为在其底层实现中还是通过匿名函数来实现的。
    2、将函数作为另一个函数的参数或者返回值的函数是高阶函数

    语法:

    1\. 无参数的情况 :
        val/var 变量名 = { 操作的代码 }
    
    2\. 有参数的情况     
        val/var 变量名 : (参数的类型,参数类型,...) -> 返回值类型 = {参数1,参数2,... -> 操作参数的代码 }
        可等价于
        // 此种写法:即表达式的返回值类型会根据操作的代码自推导出来。
        val/var 变量名 = { 参数1 : 类型,参数2 : 类型, ... -> 操作参数的代码 }
    
    3\. lambda表达式作为函数中的参数的时候,这里举一个例子:
        fun test(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, ... ) -> 表达式返回类型){  
           ...  
       }
    

    特点:
    1、Lambda表达式总是被大括号括着
    2、其参数(如果存在)在 -> 之前声明(参数类型可以省略)
    3、函数体(如果存在)在 -> 后面。
    举例:

    1、无参数的情况

     // 源代码
     fun test() { 
        println("无参数") 
     }
    
     // lambda代码
     val test = { 
        println("无参数") 
     }
    
     // 调用
     test()  => 结果为:无参数
    
    2、有参数的情况
     // 源代码
     fun test(a : Int , b : Int) : Int{
         return a + b
     }
    
     // lambda
     val test : (Int , Int) -> Int = {a , b ->
         a + b
     }
    
     // 或者
     val test = {a : Int , b : Int ->
         a + b
     }
    
     // 调用
     test(3,5) => 结果为:8
    

    3、Lambda表达式作为函数中的参数的时候

    // 源代码 
    fun test(a : Int , b : Int) : Int{
         return a + b 
    }
    
    fun sum(num1 : Int , num2 : Int) : Int{
         return num1 + num2 
    } 
    
    // 调用 
    test(10,sum(3,5)) 
    // 结果为:18
    
    // lambda 
    fun test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
         return a + b.invoke(3,5)
     } 
    
    // 调用 
    test(10,{ num1: Int, num2: Int -> 
        num1 + num2     
    }) 
    
    // 结果为:18
    

    七、Kotlin的使用

    1、创建一个Activity默认是私有的,如果这个activity可以被继承需要加open修饰

    2、Java中的继承 extends 和实现 implements 在Kotlin中都可以用 :替换,多个implements之间添加 ,

    open class KotlinTestActivity : BaseActivity(), View.OnClickListener
    

    3、在布局中的View可以在activity直接调用,Kotlin默认给实现findViewById

    <TextView
            android:id="@+id/tv_age"
            android:layout_width="100dp"
            android:layout_height="40dp"
            android:layout_margin="20dp"/>
    
    tv_age?.setColor(R.color.color_4)
    

    查看Kotlin转换成java后的代码

    public View _$_findCachedViewById(int var1) {
       if (this._$_findViewCache == null) {
          this._$_findViewCache = new HashMap();
       }
    
       View var2 = (View)this._$_findViewCache.get(var1);
       if (var2 == null) {
          var2 = this.findViewById(var1);
          this._$_findViewCache.put(var1, var2);
       }
       return var2;
    }
    
    var10000 = (TextView)this._$_findCachedViewById(id.tv_age);
    if (var10000 != null) {
       KotlinExtensionKt.setColor(var10000, 500082);
    }
    

    4、Kotlin中的多个数据可以拼接成一个String用连接,如果是一个对象中的数据要加{} 包起来

    var num: Int = 10
    var user1 = UserData("name1”)
    println("num = $num")
    println("num = ${user1.age}")
    

    5、设置监听事件

    系统的OnClickListener, OnTouchListener等属于SAM 构造可以使用Lambda替换,具体分析:

    https://blog.csdn.net/blovecat/article/details/103767059

    tv_avatar?.setOnClickListener(object : View.OnClickListener {
        override fun onClick(v: View?) {
        }
    })
    
    // 当lambda表达式是函数调用的最后一个实参,它可以放到括号的外边。
    tv_avatar?.setOnClickListener() {
    }
    
    // 当lambda表达式是函数唯一实参时,还可以去掉代码中的空括号对
    tv_avatar?.setOnClickListener {
    }
    
    // 当lambda表达式只有一个参数,那么在调用该lambda表达式时,可以不指定它的参数名字,在lambda函数体内用it来代表这个参数.
    tv_avatar?.setOnClickListener {
        it.alpha = 1f
    }
    
    // 当lambda表达式有多个参数,那么在调用该lambda表达式时,必须指定每一个参数的名字,如果某个参数用不到可以用 _ 来代替
    tv_avatar?.setOnTouchListener { _, event ->
        if (event.action == MotionEvent.ACTION_DOWN) {
    
        }
        false
    }
    

    5、自定义View 三个构造方法可以写成一个

    Java自定义View

    public class TestView extends View {
        public TestView(Context context) {
            this(context,null);
        }
    
        public TestView(Context context, AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
    }
    

    6、Kotlin自定义View

    class TestView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
        : View(context, attrs, defStyleAttr) {
    
        // 定义接口回调方式
        var testListener: TestListener? = null
    
        // Lambda 表达式回调
        var callBack = { s: String, i: Int -> Unit}
    
        // Lambda 表达式回调简化
        var callBack2: ((String) -> Unit)? = null
    
        var callBack3: ((String, Int) -> Unit)? = null
    
        /**
         * 系统的初始化方法
         */
        init {
    
        }
    
        fun backData() {
            callBack.invoke("back", 0)
        }
    
        fun backData2() {
            callBack2?.invoke("back")
    
            callBack3?.invoke("back", 1)
        }
    
        fun setCallBack(listener: TestListener?) {
            this.testListener = listener
        }
    
    }
    
    Kotlin接口定义:
    
    interface TestListener {
    
        fun callBack1()
    
        /**
         * 在java中,接口中定义的方法不可以实现,实现类必须实现所有方法
         * 在Kotlin中,接口中的方法可提前进行空实现,实现类可不实现其不用的方法
         */
        fun callBack2() {}
    
    }
    

    Activit中调用回调函数:

    var view = TestView(this)
    
    view.setCallBack(object: TestListener{
        override fun callBack1() {
    
        }
    })
    
    view.callBack = { _: String, _: Int ->
    
    }
    
    view.callBack2 = {
    
    }
    

    7、单例模式

    /**
    * @Author: zs
    * @Date: 20/12/23 上午8:29
    * @Description:
    */
    class InstanceKotlin {
        companion object{
            @Volatile
            private var mUtil: InstanceKotlin? = null
    
            /**
             * 两次判空实现单例
             * @return
             */
            val instance1: InstanceKotlin?
                get() {
                    if (mUtil == null) {
                        synchronized(InstanceKotlin::class.java) {
                            if (mUtil == null) {
                                mUtil = InstanceKotlin()
                            }
                        }
                    }
                    return mUtil
                }
    
            /**
             * 静态内部类实现单例
             * @return
             */
            val instance2: InstanceKotlin
                get() = TestHolder.instance
    
            private object TestHolder {
                val instance: InstanceKotlin = InstanceKotlin()
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Kotlin

          本文链接:https://www.haomeiwen.com/subject/nfbgaktx.html