要點(diǎn)1:主構(gòu)造器
class User constructor(var id:Int, var name:String?, var job:String?) {
init{
// 初始化代碼塊
}
// 次構(gòu)造器必須(可間接)調(diào)用主構(gòu)造器
constructor() : this(null, null, null)
}
要點(diǎn)2:data class [語法糖]
- 編譯器會自動生成:equals、hashCode牙甫、toString、copy函數(shù)
data class User constructor(var id:Int, var name:String?, var job:String?)
- Copy函數(shù):
val user = User(1, "Name","Engineer")
val userCopy = user.copy()
println(user == userCopy) // true, '=='比較對象
println(user === userCopy) // false, '==='比較地址
- 解構(gòu):可以不用返回包裝類调违,直接返回所有類屬性
fun getUserInfo() = User(1, "Name","Engineer")
fun main() {
// 寫法:
val(id, name, job) = execute()
println("id=$id, name=$name, job=$job")
}
原理:data class自動生成component1,2,3...方法對應(yīng)構(gòu)造器參數(shù)
@Nullable
public final String component1() { return this.id; }
@Nullable
public final String component2() { return this.name; }
@Nullable
public final String component3() { return this.job; }
要點(diǎn)3:非空判斷
// kotlin語法
var job = user.job ?: "自由職業(yè)"
// 等價于
var job = user.job
if (job == null) {
job = "自由職業(yè)"
}
與 ?. 聯(lián)用
// kotlin寫法
if (user.name?.length ?:0 < 6) {
}
// 等價于
if (user.name == null || user.name!!.length < 6) {
}
要點(diǎn)4:利用filter和forEach來替代for循環(huán)及if條件判斷
// 原寫法
for(user in users) {
if(user.job == "Engineer") {
selectedUsers.add(user)
println(user.name)
}
}
// 使用forEach簡化后
users.forEach { //it代指參數(shù)
if (it.job == "Engineer") {
selectedUsers.add(user)
println(user.name)
}
}
// 使用filter簡化
users.filter { it.job == "Engineer" }.forEach { println(it.name) }
- 寫法說明:函數(shù)如果最后一個參數(shù)是lambda窟哺,則可以將lambda寫在()外,如果僅有l(wèi)ambda一個參數(shù)技肩,則()也可以省略且轨。
要點(diǎn)5:循環(huán)-Kotlin
// repeat函數(shù),循環(huán)n次
repeat(50) {
println(it)
}
// for-i循環(huán)虚婿,使用區(qū)間
val array = intArrayOf(1,2,2,3,4,5,6,7,8,9,50)
for (i in 0 until array.size) {
}
for (i in array.indices) {
}
要點(diǎn)6:函數(shù)嵌套-kotlin
- Kotlin允許函數(shù)內(nèi)嵌套函數(shù)旋奢,內(nèi)部函數(shù)可以訪問外部函數(shù)的屬性
- 優(yōu)點(diǎn):如該內(nèi)部函數(shù)僅有此調(diào)用,則可以增強(qiáng)代碼可讀性然痊,避免被其他人調(diào)用
- 缺點(diǎn):嵌套函數(shù)會在每次被調(diào)用時生成額外對象至朗,在循環(huán)中則不建議使用嵌套函數(shù),避免生成過多垃圾對象
private fun outerFun() {
val verifyCode = code.text.toString()
...
fun verify() : Boolean {
if (verifyCode?.length?:0<6) {
Logger.e("驗(yàn)證碼不正確")
return false
}
}
}
要點(diǎn)7:對象自定義get方法名剧浸,禁用set
- Kotlin會為非private的var對象創(chuàng)建get()/set()方法锹引;
- 如果不想讓set方法暴露,可使用private set修飾
- 如果想自定義get方法名辛蚊,可使用注解@get:JvmName("selfieGetApp")
companion object {
@get:JvmName("selfieGetApp")
@JvmStatic
lateinit var currentApp: Context
private set
}
要點(diǎn)8:類型推斷
- 可簡化函數(shù)聲明
// 原函數(shù)聲明
fun saveCache(key:String?, value:String?) : Unit {
cacheMap.putString(key, value)
}
fun getCache(key:String?) : String? {
return cacheMap.getString(key, null)
}
// 類型推斷用上粤蝎,簡化后
fun saveCache(key:String?, value:String?) = cacheMap.putString(key, value)
fun getCache(key:String?) = cacheMap.getString(key, null)
要點(diǎn)9:函數(shù)參數(shù)默認(rèn)值
- 可簡化重復(fù)代碼,避免函數(shù)重載
- 如在Java中調(diào)用袋马,則通過注解@JvmOverloads初澎,生成對應(yīng)的重載函數(shù)
// 函數(shù)定義
@JvmOverloads
fun toast(string:String?, duration:Int=Toast.LENGTH_SHORT) {
Toast.makeText(BaseApplication.currentApplication, string, duration).show()
}
// 函數(shù)調(diào)用
toast("Hello World")
toast("Hello World", 3000)
要點(diǎn)10:擴(kuò)展 (kotlin非常好用的一個特性)
- 可給任何一個類加上成員屬性或成員函數(shù)
- 可用來替換工具類
- 如果把已存在的函數(shù)或?qū)傩杂脭U(kuò)展覆蓋了怎么辦?
答:以原有成員函數(shù)為準(zhǔn) - 如果為父子類均擴(kuò)展了相同函數(shù)怎么辦虑凛?
答:編譯器生成拓展函數(shù)時碑宴,分別以父/子類的類型作為第一個函數(shù)參數(shù),所以調(diào)用域是哪個就會調(diào)用到哪個的拓展函數(shù)
// 定義:給Float類擴(kuò)展dp2px函數(shù)
fun Float.dp2px() : Float {
// 使用this訪問自身
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, displayMetrics)
}
// 調(diào)用
12f.dp2px()
再來一個添加擴(kuò)展成員屬性的例子
// 取LinearLayout第一個子元素
val LinearLayout.firstChild: View
get() = getChildAt(0)
要點(diǎn)11:內(nèi)聯(lián)函數(shù)(inline關(guān)鍵字)
詳見 Kotlin內(nèi)聯(lián)函數(shù)使用場景
要點(diǎn)12:函數(shù)類型 作為 參數(shù)/返回值
- Kotlin中允許函數(shù)作為函數(shù)的參數(shù)或返回值桑谍,從而可替代Java中接口類包裝
- 實(shí)際上延柠,函數(shù)類型參數(shù) 是kotlin在Functions.kt中預(yù)定義好的一系列接口,從Function0..22
// 定義一個函數(shù)
fun setOnClickListener(listener : (View) -> Unit) {
}
val view = View(context)
// 調(diào)用1: ‘::’雙冒號傳遞函數(shù)對象
view.setOnClickListener(::onClick)
fun onClick(view : View) {
println("點(diǎn)擊")
}
//調(diào)用2:匿名函數(shù)
view.setOnClickListener(fun (view:View) {
println("點(diǎn)擊")
})
//調(diào)用3:Lambda形式
view.setOnClickListener { //使用it代指view
println("點(diǎn)擊")
}
要點(diǎn)13:抽象屬性
Kotlin支持在接口聲明抽象屬性
interface BaseView<T> {
val presenter:T
}
// 實(shí)現(xiàn)處
val userPresenter = UserPresenter(this)
override val presenter: UserPresenter?
get() = userPresenter
要點(diǎn)14:kotlin特性-委托
- by lazy:
作用1:by lazy包含的代碼只會加載一次
作用2:by lazy修飾的對象僅在被調(diào)用時才創(chuàng)建
于是锣披,要點(diǎn)13中的代碼就可以優(yōu)化為:
override val presenter: LessonPresenter by lazy {
UserPresenter(this)
}
- 通過by關(guān)鍵詞實(shí)現(xiàn)屬性委托:
先看一段不優(yōu)雅的代碼
var userid: String
set(value) {
CacheUtils.save("userid", value)
}
get() {
return CacheUtils.get("userid")!!
}
var username: String
set(value) {
CacheUtils.save("username", value)
}
get() {
return CacheUtils.get("username")!!
}
使用委托優(yōu)化
1贞间、聲明一個Saver類,構(gòu)造函數(shù)傳入key雹仿,實(shí)現(xiàn)getValue/setValue方法執(zhí)行原本的set/get操作
class Saver(var key: String) {
operator fun getValue(activity: MainActivity, property: KProperty<*>): String {
return CacheUtils.get(key)!!
}
operator fun setValue(activity: MainActivity, property: KProperty<*>, value: String) {
CacheUtils.save(key, value)
}
}
2增热、在聲明userid、username變量時胧辽,將對應(yīng)的get/set操作委托給Saver對象
var userid: String by Saver("userid")
var username: String by Saver("username")
通過反編譯看看編譯器是如何實(shí)現(xiàn)的呢峻仇?
// 創(chuàng)建Saver對象 xxx$delegate
@NotNull
private final MainActivity.Saver userid$delegate = new MainActivity.Saver("userid");
@NotNull
private final MainActivity.Saver username$delegate = new MainActivity.Saver("username");
// 在get/set方法里,通過分別創(chuàng)建的Saver對象執(zhí)行g(shù)etValue/setValue方法
@NotNull
public final String getUserid() {
return this.userid$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setUserid(@NotNull String var1) {
this.userid$delegate.setValue(this, $$delegatedProperties[0], var1);
}
@NotNull
public final String getUsername() {
return this.username$delegate.getValue(this, $$delegatedProperties[1]);
}
public final void setUsername(@NotNull String var1) {
this.username$delegate.setValue(this, $$delegatedProperties[1], var1);
}