變量延遲加載
// 某些成員變量在聲明時無法初始化,且不想使用可空類型(也就是帶?的類型)。可使用 lateinit 和 by lazy
// 不知道具體值,後面再賦值使用;所以必須var
lateinit var name: String
// 知道具體值,用到的時候再加載,表示不可變的值,所以必須val
// {}中的最後一行代碼返回初始化的結果,加載時機爲第一次調用常量的時候,且只會加載一次
private val book by lazy {
LogUtil.i("這行代碼不會影響book賦值")
"Android"
}
訪問權限修飾符
public: 公開,可見性最大,哪裏可以引用 Kotlin 的類默認是 public 的
private: 私有,可見性最小,根據聲明位置不同可分爲類中可見和文件中可見
protected: 保護,相當於private+ , 子類可見
internal: 內部,僅對module內可見
構造方法,init代碼塊
/**
* 構造函數單獨用了一個 constructor 關鍵字來和其他的 fun 做區分,分主構造和次構造
* 如果類中有主構造器,所有次構造器都需要通過this關鍵字調用主構造器
*
* 從主構造器的特性出發,一旦在類中聲明瞭主構造器,就包含兩點:
* 必須性:創建類的對象時,不管使用哪個構造器,都需要主構造器的參與
* 第一性:在類的初始化過程中,首先執行的就是主構造器
*/
class User constructor(var name: String) {
// init 代碼塊是先於次構造器執行的。
init {
// 如果把主構造器看成身體的頭部,那麼 init 代碼塊就是頸部,次構造器就相當於身體其餘部分
}
// 直接調用主構造器
constructor(name: String, age: Int) : this(name)
// 通過上一個次構造函數,間接調用主構造器
constructor(name: String, age: Int, id: Int) : this(name, age) {}
}
constructor 關鍵字省略,私有,參數
// 主構造器中 constructor 關鍵字如果沒有被 可見性修飾符 或 註釋 標註可以省略
class User(var name: String) {
constructor(name: String, age: Int) : this(name)
}
// 主構造器被修飾爲私有的,外部就無法調用該構造器
class User private constructor(var name: String) {
}
// 主構造函數裏面聲明屬性,前面加 var / val 構造參數同時成爲成員變量
class User(var name: String) {
}
// ↑↓ 上下等價
class User(name: String) {
var name: String = name
}
靜態方法
一共三種實現方式:①object ②伴生對象 ③頂層函數
/**
* 當用 object 聲明一個類時,表明這個類是一個單例類,可繼承其他類
* object 可以定義在全局也可以在類的內部使用
* object聲明不能用在方法和inner內部類中,但是能嵌套在其他object聲明和嵌套類中
* object 定義後即刻實例化,因此 object 不能有定義構造函數
*/
object SystemUtil{
}
/**
* 和 object 不同, companion object 的定義完全屬於類的本身,
* 因此 companion object 不能脫離類而定義在全局之中。
* 類似 Java 裏的 static 變量
*/
class ScreenUtil {
// companion object 修飾爲伴生對象,伴生對象在類中只能存在一個
companion object {
}
}
真實項目中推薦的寫法是使用伴生對象和 object
關鍵字結合的方式,示例如下:
class UmengEventUtil {
companion object {
@JvmStatic
fun getInstance(): UmengEventUtil {
return Holder.instance
}
}
private object Holder {
val instance = UmengEventUtil()
}
fun onRegister(mContext: Context) {
MobclickAgent.onEvent(mContext, "__cust_event_1")
}
}
頂層聲明 top - level property / function
又稱頂層函數,直接在文件中定義函數和屬性,這種頂層函數不要聲明在module內最頂層的包中,至少要在一個包中
/*
頂層聲明屬於 package,不在 class/object 內
屬性和函數,不屬於任何 class,而是直接屬於 package
它和靜態變量、靜態函數一樣是全局的,用起來更方便:在其它地方用的時候,類名都不用寫
*/
fun stringToDouble(money: String): Double {
return money.toDouble()
}
get,set 方法
// 默認kotlin已自動生產set,get方法,可省略
class User() {
var name: String? = null
set(value) {
field = value
}
get() = field
}
// 上下等價 ↑↓
class User{
var name: String? = null
}
// 如只想讓外部使用,不想外部set,可在set前面添加private將set方法私有化
class User {
var name: String
private set
init {
name = "設置name值,外部只能調用get方法"
}
}
數據類
相比JavaBean手動生成各種方法,kotlin data class要簡單很多
/**
* var user = User("zs",18,"10001")
* 自動生成
* toString() LogUtil.e("user.toString = $user")
* copy() var user2 = user.copy(id = 2)
* equals() user.equals(user2) 輸出 true
* hashCode() user.hashCode 輸出內存地址
* componentN() 解構聲明 val (name, age, code) = User("zs", 0, "1001")
*/
data class User(
var name: String,
var age: Int,
var code: String
)
擴展函數
// 原本使用
fun dp2px(dp: Float): Float {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().displayMetrics)
}
dp2px(3.4f)
// 擴展函數
fun Float.dp2px(): Float {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics)
}
3.2f.dp2px()
持續更新中...