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() } }
最后写法也就可以省略成这样了↑
持续更新...