zoukankan      html  css  js  c++  java
  • kotlin类和对象—>类与继承

    1.类的定义,kotlin中依旧使用关键字class声明类,类声明由类名、类头(指定其类型参数、主构造函数等)以及由花括号包围的类体构成。类头与类体都是 可选的;如果一个类没有类体,可以省略花括号。

    //1.简单定义
    class Invoice { /*......*/ }
    //2.没有类体时
    class Empty

    2.构造函数,在 Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。主构造函数是类头的一部分

    //1. 它跟在类名(与可选的类型参数)后
    class Person constructor(firstName: String) { /*......*/ }
    
    //2. 如果主构造函数没有任何注解或者可⻅性修饰符,可以省略这个 constructor 关键字。
    class Person(firstName: String) { /*......*/ }
    
    //3.主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化块(initializer blocks)中。
    // 在实例初始化期间,初始化块按照它们出现在类体中的顺序执行,与属性初始化器交织在一起
    class InitOrderDemo(name: String) { val firstProperty = "First property: $name".also(::println) init { println("First initializer block that prints ${name}") } val secondProperty = "Second property:${name.length}".also(::println) init { println("Second initializer block that prints ${name.length}") } }


    输出结果:

    First property: 1
    First initializer block that prints 1
    Second property:1
    Second initializer block that prints 1
     

         主构造的参数可以在初始化块中使用。它们也可以在类体内声明的属性初始化器中使用

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

        声明属性以及从主构造函数初始化属性,也可以如此写

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

       与普通属性一样,主构造函数中声明的属性可以是可变的(var)或只读的(val)。

       如果构造函数有注解或可⻅性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前面

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

    3.次构造函数:可以声明前缀有constructor的次构造函数

    class Person {
         var children: MutableList<Person> = mutableListOf<>() 
         constructor(parent: Person) {
             parent.children.add(this) 
         }
    }

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

    class Person(val name: String) {
        var children: MutableList<Person> = mutableListOf<>() 
        constructor(name: String, parent: Person) : this(name) {
            parent.children.add(this) 
        }
    }

       构造函数的运行顺序,是先运行主构造函数,即使为声明,如果有init代码块,也会在次构造函数体之前执行,其实跟java的代码块逻辑相同

    class Constructors { 
    
       init {
          println("Init block")
       }
    
       constructor(i: Int) {
          println("Constructor")
       }
    
     }

    运行结果

         Init block
         Constructor

    
    

    4.创建类,就像普通函数一样调用,在kotlin中没有new关键字

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

    5.kotlin中所有类的超类为 Any ,存在三个方法 equals() 、hashCode() 与 toString(),默认情况下kotlin中所有的类都是final,如果需要被继承,则需要加open

     open class Base //Class is open for inheritance
    
     //例:
     open class Base(p: Int)
     class Derived(p: Int) : Base(p)
    
     //注意:如果派生类有主构造函数,其基类必须用派生类主构造函数的参数就地初始化

    6.覆盖方法,kotlin中对于可覆盖的成员(或成为open开放的)覆盖后的成员需要显示修饰符

    open class Shape {
           open fun draw() { /*......*/ } 
           fun fill() { /*......*/ }
    }
    
    class Circle() : Shape() { 
         override fun draw() { /*......*/ }
    }
    
    //Circle.draw() 函数上必须加上 override 修饰符。
    //如果没写,编译器将会报错。如果函数没有标 注open如 Shape.fill(),那么子类中不允许定义相同签名的函数,不论加不加override。将 open 修饰符添加到 final 类(即没有 open 的类)的成员上不起作用。
    //标记为 override 的成员本身是开放的,也就是说,它可以在子类中覆盖
    
    
    
    //如果想禁止再次被覆盖,使用final关键字
    open class Rectangle() : Shape() {
         final override fun draw() { /*......*/ }
    }

    7.覆盖属性,于覆盖方法,基本一样

    //1.例子
    open class Shape {
       open val vertexCount: Int = 0
    }
    class Rectangle : Shape() { 
       override val vertexCount = 4
    }
    
    //2.例子
    interface Shape {
        val vertexCount: Int
    }
    class Rectangle(override val vertexCount: Int = 4) : Shape // 总是有 4 个顶点
    
    class Polygon : Shape {
          override var vertexCount: Int = 0 // 以后可以设置为任何数,val变为了var
    }

       注意:设计一个基类时,应该避免在构造函数、属性初始化器以及 init 块中使用 open 成员。

    8.调用超类实现

      8.1 派生类中可以通过super调用超类中的函数和属性访问器

    open class Rectangle {
          open fun draw() { println("Drawing a rectangle") } 
          val borderColor: String get() = "black"
    }
    
    class FilledRectangle : Rectangle() { 
          override fun draw() {
              super.draw()
              println("Filling the rectangle") 
          }
          val fillColor: String get() = super.borderColor
    }

      8.2在内部类中访问外部类的超类,可以通过外部类名限定的super关键字来实现:super@Outer

    class FilledRectangle : Rectangle() {
        override fun draw() { /* ...... */
        }
    
        override val borderColor: String get() = "black"
    
        inner class Filler {
            fun fill() { /* ...... */
            }
    
            fun drawAndFill() {
                super@FilledRectangle.draw() // 调用 Rectangle 的 draw() 实现 fill()
                println("Drawn a filled rectangle with color${super@FilledRectangle.borderColor}") // 使用 Rectangle 所实现的 borderColor 的 get()
            }
        }
    }

    9.覆盖规则在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现,它必须 覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。为了表示采用从哪个超类型继承的实 现,我们使用由尖括号中超类型名限定的 super,如 super<Base>

    open class Rectangle {
         open fun draw() { /* ...... */ }
    }
    interface Polygon {
         fun draw() { /* ...... */ } // 接口成员默认就是“open”的
    }
    class Square() : Rectangle(), Polygon { 
        // 编译器要求覆盖 draw():
        override fun draw() {
            super<Rectangle>.draw() // 调用 Rectangle.draw()
            super<Polygon>.draw() // 调用 Polygon.draw() 
        }
    }

    10.抽象类,在kotlin中可以用抽象类/成员去覆盖一个非抽象的类/成员

    open class Polygon { 
          open fun draw() {}
    }
    
    abstract class Rectangle : Polygon() { 
         abstract override fun draw()
    }

    11.伴生对象 如果你需要写一个可以无需用一个类的实例来调用、但需要访问类内部的函数(例如,工厂方法),你可 以把它写成该类内对象声明中的一员。

    更具体地讲,如果在你的类内声明了一个伴生对象,你就可以访问其成员,只是以类名作为限定符。

  • 相关阅读:
    SecureCRT显示乱码的解决办法
    Django如何安装指定版本
    转战简书
    NSmutableArray 的实现原理机制
    字符编码笔记:ASCII,Unicode 和 UTF-8
    [每天记录一个Bug]Cell中由于block加载网络请求产生的复用
    提示的简易写法
    价格不同字体大小的富文本实现方式
    星星的模块封装类 IDSStarsScoreView
    性别年龄的模块封装类 IDSGenderLeviNamedView
  • 原文地址:https://www.cnblogs.com/developer-wang/p/13163349.html
Copyright © 2011-2022 走看看