kotlin之面向对象

这篇具有很好参考价值的文章主要介绍了kotlin之面向对象。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Kotlin之面向对象

  • 定义:使用class关键字进行定义。
    •  class Dog {
       
       }
      
    • 在kotlin类中,除非显式地声明延迟初始化,否则就得指定属性的默认值。
    • 在kotlin类中,成员默认是全局可见,而Java中,需要使用public才能达到此效果。
  • 构造函数
    • Kotlin将构造函数分为两种:主构造函数和次构造函数。
    • ①主构造函数:
      • 每个类默认都会有一个不带参数的主构造函数,也可以显式地给它指明参数。
      • 可以给主构造函数的参数指定默认值。
        •  class Dog(val name: String = "", val age: Int = 0, val color: Color = Color.BLUE)
           
           创建:
           val dog = Dog("wangwang")
           //创建对象时会根据传入的参数进行匹配,如果发现不一致的就会报错
           //解决办法就是指定这个参数值要赋值给哪一个参数,例如dog2的color = Color.BLUE
           //val dog1 = Dog(1)
           val dog2 = Dog(color = Color.BLUE)
           val dog3 = Dog("Tom", 1)
          
      • 如果主构造函数中的变量被var或val修饰,表示这个变量相当于类的成员变量。此时如果再在类中定义同名变量会报错。
        •  class Dog(val name: String = "", age: Int = 0) {
           	var age: Int = 0
           	//由于主构造函数中已经定义了该属性,这里再定义就重名了
           	//var name: String = ""
           	init {
           		//this.name = name
           		//左边是类的成员变量,右边是构造函数中的变量
           		this.age = age
           	}
           }
          
      • 特点:没有函数体,直接定义在类名的后面即可。如果想在主构造函数中写一些逻辑可以放在init结构体中。
      •  //People后面的括号用来说明Java的一个特性:
         //子类构造方法中必须调用父类的构造方法,这里调用了People的无参构造函数,就算无参也需要写括号。 
         class Student(sno: String, grade: Int) : People() {
         	init {
         		//在此处写主构造函数的逻辑
         	}
         }
         //调用了People的有参构造函数,由于Student类没有name和age字段,因此需要我们自己添加
         //注意:不能再将name和age属性声明成var或val,防止与父类属性重名。
         class Student(sno: String, grade: Int, name: String, age: Int) : People(name, age) {
         	
         }
        
      • 利用刚说的构造函数中参数的特性,我们有3种方式初始化:
        • ①在构造函数中将参数指定为var或val,使其变为类的成员变量;
        • ②不把构造函数中的参数指定为var或val,在类中定义同名的成员变量,并在init块中使用构造参数来进行初始化;
        • ③不把构造函数中的参数指定为var或val,在类中定义同名的成员变量,并把构造参数赋值给成员变量。
        •  //①
           class Dog(val name: String = "", val age: Int = 0) {
          
           	fun test() {
           		println("name  = $name, age = $age")
           	}
           }
           
           //②
           class Dog(name: String = "", age: Int = 0) {
          
           	val name: String
           	val age: Int
           	
           	//注:init初始化块可以定义多个,当创建对象时会依次从上往下执行每个块
           	init {
           		this.name = name
           		println("初始化块1:name = $name")
           	}
          
           	init {
           		this.age = age
           		println("初始化块2:age = $age")
           	}
          
           	fun test() {
           		println("name  = $name, age = $age")
           	}
           }
           
           输出:
           初始化块1:name = wangwang
           初始化块2:age = 1
           name  = wangwang, age = 1
           
           //③
           class Dog(name: String = "", age: Int = 0) {
          
           	val name: String = name
           	val age: Int = age
          
           	fun test() {
           		println("name  = $name, age = $age")
           	}
           }
          
      • 延迟初始化:不想在创建对象时就初始化该属性。
        • 可以使用lateinit和by lazy这两种语法来实现。
          • by lazy:
            • ①主要用于val变量;
            • ②在首次被调用时才会赋值,一旦赋值就不能再修改它。
            • ③线程安全问题:
              • a.LazyThreadSafetyMode.SYNCHRONIZED:系统会默认给lazy属性加上同步锁,它在同一时刻只允许一个线程对它进行初始化,所以它是线程安全的;
              • b.LazyThreadSafetyMode.PUBLICATION:你能确认该属性可以并行执行,没有线程安全问题;
              • c.LazyThreadSafetyMode.NONE:不会有任何线程方面的开销,也不保证线程安全。
            •  val name: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
               	"lala"
               }
              
          • lateinit:
            • ①主要用于var变量;
            • ②不能用于像Int、Long这些基本类型,必须用它们的包装类如Integer等。如果必须要用Int,可以采用Kotlin中委托的语法实现,即Delegates.notNull。
            •  lateinit var name: String
               var age by Delegates.notNull<Int>()
               lateinit var age: Integer
              
    • ②次构造函数:
      • 任何类只能有一个主构造函数,但可以有多个次构造函数。
      • 次构造函数也可以用于实例化一个类,只不过它是有函数体的。
      • Kotlin规定:当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(也包括间接调用)。
      • 次构造函数可能在自定义view时使用。
      • 定义:次构造函数使用constructor关键字来定义。
        •  class Student(sno: String, grade: Int, name: String, age: Int) : People(name, age) {
           	//直接调用了主构造函数,并使用默认值赋给次构造函数的变量
           	constructor(name: String, age: Int) : this("", 0, name, age) {
          
           	}
           	
           	//通过上面的次构造函数间接调用了主构造函数
           	constructor() : this("", 0) {
          
           	}
           }
           
           使用:
           val student1 = Student()
           val student2 = Student("Tom", 18)
           val student3 = Student("100", 7, "Jack", 17)
          
      • 特殊情况:类中只有次构造函数,没有主构造函数。
        • Student没有显示定义主构造函数,同时又定义了次构造函数,所以Student是没有主构造函数的。因此,也不用在遵循Java的规定,不用再调用父类的构造方法了,去掉了People的构造方法。
        •  class Student : People {
           	constructor(name: String, age: Int) : super(name, age) {
          
           	}
           }
          
      • 次构造函数基本用不到,Kotlin提供了一个给函数设定默认值的功能,基本上可以代替次构造函数的作用。

对象

  • 实例就是对象,对象就是实例。
  • 创建对象:不再需要使用Java那样的new关键字。
    • val a = A()

接口

  • Kotlin的接口基本和Java的接口一样。
  • Kotlin和Java一样,最多只能继承一个类,实现一个或多个接口。
  • Java实现接口使用implements关键字,kotlin不管是继承还是实现,都是用冒号:,之间使用逗号,分隔。
  • 使用override关键字重写父类或实现接口中的函数。
    •  class Student : People {
      
       	override fun test() {
       		
       	}
       }
      
  • 支持定义抽象属性。
    • 虽然kotlin的接口支持定义属性,但不能同时给它赋值:val a: Int = 10
    • 需要使用另一种方式来赋初值:
      •  val a: Int
         	get() = 10
        
  • 支持定义有默认实现的方法。
    • Java从1.8开始也支持这个功能了。
    • 背后实现其实是通过在内部定义一个静态内部类来提供方法的默认实现。
    •  interface A {
       	//抽象属性
       	val a: Int
       	//抽象方法
       	fun run()
       	//带有默认实现的方法
       	fun show() {
       		println("A show()")
       	}
       }
      

继承

  • 在kotlin中,一个非抽象类默认是不可被继承的,相当于Java中给类声明了final关键字。需要给类加上open关键字。
    •  open class People {
       	
       }
      
  • 继承需要使用冒号:,在Java中是使用extends关键字。
    •  class Student : People() {
       	
       }
      
  • 多继承:
    • 特点:
      • ①在实现一个接口时,需要实现接口中没有默认实现的方法及未初始化的属性。
      • ②若要同时实现多个接口以及方法,同时又遇到同名的未实现的方法时,这个方法来自于谁已经不重要了,可以说它既来自类又来自接口,如果是同名的已实现的方法,要么重写方法,要么用“super”指定要调用哪个接口或类的方法。
      • ③在实现接口或类的属性或方法时,必须要带上override关键字。
      •  interface FlyAnimal {
        
         	val name: String
        
         	fun fly()
        
         	fun eat() {
         		println("FlyAnimal eat")
         	}
         }
        
         abstract class Animal {
        
         	abstract fun fly()
        
         	open fun eat() {
         		println("FlyAnimal eat")
         	}
         }
        
         class Bird(override val name: String) : Animal(),FlyAnimal{
         	override fun fly() {
         		println("fly")
         	}
        
         	override fun eat() = super<Animal>.eat()
         }
         
         fun main() {
         	val bird = Bird("lala")
         	bird.eat()
         }
         
         输出:
         FlyAnimal eat
        
    • 实现多继承的方式:
      • ①使用多个接口模拟;
      • ②使用内部类实现;
        • 内部类:内部类使用inner class进行定义,如果不写,默认是静态内部类。
        • 这种实现方式的优点:
          • 1.可以在内部定义多个内部类,每个内部类的实例都有自己的独立状态,它们与外部对象的信息相互独立;
          • 2.内部多个类可以实现不同的接口从而拥有多个状态和行为;
          • 3.可以使用private修饰内部类,使得其他类不能访问内部类。
          •  open class Horse {
             	fun runFast() {}
             }
            
             open class Donkey {
             	fun doLongTime() {}
             }
            
             class Mule {
             	fun runFast() {
             		CHorse().runFast()
             	}
             	fun doLongTime() {
             		CDonkey().doLongTime()
             	}
             	private inner class CHorse : Horse()
             	private inner class CDonkey : Donkey()
             }
            
      • ③使用委托代替多继承:
        • 使用by关键字实现委托。
        • 优点:
          • 1.接口是无状态的,即使可以在默认方法写逻辑,但也仅限于简单的逻辑,如果给它创建一个实现类,可以在其中编写更复杂的逻辑;
          • 2.委托更加直观。
          •  interface Fly {
             	fun fly()
             }
            
             interface Eat {
             	fun eat()
             }
            
             open class Flyer : Fly {
             	override fun fly() {
             		println("fly")
             	}
             }
            
             open class Animal : Eat {
             	override fun eat() {
             		println("eat")
             	}
             }
            
             class Bird(flyer: Flyer, animal: Animal) : Fly by flyer, Eat by animal {}
            
             fun main() {
             	val bird = Bird(Flyer(), Animal())
             	bird.eat()
             	bird.fly()
             }
             
             输出:
             eat
             fly
            

可见性修饰符

  • kotlin的可见性修饰符分4种:public、internal、protected、default。
  • Java默认的可见性修饰符是default,不同于Java,Kotlin则是public。
  • internal:我们开发了一个模块给别人使用,但是有一些函数只允许我们在模块内部调用,而不想暴露给外部,就可以用internal。
  • 可见性修饰符功能一览表:
修饰符 可见性
public 所有类可见
internal 同一模块中的类可见
protected 当前类、子类可见
private 当前类可见

伴生对象

  • 意为某个类的对象,它属于这个类所有。
  • 伴生对象和Java的static效果一样,全局只有一个单例。它需要声明在类的内部,在类被装载时进行初始化。
  • 使用companion object进行定义,里面用来装类的静态变量和静态方法。
  • 使用时直接用类名.。
  • 在安卓中,我们可以给Fragment、Activity、Dialog定义一个伴生对象用来传递数据和启动等。
    •  class HomeFragment {
       	companion object {
       		private const val TAG = "HomeFragment"
       		
       		fun newInstance(): HomeFragment {
           		return HomeFragment()
       		}
       	}
       }
      

数据类

  • 它相当于Java的bean类。
  • data类会自动重写equals()、hashCode()、toString()方法。
    • equals():判断两个类是否相等。
    • hashCode():作为equals()方法的配套方法,若不重写会导致HashMap、HashSet等无法正常工作。
    • toString():提供更清晰的输出日志。
  • 使用data class进行声明,它会根据构造函数中的参数自动生成以上几个方法。
  •  data class People(val name: String, val age: Int)
    
  • 解构:
    • kotlin对于数组的解构默认最多允许5各变量。
    • 解构还用于Pair和Triple。
    •  val (int,string,double) = "1,abc,20.1".split(",")
       println("int = $int, string = $string, double = $double")
       
       输出:
       int = 1, string = abc, double = 20.1
      
  • Pair:
    • 二元组,可以有两个元素。
    •  //定义
       val a = "s" to 1
       val b = Pair("s", 1)
       
       //使用
       val a1 = a.first
       val a2 = a.second
       
       //解构
       val (string, int) = a
      
  • Triple:
    • 二元组,可以有两个元素。
    •  //定义
       val c = Triple(1, "abc", 20.1)
       
       //使用
       val a1 = c.first
       val a2 = c.second
       val a3 = c.third
      
       //解构
       val (int,string,double) = c
      

单例类

  • 希望某个类在全局最多只能拥有一个实例。
  • 在Java中创建单例类的步骤:
    • (1)使类的构造方法私有化;
    • (2)提供一个静态的getInstance()方法,用于给外部提供类的实例。
  • 在kotlin中使用object关键字进行声明。
    •  object SystemManager {}
      

object表达式

  • 相比于匿名内部类只能继承一个类或实现一个接口,object表达式却没有这个限制。
  • 在安卓中,我们可以使用object表达式来代替匿名内部类,如常用的Listener接口等。
    • viewLifecycleOwner.lifecycle.addObserver(object : LifecycleObserver {
      	@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
      	fun onDestroyView() {
          	block.invoke()
      	}
      })
      
  • 对于object表达式可以实现的一些场景,Lambda表达式也可以实现。具体建议参考如下:
    • 当匿名内部类使用的类接口只需要实现一个方法时,使用Lambda更合适;当有多个方法需要实现时,则建议使用object表达式。

文章来源地址https://www.toymoban.com/news/detail-493176.html

到了这里,关于kotlin之面向对象的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Kotlin函数和对象

    1.高阶函数 如果一个函数的参数是函数类型或者返回值是函数类型,那么这个函数就是高阶函数。 在kotlin中函数也是有类型的,跟整型、字符串类型是同样的性质,函数类型就是将函数的“输入参数类型”和“返回值类型”的抽象表达,如(Int,Int)- Int 2.扩展函数 kotlin允许

    2024年02月20日
    浏览(43)
  • Kotlin基础(九):对象和委托

    本文主要讲解kotlin对象和委托。 Kotlin文章列表 Kotlin文章列表: 点击此处跳转查看 在Kotlin中,对象(Object)是一个具有特殊用途的单例实例。它是一种创建单个实例的方式,确保在整个应用程序中只存在一个特定对象。 对象在Kotlin中有以下特点和用途: 单例实例:对象只能有

    2024年02月14日
    浏览(38)
  • kotlin怎么定义类

    在Kotlin中,你可以使用class来定义一个类。以下是一个简单的例子: 这个例子定义了一个名为MyClass的类。你可以在类体中定义属性和方法。 如果你想定义一个带有属性的类,你可以这样做: 在这个例子中,我们定义了一个名为Person的类,它有两个属性:name和age。na

    2024年02月10日
    浏览(26)
  • Kotlin-变量定义,与类型

    Kotlin可以定义的时候不标明数据的数据类型,编译器会根据初始值确定类型 提供4种类型:Byte、Short、Int、Long 但是Kotlin时安全语言,所以不允许为空,如果需要存储空值的话就需要使用Byte?、Short?、Int?、Long?。 普通类型的整数类型会映射到java的基本类型;带?的数据类

    2024年01月16日
    浏览(38)
  • Kotlin中特性、数据类、伴生对象、顶层函数

    在 Kotlin 中,函数参数和属性有不同的声明方式和行为。这些特性使得 Kotlin 代码更加安全、易于理解和维护。 函数参数的只读性 在 Kotlin 中,函数参数默认是只读的。这意味着在函数体内无法直接修改函数参数的值。如果尝试在函数内部修改函数参数,编译器会报错。 这种

    2024年02月09日
    浏览(44)
  • Kotlin版 自定义的LiveDataBus

    先上代码: 为了开启,关闭粘性事件,使用了 isStick 控制。 通过继承 MutableLiveData,在observe的时候hook 获取 mLastVersion 和mVersion,进行版本对齐

    2024年02月03日
    浏览(25)
  • Kotlin语法入门-自定义注解(7)

    示例: 注解的附加属性可以通过用元注解标注注解类来指定: @Target 指定可以用该注解标注的元素的可能的类型(类、函数、属性与表达式); @Retention 指定该注解是否存储在编译后的 class 文件中,以及它在运行时能否通过反射可见 (默认都是 true); @Repeatable 允许在单个

    2024年04月25日
    浏览(29)
  • android 自定义车牌键盘(kotlin)

    平时停车缴费都要填车牌号码,就想着自己能不能也做个车牌键盘demo。 自定义车牌键盘能满足(普通车牌,新能源,警车,军车,领事馆车,教练车以及特种车辆等车牌) 1、车牌前两位默认是:粤A 2、第一个控件,默认是省份键盘 3、剩下控件,默认是abc键盘 4、当前输入

    2024年02月16日
    浏览(45)
  • 18:kotlin 类和对象 -- 数据类(Data classes)

    数据类是其主要目的是保存数据的类。数据类会自动附带额外的成员方法 使用 data 声明一个数据类 编译器会自动从 主构造函数 中声明的所有属性派生以下成员 .equals() / .hashCode() .toString() 如: \\\"User(name=John, age=42)\\\" .componentN() (在后边的文章会讲到) .copy() 为了确保生成的代码

    2024年02月03日
    浏览(51)
  • Kotlin 集合对象的单条件和多条件排序

    原文: Kotlin 集合对象的单条件和多条件排序 - Stars-One的杂货小窝 本文不是太难的东西,因为 sortedWith 之前没怎么用过,所以就记录下 平常开发经常使用到List,Map等数据集合类型,也会经常遇到排序的问题,可以直接使用 sortedBy 或 sortedByDescending 排序 多条件则是使用 sortedWith ,具体使

    2024年02月08日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包