Kotlin学习笔记:类和接口

Kotlin学习笔记:概述
Kotlin学习笔记:基本语法和函数
Kotlin学习笔记:类和接口
Kotlin学习笔记:lambda编程
Kotlin学习笔记:类型系统
Kotlin学习笔记:泛型
Kotlin学习笔记:注解和反射

类和接口思维导图

在Kotlin中,类默认是final和public的。如果该类需要被继承,则可以用open关键字显示的声明类。

可见性修饰符

image.png

构造方法

Kotlin引入了constructor和init关键字。constructor关键字用于声明一个主构造方法或者从构造方法。而init是一个初始化语句块。这个语句块会在类创建时,与主构造方法一起使用。因为主构造方法不能包含初始化代码。

class User constructor(_name: String){
    val name: String
    init {
        this.name = _name
    }
}

从构造方法

虽然大多数在Java中需要重载的构造方法场景都可以使用参数默认值和参数命名的方法解决掉,但是,还是有些场景需要声明多个构造方法,以便于以不同的方式初始化类。

例如,在Android中自定义View,往往就需要声明多个构造方法。此时,可以使用从构造方法。从构造方法可以声明任意多个。

class CustomView: View {
    constructor(context: Context) : super(context) {
        //...
    }
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        // ...
    }
}

内部类

与java不同的是,默认情况下,内部类不能访问外部类。如果内部类想要访问外部类,需要使用inline关键字显示声明内部类。

image.png

sealed 类(密封类)

如果父类使用sealed修饰符,那么它会对可能创建的子类做出严格限制,并且所有子类必须嵌套在父类中。

数据类

在Java中,会出现很多样板代码,比如setter/getter,toString,equals,hashCode等方法。为了消除这些样板代码,Kotlin引用了数据类,即使用data关键字修饰类即可。

下面我们创建了一个User数据类,它有两个属性,姓名和年龄。

data class Person(val name:String, val age: Int)

在使用时,我们可以直接user1.name或user1.toString()调用。

为了更清楚的看到数据类是如何工作的,我们可以查看这个类的字节码。将字节码反编译为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;
      }
   }
}

由此可见,在编译器将代码编译为字节码时,为User类自动添加了上述这些方法。

除了常用的toString等方法外,还自动生成了一个copy方法。那么,这个copy方法的作用是什么呢?为了让使用不可变对象的数据类变得更容易,Kotlin提供了一个copy方法,以便于通过创建副本的方式修改数据类

object关键字

object关键字有三种应用场景:

  • 单例
  • 伴生对象(companion object)
  • object表达式,可以替代Java匿名内部类

单例

object声明将 类声明和单一实例声明结合在一起。下面创建一个object

object ObjectDemo{  
}

反编译为Java代码为

public final class ObjectDemo {
   public static final ObjectDemo INSTANCE;

   static {
      ObjectDemo var0 = new ObjectDemo();
      INSTANCE = var0;
   }
}

companion object

可以包含工厂方法或者与该类相关但不需要该类实例的方法。因为顶层函数不能访问类的私有方法,而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表达式

可以替代匿名内部类

        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接口方法可以有默认实现。

interface Clickable {
    fun click() // 正常方法
    fun showOff() = println("I'm clickable!") // 方法的默认实现
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,252评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,886评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,814评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,869评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,888评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,475评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,010评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,924评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,469评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,552评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,680评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,362评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,037评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,519评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,621评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,099评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,691评论 2 361

推荐阅读更多精彩内容

  • 写在开头:本人打算开始写一个Kotlin系列的教程,一是使自己记忆和理解的更加深刻,二是可以分享给同样想学习Kot...
    胡奚冰阅读 1,424评论 5 11
  • Kotlin的类和接口与Java的类和接口是有一定的区别的。Kotlin的接口是可以包含属性声明。Kotlin默认...
    程自舟阅读 10,340评论 0 11
  • 面向对象编程(OOP) 在前面的章节中,我们学习了Kotlin的语言基础知识、类型系统、集合类以及泛型相关的知识。...
    Tenderness4阅读 4,449评论 1 6
  • 嵌套类和内部类 大部分时候,类被定义成一个独立的程序单元。在某些情况下,也会把一个类放在另一个类的内部定义,这个定...
    凌寒天下独自舞阅读 488评论 0 0
  • 戏精独白 这一个月来,我通过各种折腾,勾搭到的人可不少啊!5个哪够啊!起码得乘以6~ 恩,666~ 勾搭的7种姿势...
    Peter_333e阅读 773评论 0 0