美文网首页
Kotlin基础2

Kotlin基础2

作者: isLJli | 来源:发表于2020-06-27 11:24 被阅读0次

    kotlin的构造方法

    在kotlin中,一个类可以有一个primary构造方法以及一个或多个secondary构造方

    // 在kotlin中,一个类可以有一个primary构造方法以及一个或多个secondary构造方法
    
    //primary构造方法,是类头,它位于类头的后面
    // 如果primary构造方法没有任何注解或者可见性关键字修饰,那么constructor关键字可省略
    class MyCalss constructor(userName:String){
      private val username :String = userName.toUpperCase()
    
      init {
          println(userName)
      }
    }
    
    fun main(args:Array<String>){
      var myCalss = MyCalss("张三")
    }
    
    • primary构造方法,是类头,它位于类头的后面
    • 如果primary构造方法没有任何注解或者可见性关键字修饰,那么constructor关键字可省略

    打印结果:

    张三
    

    对于secondary构造方法必须直接或间接的调用primary构造方法

    class Person constructor(userName:String){
       private var userName:String? = null
       private var age:Int
       private var address:String
    
       init {
           println(userName)
           this.userName = userName
           this.age = 20
           this.address = "guangdong"
       }
    
       //对于secondary构造方法必须直接或间接的调用primary构造方法
       constructor(userName: String,age:Int):this(userName){
           this.age = age
           this.address = "guangdong"
       }
    
       constructor(userName: String,age: Int,address:String):this(userName,age){
           this.address = address
       }
    
       fun printInfo(){
           println("username = ${this.userName},age = ${this.age} , address = ${this.address}")
       }
    }
    
    fun main(args:Array<String>){
      val person = Person("zhangsan")
      val person2 = Person("lisi",30)
      val person3 = Person("wangwu",30,"hangzhou")
      person.printInfo()
      person2.printInfo()
      person3.printInfo()
    }
    

    打印结果:

    zhangsan
    lisi
    wangwu
    username = zhangsan,age = 20 , address = guangdong
    username = lisi,age = 30 , address = guangdong
    username = wangwu,age = 30 , address = hangzhou
    

    构造方法的参数可以当全局变量使用

    class Student(private val userName:String , private val age:Int,private var address:String){
    
      fun printInfo(){
          println("userName= $userName, age = $age , address = $address")
      }
    }
    
    fun main(args:Array<String>){
      val student = Student("zhangsan",20,"shenzhen")
      student.printInfo()
    }
    

    打印结果

    userName= zhangsan, age = 20 , address = shenzhen
    

    构造方法的都拥有默认值

    /**
    * 在JVM上,如果类的primary构造方法的所有都拥有默认值,那么kotlin编译器就会为这个生成一个不带参数的构造方法
    * 在这个不带参数的构造方法会使用这些参数的默认值。
    */
    class Student3 (val userName: String = "zhangsan"){
    
    }
    fun main(args:Array<String>){
      var student3 = Student3()
      println(student3.userName)
    
      student3 = Student3("lisi")
      println(student3.userName)
    }
    

    打印结果:

    zhangsan
    lisi
    

    Kotlin的继承

    • 在kotlin中,所有类和方法默认情况下都是final的,所有类在默认下都是无法被继承的
    • open含义与final相反
    //在kotlin中,所有类默认情况下都是final的,所有类在默认下都是无法被继承的
    // open含义与final相反
    open class Parent(name:String,age:Int){
    
    }
    class Child(name: String,age: Int):Parent(name,age){
    
    }
    
    • 在kotlin中,如果一个类没有primary构造方法,那么这个类的每个secondary构造方法就需要通过super关键字来初始化父构造。
    open class Parent2(name: String){
    
    }
    class Child2:Parent2{
      constructor(name: String):super(name){
    
      }
    }
    
    • Open声明的类,其方法也要声明为open才能被子类重写。
    open class Fruit{
      open fun name(){
          println("fruit")
      }
    
      fun expirationDate(){
          println("1 month")
      }
    }
    
    class Apple:Fruit(){
      override fun name(){
          println("apple")
      }
    }
    
    open class Orange:Fruit(){
      override fun name() {
          println("orange")
      }
    }
    
    fun main(args:Array<String>){
      var apple = Apple()
      apple.name()
      apple.expirationDate()
    }
    

    打印结果:

    apple
    1 month
    

    val的属性不能set

    • 1.val 可以 override val
    • 2.var 可以 override val
    • 3.val 无法 override var
    • 本质上,val相当于get方法,var相当于get与set方法
    open class MyParent3{
      open fun method(){
          println("parent method")
      }
    
      open val name:String get() = "parent"
    }
    
      class MyChild3:MyParent3(){
          override fun method() {
              super.method()
              println("child method")
          }
    
          override val name: String
              get() = super.name+ " and child"
      }
    
    fun main(args:Array<String>) {
      var myChild3 = MyChild3()
      myChild3.method()
      println(myChild3.name)
    }
    

    打印结果:

    parent method
    child method
    parent and child
    

    继承和实现的类有相同的方法

    要么自己重写方法,否则要指明表示那个类的方法。接口有自己的默认方法实现

    //接口默认实现方法
    interface A{
      fun method(){
          println("A")
      }
    
    }
    
    //开放类实现方法
    open class B {
      open fun method(){
          println("B")
      }
    }
    
    //继承类和实现类有同一个方法
    class C:B(),A{
      override fun method() {
         println("C")
      }
    }
    
    //用接口A类的方法
    class D:B(),A{
      override fun method() {
          super<A>.method()
      }
    }
    
    class E:B(),A{
      override fun method() {
          super<A>.method()
          super<B>.method()
      }
    }
    
    fun main(args:Array<String>){
      val c =C()
      c.method()
    
      val d = D()
      d.method()
    
      val e = E()
      e.method()
    }
    

    打印结果:
    C
    A
    A
    B

    伴生对象companion object

    1. 虽然伴生对象的成员看起来向java中的静态成员,但在运行期,依旧是真实对象的实例成员。
    2. 如果不提供伴生对象名字,那么编译器会提供一个默认的名字Companion。
    3. 通过@JvmStatic注解可实现的伴生对象在编译后会生成一个静态内部类、方法、属性。
    // object declaration, 对象声明
    object MyObject{
      fun method(){
          println("method")
      }
    }
    
    fun main(args:Array<String>){
      MyObject.method()
      
      println("----------")
    
      MyTest.MyObject.method()
    
      println("----------")
      //类似于静态方法,Kotlin中没有静态方法
      println(MyTest.a)
      println(MyTest.method())
    
      println("----------")
    
      println(MyTest2.Companion.a)
      println(MyTest2.a)
    
    }
    
    //companion object,伴生对象
    //在Kotlin中,与Java不同的是,类是没有static方法的
    //在大多数情况下,kotlin推荐的做法是使用包级别的函数作为静态方法
    // kotlin会将包级别的函数当作静态方法来看待
    
    //注意:虽然伴生对象的成员看起来向java中的静态成员,但在运行期,依旧是真实对象的实例成员
    //在JVM上,可以将伴生对象的成员真正生成为类的静态方法与属性,这是通过@JvmStatic注解来实现的
    //伴生对象在编译后会生成一个静态内部类
    class MyTest{
    
      //类似于静态方法
      companion object MyObject{
          var a:Int = 1000
          fun method(){
              println("methiod invoked!")
          }
      }
    }
    
    class MyTest2{
    
      //如果不提供名字,那么编译器会提供一个默认的名字Companion
      companion object {
          var a:Int = 1000
          fun method(){
              println("methiod invoked!")
          }
      }
    }
    

    打印结果:
    method


    methiod invoked!


    1000
    methiod invoked!
    kotlin.Unit


    1000
    1000

    属性的get/set方法

    class ThePerson(address:String,name:String){
      val age:Int
          get() = 20
    
      var address:String = address
      get() {
          println("get invoked")
          return field
      }
      set(value) {
          println("set invoked")
          field = value
      }
    
      var name :String = name
    }
    
    fun main(args:Array<String>){
    
      var person = ThePerson("huizhou","zhangsan")
    
      println(person.age)
      println("********")
      println(person.address)
      person.address =  "gz"
      println(person.address)
      println("********")
      println(person.name)
      person.name ="lisi"
      println(person.name)
    }
    

    打印结果:
    20


    get invoked
    huizhou
    set invoked
    get invoked
    gz


    zhangsan
    lisi

    属性延迟初始化

    通过lateinit关键字标识属性为延迟初始化,需要满足3个条件:

    1. lateinit只能用在类体中声明的Var属性,不能用在primary constructor声明的属性上
    2. 属性不能拥有自定的setter和getter方法
    3. 属性类型需要为非空,且不能是原生类型
    class TheClass{
     lateinit var name:String
    
      fun init(){
          this.name ="zhangsan"
      }
    
      fun print(){
          println(this.name)
      }
    }
    
    fun main(args:Array<String>){
      var theClass = TheClass()
      theClass.init()
      theClass.print()
    }
    

    打印结果:
    zhangsan

    kotlin的四种可见性修饰符

    1. kotlin提供了四种可见性修饰符:private、protected、internal、public ; internal:模块化范围 ;kotlin默认为public
    // 可见性 visibility
    // kotlin提供了四种可见性修饰符:private、protected、internal、public
    // internal:模块化范围
    //kotlin默认为public
    open class Clazz{
      private val b = 3
      protected open val c = 4
      internal val d = 5
      val e =6
    }
    
    class subClazz:Clazz(){
      fun p(){
          println(c)
          println(d)
          println(e)
      }
    
    }
    
    class Claazz2{
      var clazz = Clazz()
    
      fun p(){
          println(clazz.d)
          println(clazz.e)
      }
    
    }
    

    Kotlin的扩展函数

    1. 扩展本身并不会真正修改目标类,也就是说它并不会在目标类中插入新的属性或方法
    2. 扩展函数的解析是静态分发的,而不是动态的,即不支持多态,调用只取决于对象的声明类型
    3. 调用是由对象声明类型所决定的,而不是由对象的实际类型决定
    class ExtensionTest{
      fun add(a:Int,b:Int) = a+b
      fun subtract(a:Int,b:Int) = a-b
    }
    
    //为ExtensionTest类扩展了一个新方法,扩展函数
    fun ExtensionTest.multiply(a:Int,b:Int) = a+b
    
    fun main(args:Array<String>){
      val extensionTest = ExtensionTest()
      println(extensionTest.add(1,2))
      println(extensionTest.subtract(1,2))
      println(extensionTest.multiply(1,2))
      println("********")
      mtPrint(AA())
      mtPrint(BB())
    }
    
    
    //扩展函数的解析是静态的
    /**
    * 1.扩展本身并不会真正修改目标类,也就是说它并不会在目标类中插入新的属性或方法
    * 2.扩展函数的解析是静态分发的,而不是动态的,即不支持多态,调用只取决于对象的声明类型
    * 3.调用是由对象声明类型所决定的,而不是由对象的实际类型决定
    */
    open class AA
    
    class BB:AA()
    
    fun AA.a() = "a"
    
    fun BB.a() = "b"
    
    fun mtPrint(aa:AA){
      println(aa.a())//只调用AA.a()方法
    }
    

    打印结果:
    3
    -1
    3


    a
    a

    1. 如果扩展函数与类中的方法重名,则调用类中的方法
    class CC{
      fun foo(){
          println("number")
      }
    }
    
    // 如果扩展函数与类中的方法重名,则调用类中的方法
    fun CC.foo(){
      println("number2")
    }
    
    fun CC.foo(int: Int){
      println("number3")
    }
    
    fun main(args:Array<String>){
      CC().foo()
      CC().foo(1)
    }
    
    

    打印结果:
    number
    number3

    扩展属性

    class MyExtensionProperty
    
    //扩展属性
    val MyExtensionProperty.name:String
    get() = "hello"
    
    fun main(args:Array<String>){
      var myExtensionProperty = MyExtensionProperty()
      println(myExtensionProperty.name)
    }
    

    数据类

    数据类需求满足如下要求:

    1. 主构造方法至少要有一个参数
    2. 所有的主构造方法参数都需要标记为var或时val
    3. 数据类不能时抽象的、open的、sealed的以及inner的

    对于数据类来说,编译器会自动生成如下内容:

    1. equals/hashCode
    2. toString()方法,形式为Person(name=..,)
    3. 针对属性的componentN方法,并且按照属性声明顺序来生成

    对于数据类成员的继承要点

    1. 如果数据类中显示定义了equals,hashCode或是toString方法,或是在数据类的父类中将这些方法声明为final,
      那么这戏方法就不会再生成,转而使用已有的。

    2. 如果父类拥有componentN方法,并且是open的以及返回兼容的类型,那么编译器就会在数据类中生成相应的componentN方法并且覆盖,
      如果父类中的这些方法由于不兼容的签名或是被定义为Final,那么编译器会报错

    3. 在数据类中显示提供componentN方法以及copy方法实现是不允许的

      解构声明
      在主构造方法中有多少个参数,就会依次生成对应的component1,component2,component3...
      在这些方法返回的就是对应字段的值,componentN方法是用来实现解构声明的

    data class Person(val name:String,var age:Int,var address:String)
    
    fun main(args:Array<String>){
      var person = Person("zhangsan",20,"beijing")
      println(person)
      person.age = 30
      println(person.age)
    
      //复制对象,并改其地址
      var person2 = person.copy(address = "guangdong")
      println(person2)
    
      //解构
      var(name,age,address) = person
      println("$name,$age,$address")
    }
    

    结果:

    Person(name=zhangsan, age=20, address=beijing)
    30
    Person(name=zhangsan, age=30, address=guangdong)
    zhangsan,30,beijing
    

    密封类

    密封类(sealed class) ,非常像java的枚举
    表示一种受限的层次结构(子父类),本身是一个抽象的类。常用在when中

    /*
    密封类(sealed class) ,非常像java的枚举
    表示一种受限的层次结构(子父类),本身是一个抽象的类
    */
    
    //密封类
    sealed class Calculator
    
    //密封类的子类
    class Add:Calculator()
    //密封类的子类
    class Subtract:Calculator()
    //密封类的子类
    class Multiply:Calculator()
    
    //密封类在when中使用最多
    fun calculate(a:Int,b:Int,cal:Calculator) = when (cal){
      is Add -> a+b
      is Subtract -> a-b
      is Multiply -> a*b
    }
    
    fun main(args:Array<String>){
      println(calculate(1,2,Add()))
      println(calculate(1,2,Subtract()))
      println(calculate(1,2,Multiply()))
    }
    

    相关文章

      网友评论

          本文标题:Kotlin基础2

          本文链接:https://www.haomeiwen.com/subject/ebiiahtx.html