Kotlin

一、基础语法

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



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)