Kotlin学习笔记之 6 继承

首发于公众号: DSGtalk1989

6.Kotlin 继承

  • Any

    Any是所有类的超类,就像java中的Object。但它并不等同于Object,除了equals()``hashCode()``toString()没有其他任何成员。

  • 继承和实现':'

    之前我们已经知道了接口是interface,可被继承的类是open,抽象类是abstract

    跟java不同的是,java中extends是继承,implements是实现。而在kotlin中跟在:后面,不管是接口还是类,没有先后顺序。也就是说:既可以继承也可以实现,互相用,隔开

    open class Person3 {
         open var sex: String = "unknow"
     
         init {
             println("基类初始化")
         }
     }
     
     interface Grand {
         fun make()
     }
     
     class Student : Grand, Person3() {
         override fun make() {
         }
     
         override var sex: String = "male"
     }
    
  • 基类构造和子类构造

    首先我们先看下最基础的构造,在经过编译之后分别是什么情况的

    • 默认定义

      ```js
      //kt
      class Person(name: String) {    
      }
      
      //decompiled
      public final class Person {
         public Person(@NotNull String name) {
            //无视,这段代码之后会出现很多次
            Intrinsics.checkParameterIsNotNull(name, "name");
            super();
         }
      }
      ```
      

      我们看到经过编译之后,就是定义了一个final的class Personname只是一个构造函数的传参而已

    • var定义

      我们尝试着在构造传参name前加一个var看看,会发现编译之后的差别不是一点点。

      ```js
      //kt
      class Person(var name: String) {    
      }
      
      //decompiled
      public final class Person {
         @NotNull
         private String name;
      
         @NotNull
         public final String getName() {
            return this.name;
         }
      
         public final void setName(@NotNull String var1) {
            Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
            this.name = var1;
         }
      
         public Person(@NotNull String name) {
            Intrinsics.checkParameterIsNotNull(name, "name");
            super();
            this.name = name;
         }
      }
      ```
      

      编译过程帮我们创建了一个同名的属性name,并且提供了namesetget方法,也就是说一旦主构造函数中出现了var(我这边故意重点说了主构造函数,因为次构造函数中无法使用var),那么所描述的这个参数就可以变得在类中可以被访问和修改,name就变成了Person的一部分了。

OK,我们接下去看一下两种情况下作为基类被继承了之后会有什么地方的不同。

前面我们有提到,kotlin中无论使用什么修饰符,对于参数本身来说,编译成java代码之后始终是private的,只是通过getset方法来体现修饰符,

如果我们的子类是这么定义的:

//kt
class Sun(name : String): Person(name){   
}

//decompiled
public final class Sun extends Person {
    public Sun(@NotNull String name) {
       Intrinsics.checkParameterIsNotNull(name, "name");
       super(name);
    }
 }

看起来完全没有问题。这时候我们把name写上var,我们先不反编译,直接按照上面的理解,应该是这样的

```js
//kt
class Sun(var name : String): Person(name){ 
}

//decompiled
public final class Sun extends Person {
   @NotNull
   private String name;

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.name = var1;
   }

   public Sun(@NotNull String name) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
   }
}
```

乍一看,没有问题。但是实际上这么写IDE直接会报错。Sun的方法getNamesetNamepublic final的,由于父类也有相同的方法getNamesetName。犯了java的大忌,子类出现了父类的同名函数,父类的函数还他么是final的。

也就是说,除了父类是非final字段,子类不能出现相同的字段。

综上所述,只要不是open形容的字段,都不能在子类出现重复的字段名。无论是val还是var

  • varval复写关系

    val无法复写var,不要当做概念去背。

    前面我们说过,一个属性必须要用open来形容才能被子类复写。这是其一

    其二,kotlin中我们是直接去操作属性的,因为编译成java文件是通过gettersetter方法做访问和修改。var是可以访问并修改,val只能访问无法修改。

    父类中本身可以访问并修改的,在子类中变得只能访问了,是不允许的。继承关系我们只能拓展而不能缩减,子类必须包含父类。

  • 子类构造函数的影响

    首先,一个类class肯定会有一个构造函数。那么对于子类来说需要注意什么呢。

    我们先来看一个隐式主构造函数的类:

    open class Parent{
    }
    

    我们前面说到,一旦没有显式的跟在类名后面申明constructor,或者(),并且在类体中没有出现次级构造函数constructor。我们就认为有一个隐式的无参的主构造函数。

    这时候我们继承一下,并且尝试着什么都不做

    class Sun : Parent{
    }
    

    你会发现Person下面有根红线报错了,写道

    This type has a constructor, and thus must be initialized here

    父类有构造器,必须要进行初始化。也就是说我们必须显式或者隐式的去调一次Parent的无参的构造函数。

    方式有很多种,我们先看第一种:

    class Sun : Parent(){
    }
    

    直接在父类后面来个括号即可。

    你会发现加()和不加的前后经过编译得到的java文件是一样的,都是

    public final class Sun extends Parent {
    }
    

    实际上,这边我们用有参构造去讲,会更加容易理解。比如我们针对Parent类添加一个有参的主构造函数,并且保留无参构造函数。

    open class Parent(name : String){
    
    }
    

    子类分别调用和不调用父类的构造函数,所编译出来的效果是明显不同的。

    //kt
    class Sun1 : Parent{
    } 
    
    class Sun2 : Parent(){
    } 
    
    class Sun3 : Parent("tom"){
    }
    
    
    //decompiled
    public final class Sun1 extends Parent {
    }
    
    public final class Sun2 extends Parent {
    }
    
    public final class Sun3 extends Parent {
         public Sun3() {
            super("tom");
         }
    }
    

Sun1是无法编译通过的,所以出来的decompiled实际上是没有意义,上面说过调用父类的无参构造和不调用最终出来的结果是一样的,所以我们直接看Sun2即可

Sun2Sun3连在一起看,首先我们知道,在java中,每一个类如果没有单独的去申明他的构造函数,那么他们都将有一个默认的无参构造函数。并且又有继承,所以Sun2实际上是这样的

public final class Sun2 extends Parent {
      public Sun2() {
         super();
      }
 }

Kotlin学习笔记之 1 基础语法

Kotlin学习笔记之 2 基本数据类型

Kotlin学习笔记之 3 条件控制

Kotlin学习笔记之 4 循环控制

Kotlin学习笔记之 5 类和对象

Kotlin学习笔记之 6 继承

Kotlin学习笔记之 7 接口

Kotlin学习笔记之 8 扩展

Kotlin学习笔记之 9 数据类与密封类

Kotlin学习笔记之 10 泛型

Kotlin学习笔记之 11 枚举类

Kotlin学习笔记之 12 对象表达式和对象声明

Kotlin学习笔记之 13 基础操作符run、with、let、also、apply

Kotlin学习笔记之 14 包与导入

Kotlin学习笔记之 15 伴生对象

Kotlin学习笔记之 16 委托

Kotlin学习笔记之 17 可观察属性

Kotlin学习笔记之 18 函数

Kotlin学习笔记之 19 高阶函数与 lambda 表达式

Kotlin学习笔记之 20 内联函数

Kotlin学习笔记之 21 解构声明

Kotlin学习笔记之 22 集合

Kotlin学习笔记之 23 相等判断

Kotlin学习笔记之 24 操作符重载

Kotlin学习笔记之 25 异常捕捉

Kotlin学习笔记之 26 反射

Kotlin学习笔记之 27 类型别名

Kotlin学习笔记之 28 协程基础

Kotlin学习笔记之 29 上下文与调度器

Kotlin学习笔记之 30 协程取消与超时

Kotlin学习笔记之 31 协程挂起函数的组合

Kotlin学习笔记之 32 协程异常处理

Kotlin学习笔记之 33 协程 & Retrofit

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

推荐阅读更多精彩内容