美文网首页
Kotlin——面向对象(下)

Kotlin——面向对象(下)

作者: So_ProbuING | 来源:发表于2023-09-27 15:20 被阅读0次

扩展

Kotlin支持扩展方法和扩展属性

扩展方法

Kotlin的扩展其实就是定义一个函数,只是函数名不要写成简单的普通函数,而是在函数名前增加被扩展的类(接口)名和点号“.”

fun main(args: Array<String>) {
    //row
    var r = Row()
    r.test()
    //调用扩展方法
    r.extendsFun("hello")
    //子类调用父类的方法
    var sr = SubRow()
    sr.test()
    //子类调用自己的方法
    sr.sub()
    //子类调用父类的扩展方法
    sr.extendsFun("sub")
}

open class Row{
    fun test(){
        println("Row的test方法")
    }
}

class SubRow: Row() {
    fun sub() {
        println("sub方法")
    }
}

fun Row.extendsFun(name: String) {
    println("扩展的Row方法")
}
  • 程序为一个类扩展了方法之后,就像为该类增加了方法一样,所有的该类的对象都可以调用扩展的方法,该类的子类实例也可以调用扩展的方法。

扩展属性

Kotlin允许扩展属性,Kotlin扩展属性其实是通过添加getter、setter方法实现的。扩展的属性只能是计算属性

final和open修饰符

  • final关键字可用于修饰类、属性和方法,表示它修饰的类、属性和方法不可改变
    Kotlin会为非抽象类自动添加final修饰符,也会为非抽象方法、非抽象属性等无须重写的成员自动添加final修饰符。开发者可以使用open修饰符取消自动添加final修饰符
    Kotlin的final修饰符不能修饰局部变量,open自然也不能修饰局部变量

可执行“宏替换”的常量

Kotlin提供了const用来修饰可执行“宏替换”的常量,这种常量也被称为"编译时"常量。因为它在编译阶段就会被替换掉

  • 位于顶层或是对象表达式的成员
  • 初始值为基本类型值或字符串字面值
  • 没有自定义的getter方法
const val MAX_AGE =100
println(MAX_AGE)

上面的代码中,根本就不存在MAX_AGE,当程序执行println时,实际替换为执行println(100),这个替换在编译阶段就完成了

final属性

final属性表明该属性不能被重写。如果程序对属性不使用任何修饰符,Kotlin会自动为该属性添加final修饰

final方法

使用final修饰的方法不可被重写。如果程序不为方法添加任何修饰,Kotlin会自动为该方法添加final修饰

final类

使用final修饰的类不可以有子类,Kotlin也会为没有显式使用open修饰的类添加final修饰

抽象类

抽象成员和抽象类

抽象成员(方法和属性)和抽象类必须使用abstract修饰符来定义,包含抽象成员的类只能被定义成抽象类。抽象类中可以没有抽象成员
规则如下

  • 抽象类必须使用abstract修饰符来修饰,抽象成员也必须使用abstract修饰符来修饰,抽象方法不能有方法体
  • 抽象类不能被实例化,无法调用抽象类的构造器创建抽象类的实例
  • 抽象类可以包含属性、方法、构造器、初始化块、嵌套类5种成员,抽象类的构造器不能用于创建实例,主要用于被其子类调用
  • 含有抽象成员的类只能被定义成抽象类

定义抽象方法,只需在普通方法上增加abstract修饰符,并把普通方法的方法体去掉即可
定义抽象类,只需在普通类上增加abstract修饰符

abstract class Shape{
    init {
        println("shape的初始化块")
    }

    var color = ""

    abstract fun calPerimeter():Double

    //抽象属性不需要初始化
    abstract val type:String
    constructor()
    constructor(color:String){
        println("shape构造器")
        this.color = color
    }

}

创建一个普通类继承抽象类

class Triangle(color:String, private var a:Double):Shape(color){
    override fun calPerimeter(): Double {
        this.a = a
        return a * a * a
    }

    override val type: String = "三角形";

}

fun main(args: Array<String>) {
    var triangle = Triangle("red", 1.0)
    triangle.calPerimeter()
}

密封类

密封类的子类是固定的,密封类的子类必须与密封类本身在同一个文件中,在其他文件中则不能为密封类派生子类

//创建一个密封类
sealed class Appleb{
    abstract fun eat()
}
//创建密封类的子类
open class RedFuJi:Appleb(){
    override fun eat() {
        println("密封类的子类")
    }

}

fun main(args: Array<String>) {
    val a1:Appleb = RedFuJi()
    a1.eat()
}

接口

接口的定义

语法

[修饰符] interface 接口名:父接口1,父接口2...{
//零个到多个属性定义...
//零个到多个方法定义...
//零个到多个嵌套类、嵌套接口、嵌套枚举定义...
}
  • 修饰符可以是public|internal|private中的任意一个或者完全省略,完全省略默认采用public
  • 接口名应与类名采用相同的命名规则
  • 一个接口可以有多个直接父接口,但接口只能继承接口
    Kotlin的接口既可以包含抽象方法,也可以包含非抽象方法
    接口中不能包含构造器和初始化块定义
interface Outputtable{
    //定义属性
    //只读属性 定义get方法
    val name:String
        get() ="只读属性"
    //读写属性 设置get set方法
    var price:Int
        get() {
           return price
        }
        set(value) {
            price = value
        }

    //抽象属性
    var age:Int
    //抽象方法
    fun a1()
    fun a2()
    fun a3()

    //非抽象方法
    fun print(vararg msg: String){
        for (s in msg) {
            println(s)
        }
    }
}

接口的继承

接口完全支持多继承,一个接口可以有多个父接口,一个接口继承多个父接口,多个父接口排在英文冒号:之后,它们之间以英文逗号隔开

使用接口

接口的主要用途就是被实现类实现

class OutputtableImpl:Outputtable{
    override var age: Int
        get() = TODO("Not yet implemented")
        set(value) {}

    override fun a1() {
        TODO("Not yet implemented")
    }

    override fun a2() {
        TODO("Not yet implemented")
    }

    override fun a3() {
        TODO("Not yet implemented")
    }
}

嵌套类和内部类

把一个类放在另一个类的内部定义,这个定义在其他类内部的类就称为嵌套类,包含嵌套类的类就被称为外部类

  • 嵌套类(相当于静态内部类)将一个类放在另一个类中定义,这个类就是嵌套类,相当于Java的静态内部类
  • 内部类(非静态内部类)使用inner修饰的嵌套类叫内部类,相当于Java中无static修饰的非静态内部类

内部类

内部类相当于外部类的实例成员,因此内部类可以直接访问外部类的所有成员

class Outer(var name:String){
    fun sayName(){
        println("name${name}")
    }
    inner class innerCls(){
        var innerField = ""
        fun sayInnerName(){
            println("sayInner+${innerField}")
            //访问外部类属性
            name
            sayName()
        }
    }
}

fun main() {
    //创建外部类
    var outer = Outer("hh")
    //外部类访问属性
    println(outer.name)
    outer.sayName()
    //创建内部类对象
    var innerCls = outer.innerCls()
    //访问内部类属性
    println(innerCls.innerField)
    innerCls.sayInnerName()
}
  • 如果内部类属性与外部类属性同名,则可通过使用this、带标签的thiis进行限定区分
class Out{
var name:String = ""
class inner{
var name:String = ""
  fun info(){
        //访问外部类name属性
        this@Out.name
        //访问内部类name属性
        this.name
    }
}

}
  • 内部类成员可以访问外部类的private成员,但是外部类不可访问内部类的成员,内部类的成员只在内部类范围内是可知的。如果外部类需要访问内部类的成员,则必须显式创建内部类对象来调用访问其成员

嵌套类

嵌套类相当于Java的静态内部类,嵌套类属性外部类本身,不是外部类实例相关
嵌套类不能访问外部类的其他成员,只能访问另一个嵌套类

  • 外部类不能直接访问嵌套类的成员,但可以使用嵌套类的对象作为调用者来访问嵌套类的成员

匿名内部类

Kotlin提供了对象表达式来表示内部类

object[:0~N个父类型]{
//对象表达式的类体部分
}
  • 对象表达式不能是抽象类
  • 对象表达式不能定义构造器,但可以定义初始化块
  • 对象表达式可以包含inner修饰的类,不能包含嵌套类
interface Outputable{
    fun a(){}
}
abstract class Product(var price:Double){
    abstract val name:String
    abstract fun proInfo()
}
fun main() {
    //创建一个父对象的对象表达式
    var ob1 = object : Outputable {
        //重写接口中的方法
        override fun a() {
            println("a 方法被重写")
        }
    }
    ob1.a()
    //创建零个父对象的对象表达式
    var ob2 = object {
        init {
            println("ob2 init")
        }
        //属性
        var name = "ob2 field"
        //方法
        fun test(){
            println("ob2 fun")
        }
    }
    ob2.test()
    //创建两个父类型的对象表达式
    val ob3 = object : Outputable,Product(33.3) {
        override val name: String = "ob3 name"

        override fun proInfo() {
            println("ob3 proInfo")
        }
    }
    ob3.proInfo()
}

对象声明和单例模式

对象声明的语法格式如下:

object ObjectName[:0~N个父类型]{
//对象表达式的类体部分
}
  • 对象声明需要在object关键字后面指定名字
  • 对象表达式是一个表达式,它可以被赋值给变量;对象声明不是表达式,不能用于赋值
  • 对象声明可包含嵌套类,不能包含内部类。对象表达式可包含内部类,不能包含嵌套类
  • 对象声明不能定义在函数和方法内,对象表达式可嵌套在其他对象声明或非内部类中

枚举类

Kotlin使用enum class关键字组合定义枚举类。枚举类是一种特殊的类,它一样可以有自己的属性、方法,可以实现一个或多个接口,也可以定义自己的构造器

  • Kotlin枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承Kotlin.Enum类,而不是默认继承Any类,因此枚举类不能显式继承其他父类
  • 使用enum定义的非抽象枚举类不能使用open修饰,枚举类不能派生子类
  • 枚举类的构造器只能使用private访问控制符。
  • 枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例。
    枚举类默认提供两个方法
  • EnumClass.valueOf(value:String):EnumClass:类似于Java枚举类的valueOf()方法,用于根据枚举的字符串名获取实际的枚举值
  • EnumClass.values():Array<EnumClass>:类似于Java枚举类的values()方法,用于获取该枚举类的所有枚举值组成的数组

委托

相关文章

  • 第六篇:Kotlin之面向对象简单

    上篇:Kotlin之函数Lambda表达式 下篇:Kotlin之面向对象升级(一) Kotlin也支持面向对象的三...

  • kot

    #Kotlin之班门弄斧 ##面向对象 ##java和kotlin的交互 ##协程及协程框架 ## 面向对象 ...

  • 第七篇:Kotlin之面向对象升级(一)

    上篇:Kotlin之面向对象简单 本章节来介绍Kotlin面向对象的高级部分: 一. 扩展:kotlin的扩展是一...

  • [Kotlin]面向对象

    Kotlin vs Java Kotlin中的类默认是声明为public final, 如果需要这个类有可以被继承...

  • Kotlin面向对象

    准备好开发工具IDEA,注册码的获取网址:http://idea.lanyus.com/定义一个类 定义一个类和方法

  • Kotlin -面向对象

    kotlin中的类 上面代码反编译成Java的版本后,会有get方法,除此之外还有一些不同1)不可变属性成员。这是...

  • Kotlin——面向对象

    Kotlin面向对象 类和对象 Kotlin提供了定义类、属性、方法等最基本的功能。类可被认为是一种自定义的数据类...

  • kotlin从入门到看开 ₅

    layout: posttitle: "kotlin-面向对象"subtitle: "前途和...

  • 第一天

    概述: Kotlin基础面向过程面向对象接口、扩展、泛型 为什么学习Kotlin 1.Google官方指定2.简介...

  • Kotlin学习之类

    Kotlin学习之类 @(Kotlin学习) Kotlin在面向对象上具有和Java相似的特征,但是针对不同的情况...

网友评论

      本文标题:Kotlin——面向对象(下)

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