基本类型

类和对象

类和继承

Kotlin中使用关键字class声明类

class Person{
}

类的声明由类名类头(指定类的类型参数、主构造函数等)和类体(后面花括号包围的部分);如果一个类没有类体,可以省略花括号。

class Person

构造函数

在Kotlin中一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数是类头的一部分:它跟在类名(和可选的类型参数)后。

class Person constructor(firstName: String){
}

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

class Person(firstName: String){
}

主构造函数不包含任何代码。初始化代码可以放在以init关键字作为前缀的初始化块(initializer block)中:

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

注意主构造函数的参数可以在初始化块中使用。也可以在类体内声明属性时,在属性的初始化器中使用:

class Customer(name: String){
    init{
        logger.info("Customer initialized with value ${name}") //在初始化块中使用主构造函数的参数
    }
    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){
    //do some thing
}

次构造函数

类也可是声明前缀有constructor次构造函数

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

如果类有主构造函数,每个次构造函数都需要委托给主构造函数,可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用this关键字即可:

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

如果一个类非抽象并且没有声明任何(主或次)构造函数,它会默认生成一个无参的主构造函数。并且这个默认无参构造函数的可见性为public。如果你不希望你的类有一个公有的构造函数,你需要声明一个带飞默认可见性的空主构造函数:

class DontCreatMe private constructor(){
}

在JVM上,如果主构造函数的所有参数都有默认值,编译器会生成一个额外的无参构造函数,它将使用默认值,这使得Kotlin更易于使用像Jackson或JPA这样通过无参构造函数创建类的实例的库。

class Customer(val customerName: String = "")

创建类的实例

要创建类的实例,我们只需要像调用普通函数一样调用构造函数:

val user = User()
val customer = Customer("Jon Smith")

可以发现Kotlin中创建类的实例,是不需要new关键字的,Kotlin中也没有这个关键字

类成员

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

继承

在Kotlin中所有类都有一个共同的超类Any,所有类都直接或间接派生自这个类,类似Java中的Object

class Example (){//默认派生自Any
}

但是,Any并不是java.lang.Object;它除了equalshasCode()toString()外没有其它成员。
要继承一个类,我们把超类放到派生类的类头的冒号后面:

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)
}

在Kotlin中,open标注与Java中的final相反,它标注的类才允许被其他类继承。默认情况下,在Kotlin中所有的类都是final的,这正对应了Effective Java中的要么为继承而设计,并提供文档说明,要么禁止继承。

覆盖方法

在Kotlin中力求清晰显式。与Java不同,Kotlin中需要显式标注可以被覆盖的成员(或称开放的成员)和覆盖后的成员:

open class Base {
    open fun v(){} //可以被复写的成员用open标注
    fun nv(){}
}
class Derived() : Base(){
   final override fun v(){} //复写后的成员用override标注,默认override标注的成员也是开放的,如果想再次限制其被覆盖可以显式的用final标注
}

覆盖属性

属性覆盖和方法覆盖类似;在子类中声明超类中的同名属性就是覆盖超类中的属性,并且必须以override开头作为标注,并且它们的类型必须兼容。每个声明的属性可以由具有初始化器的属性或者具有getter方法的属性覆盖。

open class Foo{
    open val x: Int?= null
        get(){//重写get方法
            field = 100
            return field
        }
}
class Bar1 : Foo(){
    override val x: Int? = null
}

在Kotlin中,属性都有默认的getset方法,并且可以被重写,如上面的例子。如果子类中覆盖了父类中的属性,那么在父类中重写的被覆盖属性的get方法,在子类中是无效的。

val可以被var覆盖
但是var不能被val覆盖

覆盖规则

如果一个类从它的直接超类继承相同成员的多个实现,那么这个类必须必须覆盖这个成员并提供自己的实现(或者用继承来的其中之一)。为了表示采用从哪个超类中继承的实现,我们使用super<Base>表示:

open class A {
    open fun f() { 
        print("A") 
    } 
    fun a() { 
        print("a") 
    }
}
interface B {
    fun f() { 
        print("B") 
    } // 接口成员默认就是“open”的,并且可以有实现
    fun b() { 
        print("b") 
    }
}
class C() : A(), B {
    // 编译器要求覆盖 f(): 
    override fun f() {
        super<A>.f() // 调用 A.f()
        super<B>.f() // 调用 B.f() 
    }
}

C同时继承了两个不同f()实现,所以必须在C中覆盖f()并且提供自己的实现来消除歧义。

抽象类

类和其中某些成员可以声明为abstract的。抽象成员在本类中可以不实现。抽象类默认是开放的,不需要用open关键字标注。并且我们可以用一个抽象成员覆盖一个非抽象的开放成员

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

伴生对象

在Kotlin中没有静态方法。在大多数情况下,它建议采用包级函数(在类外面与包在一个级别)。
如果你需要写一个无需类的实例来调用,但需要访问类内部的的函数,你可以把它写成该类内对象声明中的一员,而不是类本身的成员。
这里说的类内声明的对象,就是伴生对象,伴生对象内声明的成员只需要类名作为限定符就可以访问,语法与Java/C#中调用静态方法一样。

封闭类或密封类

用来限制类的继承,可以限制给定的某个对象只可能是某些指定的类型之一。有点像枚举。枚举类的值是有限的,每个枚举值常数都代表枚举类的一个实例,而密封类允许的子类类型是有限的,但每个子类的实例数并未做限制。
如何声明密封类?

  1. 使用sealed修饰符放在class关键字之前;
  2. 子类声明必须嵌套在密封类声明部分之内;

如:

sealed class Expr {
    class Const(val number:Double):Expr()
    class Sum(val e1: Expr,val e2: Expr):Expr()
    object NotAnumber : Expr()//这里声明的是个单利类
}

用途:
when表达式中可以验证分支语句覆盖了所有条件,避免使用else分支处理例外情况。

sealed class Expr {
    class Const(val number:Double):Expr()
    class Sum(val e1: Expr,val e2: Expr):Expr()
    object NotAnumber : Expr()
}

是否还有其他更有用的用途呢?

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

推荐阅读更多精彩内容