Skip to content

Latest commit

 

History

History
230 lines (169 loc) · 7.01 KB

7类和对象.md

File metadata and controls

230 lines (169 loc) · 7.01 KB
  • 类和对象
    • kotlin类定义由类名,类头(指其范型声明、主构造器等)和用花括号包围的类体构成。类头和类体都是可选的。空类没有实际意义。

      • 属性用于定义该类的对象所包含的状态数据。
      • 方法定义该类的行为特征或者功能实现。
      • 构造器用于构造该类的对象。

      一个类有0-1个主构造器和0-N个次构造器,主构造器是类头的一部分,跟在类名(和范型声明)后。

    class User constructor(first: String){}
    • kotlin类大致有如下作用:
      • 定义变量
      • 创建对象
      • 派生子类
    • 创建对象的根本途径是构造器,调用某个类的构造器便可创建这个类的对象,无须使用new关键字。
    class Person{
      var name: String = ""
      var age: Int = 0
      fun say(content:String){
        println(content)
      }
    }
    var p:Person
    
    p = Person()
  • this关键字:作为对象的默认引用有两种形式:

    • 在构造器中引用改构造器正在初始化的对象。
    • 在方法中引用调用该方法的对象。
  • 方法是类或者对象行为特征的抽象。kotlin方法与函数是统一的。不仅定义函数和方法的语法相同,而且定义在类中的方法依然可独立出来。也就是说,即时我们将方法定义在类里面,这个方法也依然可以转化为函数。

    fun main(){
      var rn:(Dog)->Unit = Dog::run
    	var dog = Dog()
      rn(dog)
      var en = Dog::eat
      en(dog,"骨头")
    }
    
    class Dog{
        fun run(){
            println("run 方法")
        }
        fun eat(str:String){
            println("eat 方法,吃$str")
        }
    }
  • 中缀表示法 方法中用infix修饰后方法可通过中缀表示法调用。infix修饰方法只能有一个参数。

fun main(){
    var applePack = ApplePack(1.2)
    println(applePack.toString())

    var apple = Apple(2.4)
    println(apple.toString())

    var otherApple = Apple(1.1)
    println(apple.add(otherApple).toString())
    println(apple.drop(otherApple).toString())

    val ap = apple add Apple(1.1)
    println(ap)
    var dp = apple drop Apple(1.1)
    println(dp)
}

class ApplePack(weight:Double){
    var weight = weight
    override fun toString(): String {
        return "ApplePack[weight=${this.weight}]"
    }
}

class Apple(weight: Double){
    var weight = weight
    override fun toString(): String {
        return "Apple[weight=${this.weight}]"
    }
    infix fun add(other:Apple):ApplePack{
        return ApplePack(this.weight+other.weight)
    }

    infix fun drop(other: Apple):Apple{
        this.weight -= other.weight
        return this
    }
}
  • 类的componentN方法(解构) 类似js原理。从一个对象一次性解析出多个属性给不通的变量。Map中的(key,value)便利使用这个方式。 希望解析多少个变量,那么就需要在类中定义多少个componentN方法。如果有不希望要的属性,使用"_"进行忽略。

​ Map中for((key,value) in map)因为Map包含一个operator修饰的iterator()方法,且该方法返回Iterator<Map<K,V>>对象.Iterator代表了可迭代的对象,它的泛型参数代表了被迭代的元素类型——Map.Entry<K,V>(Entry是Map的嵌套类),而Map.Entry则定义了如下两个方法:(我没找到)

operator fun <K,V> Map.Entry<K,V>.component1() = getKey()
operator fun <K,V> Map.Entry<K,V>.component2() = getValue()
fun main(){

    var (name,pass) = User("张三","abcd",20)
    println("结果为:name=$name,pass=$pass")

    var (_,e,f)= User("张三","abcd",20)
    println("结果为:pass=$e,age = $f")

}


class User(name:String,pass:String,age:Int){
    var name = name
    var pass = pass
    var age = age

    operator fun component1():String{
        return this.name
    }

    operator fun component2():String{
        return this.pass
    }

    operator fun component3():Int{
        return this.age
    }
}
  • 数据类

    为了简化解构的实现,Kotlin提供了一种特殊的类:数据类。数据类专门用于封装数据。

    • 数据类需要data修饰。
    • 主构造器至少需要有一个参数。
    • 主构造器的所有参数需要用val或者var声明为属性。
    • 数据类不能用abstract、open、sealed修饰,也不能定义成内部类。

    定义数据类后,系统自动会为类生成:

    • 生成equals()/hashCode()方法
    • 自动重写toString()方法。
    • 为每个属性自动生成operator修饰的componentN()方法。
    • 生成copy方法,用于完成对象复制
  • 延迟初始化属性 使用lateinit修饰符来解决属性的延迟初始化。

    • 只能修饰在类体重声明的可变属性,使用val声明的属性不行,在主构造器中声明的也不行。
    • 不能有自定义的getter或setter方法。
    • 必须是非空类型。
    • 不能是原生类型,即java的8种基本类型对应的类型
  • 构造器

    kotlin允许主构造器上声明属性,直接在参数前使用var或者val。如果主构造器的所有参数都有默认值,程序能以构造参数的默认值来调用该构造器。

    初始化代码块中的数据,在编译后会添加到已有的所有构造器中

  • 类的继承

    继承是面向对象的三大特征之一,也是实现软件复用的重要手段。kt继承是单继承,每个子类最多只有一个直接父类。从子类的角度来看,子类扩展了父类;从父类的角度来看,父类派生出了子类。扩展和派生所描述的是同一个动作,只是观察的角度不同而已。

    如果定义一个类并未显示指定这个类的直接父类,则这个类默认扩展Any类。Any类不是java.lang.Object类。它只有equals()、hashcode()、toString()这3个方法。kt默认使用final修饰类。为类让一个类能派生子类,需要使用open修饰该类。

  • 类的方法重写

    当子类有多个超类(一个直接父类和多个接口)方法名一样,需要使用super<类名>.方法名 来调用执行父类哪个方法。

    fun main(){
        var b = B()
        b.test()
        b.play()
    }
    
    open class SuperT{
        open var a:String = "SuperT-->a"
        open fun play(){
            println("SuperT play")
        }
    
       fun test(){
          println("SuperT test")
     		}
      
    //  private fun test(){  //当父类方法私有,则子类必须重写接口中的方法。当非私有,该方法默认继承到子类,也相当于重写了接口中的同名方法
     //       println("SuperT test")
     //   }
    }
    
    interface SuperB{
        var a: String
        fun play(){
            println("SuperB play")
        }
        fun test()
    
    }
    
    class B:SuperT(),SuperB{
    //    override fun test() {
    //        println("SuperB test")
    //    }
    
        override fun play() {
    //        super<SuperT>.play()  //指定调用哪个父类方法
    //        super<SuperB>.play()
            println("B中的play"); //当不调用父类方法。执行后输出打印结果 B中的play
        }
    }