Kotlin學(xué)習(xí)筆記:概述
Kotlin學(xué)習(xí)筆記:基本語法和函數(shù)
Kotlin學(xué)習(xí)筆記:類和接口
Kotlin學(xué)習(xí)筆記:lambda編程
Kotlin學(xué)習(xí)筆記:類型系統(tǒng)
Kotlin學(xué)習(xí)筆記:泛型
Kotlin學(xué)習(xí)筆記:注解和反射
類
在Kotlin中揍堕,類默認(rèn)是final和public的畔派。如果該類需要被繼承休吠,則可以用open關(guān)鍵字顯示的聲明類凿滤。
可見性修飾符
構(gòu)造方法
Kotlin引入了constructor和init關(guān)鍵字哗讥。constructor關(guān)鍵字用于聲明一個主構(gòu)造方法或者從構(gòu)造方法。而init是一個初始化語句塊近上。這個語句塊會在類創(chuàng)建時,與主構(gòu)造方法一起使用宿饱。因為主構(gòu)造方法不能包含初始化代碼。
class User constructor(_name: String){
val name: String
init {
this.name = _name
}
}
從構(gòu)造方法
雖然大多數(shù)在Java中需要重載的構(gòu)造方法場景都可以使用參數(shù)默認(rèn)值和參數(shù)命名的方法解決掉宝鼓,但是刑棵,還是有些場景需要聲明多個構(gòu)造方法,以便于以不同的方式初始化類愚铡。
例如蛉签,在Android中自定義View,往往就需要聲明多個構(gòu)造方法沥寥。此時碍舍,可以使用從構(gòu)造方法。從構(gòu)造方法可以聲明任意多個邑雅。
class CustomView: View {
constructor(context: Context) : super(context) {
//...
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
// ...
}
}
內(nèi)部類
與java不同的是片橡,默認(rèn)情況下,內(nèi)部類不能訪問外部類淮野。如果內(nèi)部類想要訪問外部類捧书,需要使用inline關(guān)鍵字顯示聲明內(nèi)部類。
sealed 類(密封類)
如果父類使用sealed修飾符骤星,那么它會對可能創(chuàng)建的子類做出嚴(yán)格限制经瓷,并且所有子類必須嵌套在父類中。
數(shù)據(jù)類
在Java中洞难,會出現(xiàn)很多樣板代碼舆吮,比如setter/getter,toString,equals,hashCode等方法队贱。為了消除這些樣板代碼色冀,Kotlin引用了數(shù)據(jù)類,即使用data關(guān)鍵字修飾類即可柱嫌。
下面我們創(chuàng)建了一個User數(shù)據(jù)類锋恬,它有兩個屬性,姓名和年齡编丘。
data class Person(val name:String, val age: Int)
在使用時与学,我們可以直接user1.name或user1.toString()調(diào)用。
為了更清楚的看到數(shù)據(jù)類是如何工作的瘪吏,我們可以查看這個類的字節(jié)碼。將字節(jié)碼反編譯為java代碼蜗巧,如下所示掌眠。
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 1,
d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\t\n\u0002\u0010\u000b\n\u0002\b\u0004\b\u0086\b\u0018\u00002\u00020\u0001B\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\u0006J\t\u0010\u000b\u001a\u00020\u0003H?\u0003J\t\u0010\f\u001a\u00020\u0005H?\u0003J\u001d\u0010\r\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u0005H?\u0001J\u0013\u0010\u000e\u001a\u00020\u000f2\b\u0010\u0010\u001a\u0004\u0018\u00010\u0001H?\u0003J\t\u0010\u0011\u001a\u00020\u0005H?\u0001J\t\u0010\u0012\u001a\u00020\u0003H?\u0001R\u0011\u0010\u0004\u001a\u00020\u0005¢\u0006\b\n\u0000\u001a\u0004\b\u0007\u0010\bR\u0011\u0010\u0002\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\t\u0010\n¨\u0006\u0013"},
d2 = {"Lcom/nxiangbo/kotlin_learning/User;", "", "name", "", "age", "", "(Ljava/lang/String;I)V", "getAge", "()I", "getName", "()Ljava/lang/String;", "component1", "component2", "copy", "equals", "", "other", "hashCode", "toString", "production sources for module app"}
)
public final class User {
@NotNull
private final String name;
private final int age;
@NotNull
public final String getName() {
return this.name;
}
public final int getAge() {
return this.age;
}
public User(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
this.age = age;
}
@NotNull
public final String component1() {
return this.name;
}
public final int component2() {
return this.age;
}
@NotNull
public final User copy(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
return new User(name, age);
}
// $FF: synthetic method
// $FF: bridge method
@NotNull
public static User copy$default(User var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}
if ((var3 & 2) != 0) {
var2 = var0.age;
}
return var0.copy(var1, var2);
}
public String toString() {
return "User(name=" + this.name + ", age=" + this.age + ")";
}
public int hashCode() {
return (this.name != null ? this.name.hashCode() : 0) * 31 + this.age;
}
public boolean equals(Object var1) {
if (this != var1) {
if (var1 instanceof User) {
User var2 = (User)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}
return false;
} else {
return true;
}
}
}
由此可見,在編譯器將代碼編譯為字節(jié)碼時幕屹,為User類自動添加了上述這些方法蓝丙。
除了常用的toString等方法外级遭,還自動生成了一個copy方法。那么渺尘,這個copy方法的作用是什么呢挫鸽?為了讓使用不可變對象的數(shù)據(jù)類變得更容易,Kotlin提供了一個copy方法鸥跟,以便于通過創(chuàng)建副本的方式修改數(shù)據(jù)類
object關(guān)鍵字
object關(guān)鍵字有三種應(yīng)用場景:
- 單例
- 伴生對象(companion object)
- object表達(dá)式丢郊,可以替代Java匿名內(nèi)部類
單例
object聲明將 類聲明和單一實例聲明結(jié)合在一起。下面創(chuàng)建一個object
object ObjectDemo{
}
反編譯為Java代碼為
public final class ObjectDemo {
public static final ObjectDemo INSTANCE;
static {
ObjectDemo var0 = new ObjectDemo();
INSTANCE = var0;
}
}
companion object
可以包含工廠方法或者與該類相關(guān)但不需要該類實例的方法医咨。因為頂層函數(shù)不能訪問類的私有方法枫匾,而companion object 可以訪問類的私有屬性和方法。
abstract class RepoDatabase : RoomDatabase() {
abstract fun repos(): RepoDao
companion object {
@Volatile
private var INSTANCE: RepoDatabase? = null
fun getInstance(context: Context): RepoDatabase = INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(context, RepoDatabase::class.java, "zhihu.db").build()
}
}
object表達(dá)式
可以替代匿名內(nèi)部類
val vto = layout.viewTreeObserver
vto.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener {
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
override fun onGlobalLayout(){
layout.viewTreeObserver.removeOnGlobalLayoutListener(this)
val height = layout.measuredHeight
val width = layout.measuredWidth
}
})
接口
接口與Java接口聲明一致拟淮,不過Kotlin接口方法可以有默認(rèn)實現(xiàn)干茉。
interface Clickable {
fun click() // 正常方法
fun showOff() = println("I'm clickable!") // 方法的默認(rèn)實現(xiàn)
}