kotlin语法学习记录

这里作为学习kotlin时的每周技术分享准备。

kotlin大多语法使用还是与java类似,所以只记录下与java相比不同的一些地方。

①“==”与“===”

kotlin中的双等和三等的区别是 前者比较两个对象的值是否相等,后者比较两个对象的地址是否相等,也就是java中的equals。

下面有三个代码例子(这里的片段取自https://blog.csdn.net/qq_19707091/article/details/78126378

第一个 ——

fun main(args: Array<String>) {
   val a: Int = 1000
   val b: Int? = a
   val c: Int? = a
   println(b == c)    //true
   println(b === c)   //false    
}

我们从第一段代码就可以区分‘==‘和‘===‘的区别,双等号比较kotlin团队的处理就是通过Intrinsics.areEqual(b, c)来比较两个对象的值是否相等,三个等号就是通过java中的‘==‘比较两个对象的地址是否相等。

 

第二个——

fun main(args: Array<String>) {
   val a: Int? = 1000
   val b: Int? = a
   val c: Int? = a
   println(b == c)    //true
   println(b === c)   //true    
}

第二段代码很多就对第一段的分析表示怀疑了,其实第一段分析没错,第二段代码在a的定义时加了一个?空判断。我们看到第二段对应的java代码就会发现它在数据赋值给a时就已经自动包装成Integer对象,所以后面的b,c直接使用的a对象做的比较,这样就可以理解了,同一个对象的地址和值都是相等的,所以打印的都是true。

 

第三个——

fun main(args: Array<String>) {
   val a: Int = 100
   val b: Int? = a
   val c: Int? = a
   println(b == c)    //true
   println(b === c)   //true    
}

第三段代码和第一段代码很奇怪吧,除了数值不一样意外对应的java源码也是类似的,源码中就只有数值的类型不一样,原因只可能这个了,我们看看valueOf的源码:

 

return var0 >= -128 && var0 <= Integer.IntegerCache.high?Integer.IntegerCache.cache[var0 + 128]:new Integer(var0);

看完valueOf源码应该就明白为什么了,在-128到127之间的数值没有重新包装成新对象而是使用的IntegerCache里缓存的数据,所以b和c的地址和值都是同一个对象。

 

②findViewById

知道kotlin的一般也都知道kotlin不用再进行数据绑定,只要在项目的gradle中 apply plugin: 'kotlin-android-extensions',就可以直接调用布局文件中的view,不过需要注意的是在fragment中,不能在onCreateView()中直接使用view,会报空指针,要在onViewCreate()中使用才可以。原理是插件用了getView来findViewById,onCreateView()中的getView()还是空的。

 

③in运算符

in运算符用来判断集合内是否包含某个实例

fun main(args: Array<String>){
    val items = setOf("apple", "banana", "kiwifruit")
    //判断orange是否属于items的一个实例
    when{
        "orange" in items -> println("juicy")
        "apple" in items -> println("apple is fine too")
    }
    //或者在for循环中使用
    for (item in items){
        println(item)
    }
}

 

④data关键词快速实现bean类

这里直接上代码

public static class User {

        private String name;
        private int age;
        
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            User user = (User) o;

            if (age != user.age) return false;
            if (gender != user.gender) return false;
        }

        @Override
        public int hashCode() {
            int result = name != null ? name.hashCode() : 0;
            result = 31 * result + age;
            return result;
        }
    }

kotlin写法:

/*
* 用data关键词来声明一个数据类,除了会自动实现get set,还会自动生成equals hashcode toString
 */
data class User(val name: String, val age: Int)

 显然java代码更为繁琐,不仅需要自己实现get set方法,还需要手动重写toString()、equals ()、hashCode(),代码量也更大,而kotlin只需要一行代码即可,如果不加data关键词的话就只是自动实现get set方法哈

 

⑤扩展函数和属性

kotlin中的扩展函数和扩展属性可以让我们在使用第三方sdk时可以根据自己的需求去自定义扩展第三方库

先说扩展函数,比如我们想在String类中扩展函数使其可以获取到字符串的最后一个字符,可以这样定义:

/*  扩展函数  */
fun String.lastChar(): Char = this.get(this.length - 1)
/*  测试  */
fun test() {
    val str = "Sharley";
    println(str.lastChar())//输出最后一个字符'y'
}

扩展属性,例如我想实现String通过属性去直接获得最后字符:

/* 扩展属性 lastChar获取String的最后一个字符 */
val String.lastChar: Char
    get() = get(length - 1)
/* 测试 */
fun test() {
    val s = "Sharley" 
   println(sb.lastChar)
}

kotlin和java最后都是转为class字节码编译的,所以kotlin虽然有这样的扩展属性,但是java中不具备的功能Kotlin也是不能随意定义使用的。

 

⑥懒初始化 by lazy

首先kotlin中是有一个延迟初始化——lateinit,对于var的变量,如果类型是非空的,是必须初始化的否则编译不通过,如果不在当时初始化那么就需要用到lateinit,使用变量的时候再去实例化。

class Bean(var name: String, var age: Int)

lateinit var bean: Bean fun test() { bean= Bean("Sharley", 18) }

而懒初始化同样是推迟初始化时机,在使用的时候才去实例化

class Bean(var name: String, var age: Int)

val bean: Bean by lazy {
    Bean("Sharley", 18)
}

两者的区别是

  • by lazy 修饰val的变量
  • lateinit 修饰var的变量,且变量是非空的类型

⑦with函数

with函数的原型是这样的——

inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

(实不相瞒,原型我没看懂

Kotlin中可以用with语句来省略同一个变量的多次声明,比如我们打印一个字母表:

java实现——

fun alphabet(): String {
    val result = StringBuilder()
    result.append("START\n")
    for (letter in 'A'..'Z') {
        result.append(letter)
    }
    result.append("\nEND")
    return result.toString()
}

函数中,result变量出现了5次,替换为kotlin的with语句后——

/* 通过with语句,将result作为参数传入,在内部就可以通过this来表示result变量 */
fun alphabet2(): String {
    val result = StringBuilder()
    return with(result) {
        this.append("START\n")
        for (letter in 'A'..'Z') {
            this.append(letter) //省略this即只写’append(letter)'即可
        }
        this.append("\nEND") 
        this.toString()
    }
}

这个this其实是可以省略不写的,省略后即只剩一个result了,那其实也没必要:

/*  通过with语句,可以直接将对象传入,省掉对象的声明 */
fun alphabet4(): String {
    return with(StringBuilder()) {
        append("START\n")
        for (letter in 'A'..'Z') {
            append(letter)
        }
        append("\nEND")
        toString()
    }
}

最后写法也就可以省略成这样了↑

 

 

 

 

 

 

 持续更新...

 

posted @ 2020-07-29 10:49  Sharley  阅读(270)  评论(0编辑  收藏  举报