Kotlin类和继承

原文地址

Classes

类在Kotlin中使用class关键字被声明

class Invoice {
}

类声明由类名和类头组成(指定它的类型参数,主要构造函数等等)。被花阔号括起来的类体。类头和类体是可选的。如果那个类没有类体,花括号能够被省略。

class Empty

Constructors(构造器)

在Kotlin中一个类能够有一个主要构造函数和一个或多个次级构造函数。首要构造函数是类头的一部分:他在类名后面(可选类型参数)

class Person constructor(firstName: String) {
}

如果主要构造函数没有任何注解和可见修饰符,constructor关键字可以被省略:

class Person(firstName: String) {
}

主要构造函数不能包含任何代码。初始化代码能够放到以init为前缀的初始化器中。

class Customer(name: String) {
    init {
        logger.info("Customer initialized with value ${name}")
    }
}

注意:主要构造函数的参数能够被用于初始化代码块中。他们也能被用于类体中的属性值初始化。

class Customer(name: String) {
    val customerKey = name.toUpperCase()
}

事实上,为了声明属性值并且在主要构造函数中初始化,Kotlin有一个简洁的语法:

class Person(val firstName: String, val lastName: String, var age: Int) {
    // ...
}

普通的属性值很相似,在主要构造函数中声明的属性值有能够被改变(var)或者只读(val)两种
如果一个构造函数有注解或者可见修饰符,constructor关键字是被需要的,并且修饰符在它之前

class Customer public @Inject constructor(name: String) { ... }

关于更多细节,参看Visibility Modifiers

Secondary Constructors(次级构造器)

类也能被声明为以constructor关键字为前缀的次级构造器。

class Person {
    constructor(parent: Person) {
        parent.children.add(this)
    }
}

如果类有一个主要构造器,每一个次级构造器需要去代理主构造器,直接或者间接的方式通过另一个次级构造器。代理同一类的另一个构造器使用this关键字:

class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

如果一个非抽象的类不声明任何构造器(主要的或者次级的),它将生成一个没有参数的构造器。构造器的可见性将是public。如果你不想你的类有一个公共构造器。你需要声明一个不带默认可见性的空的构造器:

class DontCreateMe private constructor () {
}

注意:在JVM中,如果所有主要构造器的参数有默认值,编译器将会生成一个额外的无参使用默认值的构造器。这将使Kotlin使用像Jackson或者JPA创建class实例通过无参构造函数变得容易。

class Customer(val customerName: String = "")

Creating instances of classes(创建类实例)

为了创建一个类的实例,我们调用构造器如果它是一个常规的函数:

val invoice = Invoice()

val customer = Customer("Joe Smith")

注意Kotlin没有new关键字
创建一个嵌套的,内部的,匿名内部类的实例在 Nested classes中有描述

Class Members(类成员)

类能够包含:

  • 构造参数和初始化器
  • 函数
  • 属性值
  • 嵌套和内部类
  • 对象声明

Inheritance(继承)

所有在Kotlin中的类有一个公共的超类Any。这是一个默认的没有任何超类型被声明的超类。
···
class Example // Implicitly inherits from Any
···

Any 不是java.lang.object;在特殊情况下,它不包含任何的成员变量除了equals(), hashCode()toString().更多细节请参考Java interoperability

为了声明一个明确的超类型,我们把类型放置到类标题的分号后:

open class Base(p: Int)

class Derived(p: Int) : Base(p)

如果类有一个首要的构造函数,基本类型必须在这里初始化并使用首要构造函数的参数。
如果一个类没有首要构造函数,那么每个次级构造函数必须初始化基本类型使用super关键字。或者委托给另一个构造函数做这件事。注意在这种情况下不同的次级构造函数可以调用不同的基本类型的构造函数。

class MyView : View {
    constructor(ctx: Context) : super(ctx)

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

在一个类上的open注解是java’s final的反义词;它允许其他类继承于这个类。默认情况下,在Kotlin中所有的类是final的,这是符合Effective Java, Item 17: Design and document for inheritance or else prohibit it.

Overriding Methods(重写方法)

正如我们之上所提出的,在Kotlin中,我们执着于让事情变的明确,不像Java,Kotlin需要明确的的注解对于可重写成员(我们称之为open)和要重写的。

open class Base {
    open fun v() {}
    fun nv() {}
}
class Derived() : Base() {
    override fun v() {}
}

Derived.v()需要有重写注释,如果它缺失了,编译器将会报警。如果没有open注解在函数上,像Base.nv(),用相同的签名声明方法在子类中是非法的,不管有没有override关键字。在一个final类中(也就是没有open注解的类),open成员是被禁止的。
一个成员被标记为override它本身是open,也就是可能在子类中被重写。如果你想禁止重写,用final:

open class AnotherDerived() : Base() {
    final override fun v() {}
}

Overriding Properties(重写属性)

重写属性的工作方式与重写方法相同;在超类中声明的属性在子类中再次声明必须以override为开始,并且他们必须有一个可兼容的类型。每个声明的属性能够被重写通过一个带有初始化器的属性或者有getter函数的属性。

open class Foo {
    open val x: Int get { ... }
}

class Bar1 : Foo() {
    override val x: Int = ...
}

你也可以用一个var属性重写一个val属性,但反之则不然。这样被允许是因为val属性必须声明一个getter函数,把它当做一个var重写需要额外的声明一个setter函数在子类中。
注意:你能够使用override关键字作为首要构造函数的部分声明属性。

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}

Overriding Rules(重写规则)

在Kotlin,继承实现是被如下规则管制:如果一个类从它的直接超类中继承了很多同一成员的实现,它必须重写这个成员并且提供它自己的实现(可能,使用被继承的某一个)。为了表示被继承实现的超类型,我们可以使用超限定名通过尖括号中的超类型名称,也就是super<Base>:

open class A {
    open fun f() { print("A") }
    fun a() { print("a") }
}

interface B {
    fun f() { print("B") } // interface members are 'open' by default
    fun b() { print("b") }
}

class C() : A(), B {
    // The compiler requires f() to be overridden:
    override fun f() {
        super<A>.f() // call to A.f()
        super<B>.f() // call to B.f()
    }
}

同时继承A和B是ok的,对于a()和b()这里没有问题因为c继承了这些函数的一种实现。但是对于f()我们有两种被c继承的实现,因此我们必须重写在c中重写f()并且提供我们自己的实现去消除歧义。

Abstract Classes(抽象类)

一个类和它的成员可能被声明为abstract。一个抽象的成员在它的类中没有实现。注意我们不需要注解一个抽象类或者函数通过open-它是不需要说明的
我们可以重写一个非抽象open成员通过一个抽象的

open class Base {
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}

Companion Objects(伴随体)

在Kotlin中,不像Java或者C#,类没有静态成员,多数情况下,建议只使用包级别的函数。
如果需要一个没有类实例但能被访问类内部且能够被调用的函数(例如,一个工厂函数),你可以把它写为一个类中的object declaration 成员
更具体的说,如果你在类中声明一个 companion object,你将能够
调用它的函数使用相同的语法像调用Java/C#中的静态函数那样,仅仅使用类名称当做限定符。

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

推荐阅读更多精彩内容