Kotlin優勢
kotlin更安全
這是它最重要的優勢,空引用由類型系統控制,你不會再遇到NullPointerException。這個空指針異常就像一個隱藏的定時炸彈,指不定啥時候就炸了。
在Kotlin中調用Java代碼,Java代碼中需要使用上非空註解。
代碼簡潔
使用Lambda 表達式,大量節省末班代碼,特別是重複多餘的findViewById。都說越少的代碼越能減少錯誤。
函數式支持
使用高階函數,可以將其作爲返回值或參數值使用,特別方便。
什麼是高階函數呢?就是以函數作爲參數,又以函數作爲返回值就是高階函數,而每個函數又對應着Lambda表達式。
常見的高階函數map()、forEach()、flatMap()、reduce()、fold()、filter()、takeWhile()、let()、apply()
擴展函數
Kotlin同C#類似,能夠擴展一個類的新功能而無需繼承該類或使用像裝飾者這樣的任何類型的設計模式。Kotlin支持擴展函數和擴展屬性。
1) 表達式可以直接作爲函數返回值
2)擴展函數: fun 類名.擴展方法名(參數列表){方法體} 或者 fun 類名.擴展方法名(參數列表) = 表達式
fun MyClass.add(a:Int,b:Int) = a+b
3)擴展屬性:var 類名.擴展屬性 / 對應其他方法
var MyClass.d: String
get() = "sdasda"
set(value){d = value}//MyClass的擴展成員變量d
Kotlin中沒有靜態成員
對應的解決方案是伴生類
與java可互相調用
Kotlin的標準庫更多的是對Java庫的擴展,但是在Kotlin中可以使用Android庫。在Kotlin和Java代碼中可以互相調用,完美無障礙。
與Java區別
- 基本類型類似,不在存在拆箱裝箱過程了
- 變量的聲明只有var可變變量和val只讀變量,Kotlin 能自動聰明的判斷變量的數據類型
- Java中支持char>int >long自動轉化,爲了降低不必要的錯誤Kotlin中不支持
- Java中的原始類是Object,而Kotlin中確實Any,Any方法中只有equals(),hashCode,toString三個方法。
- Java當中的類型轉換是指存在繼承關係的,子類可以向上自動轉型爲父類,而父類轉子類則需要強制轉換。而Kotlin中的類型轉換是使用as關鍵字
- Java中存在多個相同類名,引用需要用包名.類名,在Kotlin中則使用如下
import A.Student as AS//將A包下的Student類取外號爲"AS"
import B.Studnet as BS//將B包下的Student類取外號爲"BS"
- Kotlin有獨特的區間類,名字叫做Range。用整型區間舉例:
var intRange:IntRange = 0..1024//區間爲[0,1024],注意是全閉的
var intRange2:IntRange = 0 until 1024//區間爲[0,1024),注意是半閉半開的,包頭不包尾
println("50是否存在與區間[0,1024]:"+intRange.contains(50))
println("-3是否存在與區間[0,1024):"+intRange.contains(-3))
//遍歷區間
for(i in intRange){
println(i)
}
-
Kotlin中一般聲明數組開始用intArrayOf和arrayOf來聲明
-
Kotlin的權限修飾符沒有了default,對應的改成了internal
-
在Kotlin中使用"“等價Java 中的equals()方法。使用”=“來等價Java中的”==",比較兩個引用是否是同一個對象。
-
Kotlin中沒有了Switch語句,用when來替代,它更加強大,它的判斷值可以是表達式。
-
Kotlin中構造器需要使用constructor這個關鍵字,或者有個特殊默認的構造方式,這種叫做主構造函數
class Student(var name:String,var age:Int)//構造器的特殊寫法
-
Kotlin中從屬於類的函數叫做"成員方法",不從屬於類的叫做函數,如一下參數是以方法塊的形式表現,這個就是"函數"
-
Kotlin的默認訪問權限是public,而非Java中默認的訪問權限default。
final:是Kotlin的默認修飾符。如果你想你的類能被繼承你需要使用open來修飾。
data:這個修飾符很好用,也很有特色。用data修飾後:
1)會自動將所有成員用operator聲明,自動爲成員生成getter和setter。
2)自動重寫了equals()/hashCode()和toString()方法
3)data類沒有無參構造函數,這感覺是個坑,所以Kotlin官方給出瞭解決方案,就是使用NoArg(無參構造函數)和AllOpen(可被繼承)來解決問題。 -
在Kotlin的接口中可以實現方法不報錯,如下在Java中會報錯,但是在Kotlin中不會報錯。
interface JieKou{
fun A(){
//方法體a
println("接口裏面的方法,我是方法體")
}
}
- 在class的內部類中,需要個加上inner 這個關鍵字,否則這個類默認是靜態的。非靜態內部類的this關鍵字衝突可以使用"this@外部類類名"來區分。
var ab = A.AB() //實例化A類中的靜態內部類AB
var ac = A().AC() //實例化A類中的非靜態內部類AC
A a=new A();
A.AC ac =a.new AC();
A.AC ac=new A.AC();
- 包級函數,在Kotlin 的類名之外的函數,爲之包級函數。包級函數的所有函數(包括擴展函數)都是靜態的,在編譯的時候呢,Kotlin就把所有的包級函數都放在了一個類當中,Java可以通過此類名來訪問到所有的包級函數,如Test.getMessage()
//文件名 Test.kt
class Student(var name:String,var age:Int){
}
fun getMessage(){//這個擴展方法被編譯Test.kt中的靜態方法public static getMessage(Student student)
println("")
}
- Kotlin中的通配符不是“?”,而是" * “。”?"被拿來用於判斷非空了
- 正則表達式,除了Java中傳統的方式外,還有新的方式就是使用
var results = Regex(geShi).split(str)//Regex爲Kotlin中處理正則表達式的工具類
- IO流中使用"use"自動關閉讀寫文件
伴生類
這個特性我需要單獨來講解說明,在Kotlin中沒有static,我們在伴生類中的變量和方法相當於靜態變量和靜態方法。
companion object {//靜態方法和變量都應該寫在這裏面
var a:Int = 3;//靜態變量
fun get():Int{
return a
}
}
Kotlin中的幾種註解
1.@JavaFiled:將屬性編譯爲Java變量
2.@JvmStatic:將對象的方法編譯成Java靜態方法,通常應用與伴生對象
3.@JvmOverloads:默認參數生成重載方法
4.@file:JvmName:指定Kotlin文件編譯後的類名
內聯函數Let和Apply
let
let擴展函數的實際上是一個作用域函數,當你需要去定義一個變量在一個特定的作用域範圍內,let函數的是一個不錯的選擇;let函數另一個作用就是可以避免寫一些判斷null的操作。
//另一種用途 判斷object爲null的操作
object?.let{//表示object不爲null的條件下,纔會去執行let函數體
it.todo()
}
它的使用場景如下:
場景一: 最常用的場景就是使用let函數處理需要針對一個可null的對象統一做判空處理。
場景二: 然後就是需要去明確一個變量所處特定的作用域範圍內可以使用
with
with函數和前面的幾個函數使用方式略有不同,因爲它不是以擴展的形式存在的。它是將某對象作爲函數的參數,在函數塊內可以通過 this 指代該對象。返回值爲函數塊的最後一行或指定return表達式。
如下兩代碼是等價的:
val result = with(user, {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
})
val result = with(user) {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
使用場景
適用於調用同一個類的多個方法時,可以省去類名重複,直接調用類的方法即可,經常用於Android中RecyclerView中onBinderViewHolder中,數據model的屬性映射到UI上。
override fun onBindViewHolder(holder: ViewHolder, position: Int){
val item = getItem(position)?: return
with(item){
holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
holder.tvExtraInf.text = "難度:$gradeInfo | 單詞數:$length | 讀後感: $numReviews"
...
}
}
apply
從結構上來看apply函數和run函數很像,唯一不同點就是它們各自返回的值不一樣,run函數是以閉包形式返回最後一行代碼的值,而apply函數的返回的是傳入對象的本身。
以下與with函數不一樣,其結果值result指代的是user
fun main() {
val user = User("Kotlin", 1, "1111111")
val result = user.apply {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
println("result: $result")
}
使用場景
1)apply一般用於一個對象實例初始化的時候,需要對對象中的屬性進行賦值。或者動態inflate出一個XML的View的時候需要給View綁定數據也會用到,這種情景非常常見。
mSheetDialogView = View.inflate(activity, R.layout.biz_exam_plan_layout_sheet_inner, null).apply{
course_comment_tv_label.paint.isFakeBoldText = true
course_comment_tv_score.paint.isFakeBoldText = true
course_comment_tv_cancel.paint.isFakeBoldText = true
course_comment_tv_confirm.paint.isFakeBoldText = true
course_comment_seek_bar.max = 10
course_comment_seek_bar.progress = 0
}
2) 也和let函數一樣用於去進行判null。