Kotlin學(xué)習(xí)筆記:類和接口

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í)筆記:注解和反射

類和接口思維導(dǎo)圖

在Kotlin中揍堕,類默認(rèn)是final和public的畔派。如果該類需要被繼承休吠,則可以用open關(guān)鍵字顯示的聲明類凿滤。

可見性修飾符

image.png

構(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)部類。

image.png

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)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市很泊,隨后出現(xiàn)的幾起案子角虫,更是在濱河造成了極大的恐慌,老刑警劉巖委造,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戳鹅,死亡現(xiàn)場離奇詭異,居然都是意外死亡争涌,警方通過查閱死者的電腦和手機粉楚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亮垫,“玉大人模软,你說我怎么就攤上這事∫剩” “怎么了燃异?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長继蜡。 經(jīng)常有香客問我回俐,道長,這世上最難降的妖魔是什么稀并? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任仅颇,我火速辦了婚禮,結(jié)果婚禮上碘举,老公的妹妹穿的比我還像新娘忘瓦。我一直安慰自己,他們只是感情好引颈,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布耕皮。 她就那樣靜靜地躺著境蜕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凌停。 梳的紋絲不亂的頭發(fā)上粱年,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機與錄音罚拟,去河邊找鬼台诗。 笑死,一個胖子當(dāng)著我的面吹牛舟舒,可吹牛的內(nèi)容都是我干的拉庶。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼秃励,長吁一口氣:“原來是場噩夢啊……” “哼氏仗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起夺鲜,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤皆尔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后币励,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慷蠕,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年食呻,在試婚紗的時候發(fā)現(xiàn)自己被綠了流炕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡仅胞,死狀恐怖每辟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情干旧,我是刑警寧澤渠欺,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站椎眯,受9級特大地震影響挠将,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜编整,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一舔稀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸滤淳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至断箫,卻和暖如春拂酣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仲义。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工婶熬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人埃撵。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓赵颅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親暂刘。 傳聞我的和親對象是個殘疾皇子饺谬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容