Kotlin入门____类和对象(二)

来源:互联网 发布:网络直播推广软文 编辑:程序博客网 时间:2024/06/13 00:20

在上一章学习了Kotlin基础语法,以及简单介绍了下Kotlin,这一节将会接着前面的学习类和对象,在上一节基础上进阶学习

Kotlin中类和java中一样用class声明,一个类文件由类名,类头和由大括号包围的类体构成。类头和类体是可选的,如果没有类体大括号是可以不写的。

//一个空的类class Empty

主构造函数

在Kotlin中一个类是有一个主构造函数的,这个主构造函数是类头的一部分,跟在类名后面

class Person constructor(firstName: String) {}

如果在主构造函数中没有任何注解或者可见修饰符,可以不写构造函数关键字,有就必须写。

class Person(firstName: String) {}

如果没一个有任何入口参数,Kotlin会初始化一个默认的构造函数。

而如果我们要在构造函数中写初始化代码,我们可以将其放在init代码块中,在自定义控件中一般做一些初始化熟悉,自定义属性,和画笔初始化操作。

init{//初始化代码}

注意:主构造函数的属性,可以在类体的属性初始化器中使用

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

次构造函数

类中也可以有重载式的构造函数,类之间的构造函数委托需要用this关键字委托给主构造函数,如果类没有主构造函数,需要用super委托给基类构造函数。

//this(name)委托自己给主构造函数class Person(val name: String) {    constructor(name: String, parent: Person) : this(name) {    }}

构造函数的默认可见性是public,如果你希望构造函数是不可见的,则需要声明一个带有非默认的可见性的空的主构造函数

class DontCreateMe private constructor () {}

构造函数的参数都可以带一个默认值,当构造函数所有的都有默认值,则编译器会生成一个额外的无参数构造函数

创建类的实例

要创建类的实例,我们只需要普通的调用构造函数既可,在Kotlin中是没有new关键字,我们去调用时只需要像java中省去new关键字,其他和java的一样创建,分号在Kotlin中可以不写。

val invoice = Invoice()val customer = Customer("Joe Smith")

继承

在Kotlin中所有的类都有一个共同的超类Any,对于没有任何声明的超类,超类类型默认是Any,它和java.lang.Object不一样,除了equals()、hashCode()和toString()外没有任何成员。要声明超类时候只需要将其放在类头冒号后面

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

基类类型可以直接初始化主类的主构造函数,而open是可以让主类可以直接被继承,在Kotlin中每一个类默认都是final类型,即是不可被继承的,要想被基类继承就需要用open关键字声明。并且和java不同的是,Kotlin需要显示标明可以被覆盖的成员(属性和方法)。基类继承主类的方法需要用override标注,不加,编译器就会报错。

Kotlin需要用open显示标明可以被覆盖的成员方法和熟悉,并且用override标明覆盖后的成员,这一点和java是有些不同的。

//方法覆盖open class Base {    open fun v() {}    fun nv() {}}class Derived() : Base() {    override fun v() {}}//属性覆盖open class Foo {    open val x: Int get { …… }}class Bar1 : Foo() {    override val x: Int = ……}class Bar2(override val count: Int) : Foo

抽象类

抽象类用abstract标注,不需要用open标注一个抽象类或者函数,可以用抽象成员覆盖一个非抽象的开放成员。

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

属性声明

Kotlin中类属性的声明可以用var表示可变或者val表示只读。

Getters 和 Setters

声明一个属性的完整语法是

var <propertyName>[: <PropertyType>] [= <property_initializer>]    [<getter>]    [<setter>]

其中如果属性类型可以从初始器上下文中推断出来,是可以省略的。

一个只读属性的语法和一个可变的属性的语法有两方面的不同:1、只读属性的用 val开始代替var 2、只读属性不允许 setter。

幕后字段

Kotlin中类是不能有字段的。但是当我们定义自定义访问器时,有时有一个幕后字段是有必要的,所以我们可以通过field标识符访问这个字段

var counter = 0 // 此初始器值直接写入到幕后字段  set(value) {    if (value >= 0)      field = value  }

延迟初始化属性lateinit

在有些时候属性声明为非空类型必须在构造函数中初始化。然而这是不方便的,比如我们使用Andoid的Context,你不能在声明的时候就提供其一个非空初始器,但你依然想在使用时避免空检查,这时你可以使用lateinit 修饰符标注该熟悉。

接口

接口与Java类似,既可以包含抽象方法的声明,也包含实现。与抽象类不同的是,接口无法保存状态。它可以有 属性但必须声明为抽象或提供访问器实现。

使用关键字interface来定义接口

interface MyInterface {   val prop: Int  //抽象的   val propertyWithImplementation: String        get() = "foo"    fun bar()    fun foo() {      // 可选的方法体    }}//实现class Child : MyInterface {    override val prop: Int = 29    //方法的实现需要加override    override fun bar() {        // 方法体    }}

注意:接口中的属性要么是抽象的,要么提供访问器实现,在接口中的属性不能有幕后字段,因此接口中的声明的访问器不能引用声明的属性。

覆盖冲突

由于可以实现多个接口,必然会出现冲突问题,即多个接口之间可能有相同方法,所以我们实现时,需要实现多个接口继承的所有方法。这一规则适用于单个实现也可以适用于继承多个实现的方法。

可见性修饰符

Kotlin有四个可见性修饰符:private, protected, internal和public,如果没有显示指定修饰符的话,默认是public。

函数,属性和类,对象和接口可以在顶层声明,即直接在包内。

包中声明的可见性

  • 如果你不指定任何可见性修饰符,默认为 public,这意味着你的声明 将- 随处可见;
  • 如果你声明为 private,它只会在声明它的文件内可见;
  • 如果你声明为 internal,它会在相同模块内随处可见;
  • protected 不适用于顶层声明。
// 文件名:example.ktpackage fooprivate fun foo() {} // 在 example.kt 内可见public var bar: Int = 5 // 该属性随处可见    private set         // setter 只在 example.kt 内可见internal val baz = 6    // 相同模块内可见

类内部声明成员的可见性

  • private 意味着只在这个类内部(包含其所有成员)可见;
  • protected—— 和 private一样 + 在子类中可见。
  • internal —— 能见到类声明的 本模块内 的任何客户端都可见其 internal 成员;
  • public —— 能见到类声明的任何客户端都可见其 public 成员。

如果覆盖了一个可见性成员,但是没有指明其可见性,该成员还是和父类一样的可见性。

局部变量,函数和类不能有可见性修饰符。

注意:模块和Android中的module一样,一个模块是编译在一起的一套Kotlin文件。

总结

这是第一部分类和对象基础的总结.