Kotlin学习笔记 第二章 类与对象 第五节 可见性 第六节 扩展

本文档详细介绍了Kotlin的四种可见性修饰符:public、protected、internal和private,并指出默认为public。对比了Java的可见性。接着深入探讨了Kotlin的扩展函数和扩展属性,包括扩展原理、案例解析、伴生对象扩展以及分发接收者与扩展接收者。文章还展示了扩展方法如何在不同上下文中工作,以及如何覆盖和调用它们。
摘要由CSDN通过智能技术生成

参考链接

Kotlin官方文档

https://kotlinlang.org/docs/home.html

中文网站

https://www.kotlincn.net/docs/reference/properties.html

本系列为参考Kotlin中文文档

https://download.csdn.net/download/u011109881/21418027

整理的笔记 不记得原pdf下载地址了

Kotlin 核心编程

第二章 第五节 可见性

知识点 可见性

笔记

// 1 Kotlin中的可见性修饰符
// 在 Kotlin 中有这四个可见性修饰符:private 、protected 、internal 和 public
// 如果你不指定任何可见性修饰符,默认为 public ,这意味着你的声明将随处可见
// 如果你覆盖⼀个 protected 成员并且没有显式指定其可见性,该成员还会是 protected 可见性

// 2 Java 可见性修饰符 VS Kotlin
/**
 修饰符          Kotlin                              Java
 public    Kotlin默认修饰符 全局可见                    |完全相等
 protected 类及其子类可见                              |类及其子类 包内可见
 private   修饰的类 则只有类内可见 修饰其他东西 同文件可见   |类内可见
 internal  模块内可见 类似Java的default                |无
 default   无                                        |Java默认修饰符
 */


class D0305Access

demo Java protected vs Kotlin protected

// EngineJava.java
import org.jetbrains.annotations.NotNull;

public class EngineJava {
    private final String type;

    protected String engineType() {
        return "engine type is " + this.getType();
    }

    public String getType() {
        return this.type;
    }

    public EngineJava(@NotNull String type) {
        this.type = type;
    }
}

// BMWEngineJava.java
public class BMWEngineJava {
    private EngineJava bMWEngine = new EngineJava("BWM");

    public String getEngine(){
        // 同一包内可以访问protected方法
        return bMWEngine.engineType();
    }
}

正常编译

// Engine.kt
open class Engine (open val type:String){
    protected open fun engineType():String{
        return "engine type is $type"
    }
}

// BMWEngine.kt
class BMWEngine(val name: String){
    private val bMWEngine = Engine("BMW")
    fun getEngine():String{
        // 同一包内无法访问protected方法
        // return bMWEngine.engineType()//Cannot access 'engineType': it is protected in 'Engine'
        return ""
    }
}

如果像Java那么写 报错

第二章 第六节 扩展

知识点

1 扩展函数与扩展方法

2 扩展函数

3 扩展函数原理

4 扩展函数案例解析

5 扩展超类

6 扩展属性

7 伴生对象的扩展方法

8 扩展方法 扩展属性的作用域

9 扩展成员属性与方法

10 分发接收者与扩展接收者成员名字冲突

11 扩展方法的覆盖

笔记

package com.example.lib.d03classobject

import java.util.ArrayList

// 1 扩展函数与扩展方法
// 你可以为⼀个你不能修改的、来⾃第三⽅库中的类编写⼀个新的函数。这个新增的函数就像那
// 个原始类本来就有的函数⼀样,可以⽤普通的⽅法调⽤。这种机制称为 扩展函数 。此外,也有 扩展属性 ,允许
// 你为⼀个已经存在的类添加新的属性。

fun main() {
    // 2 测试扩展函数
    val demo = D0306Extends<Int>()
    demo.add(1)
    demo.add(10)
    demo.printItems()

    println("hi!".addDot(5))

    // 4 扩展函数案例解析
    printClassName(Rectangle())
    // 5 扩展超类
    val nullObject: Int? = null
    // 调用Any的扩展方法
    println(nullObject.toString())
    val notNull = "abc"
    // 这里调用的直接是Any里面的方法
    println(notNull.toString())

    // 6 扩展属性
    println(demo.size)

    // 7 伴生对象的扩展方法
    // 使用伴生对象的扩展方法
    D0306Extends.printString("Test Companion Object Extension Method");

    // 9 扩展成员方法 仅在扩展接收者内部可以使用
    // myHost--扩展接收者
    val myHost = Host("kotl.in")
    // myConn--分发接收者
    val myConn = Connection(myHost, 443)
    myConn.connect()
    //Host("kotl.in").printConnectionString(443) // 错误, 该扩展函数在 Connection 外不可⽤

    // 10 分发接收者与扩展接收者成员名字冲突
    // 扩展接收者优先 要引⽤分发接收者的成员你可以使⽤
    // 限定的 this 语法

    // 11 扩展方法的覆盖
    // 声明为成员的扩展可以声明为 open 并在⼦类中覆盖
    // 这意味着这些函数的分发对于分发接收者类型是虚拟
    // 的,但对于扩展接收者类型是静态的
    BaseCaller().call(Base())   // “Base extension function in BaseCaller”
    BaseCaller().call(Derived()) // “Base extension function in BaseCaller”
    DerivedCaller().call(Base())  // “Base extension function in DerivedCaller”——分发接收者虚拟解析
    DerivedCaller().call(Derived())  // “Base extension function in DerivedCaller”——扩展接收者静态解析
    // 官方文档解释了一堆 我觉得关键就是fun call(b: Base)中的声明 是什么类型的
    // 如果声明的是Base 那么不管传入的实际类型是什么 总是调用Base的成员扩展方法
    // 如果声明的是Derived 则总是调用Derived的成员扩展方法
}

// 基类Base 基类扩展接收者
open class Base { }

// 子类Derived 子类扩展接收者
class Derived : Base() { }

// 基类分发接收者
open class BaseCaller {
    // Base的成员扩展方法
    open fun Base.printFunctionInfo() {
        println("Base extension function in BaseCaller")
    }

    // Base的子类Derived  的成员扩展方法
    open fun Derived.printFunctionInfo() {
        println("Derived extension function in BaseCaller")
    }

    // 这里声明为Base类型 因此调用的是 Base的成员扩展方法
    fun call(b: Base) {
        b.printFunctionInfo()   // 调用扩展函数
    }
}

// 子类分发接收者
// BaseCaller的子类
class DerivedCaller: BaseCaller() {
    // 覆盖父类  Base的成员扩展方法
    override fun Base.printFunctionInfo() {
        println("Base extension function in DerivedCaller")
    }

    // 覆盖父类  Base的子类Derived  的成员扩展方法
    override fun Derived.printFunctionInfo() {
        println("Derived extension function in DerivedCaller")
    }

    // 继承了父类的call方法
}

// 10 分发接收者与扩展接收者成员名字冲突
class Connection2 {
    fun Host.getConnectionString() {
        // Host的实例是扩展接收者
        toString() // 优先调⽤ Host.toString()
        // Connection2的实例是分发接收者
        // 限定this调用
        this@Connection2.toString() // 调⽤ Connection.toString()
    }
}

// 9 扩展成员属性与方法
class Host(val hostName: String) {// 带有一个String的主构造函数
    fun printHostName() {
        print(hostName)
    }
}

class Connection(val host: Host, val port: Int) {// 带有2个String的主构造函数
    fun printPort() {
        print(port)
    }

    // 在Connection内部扩展Host类的方法
    // 这样Connection的实例称为 分发接收者
    // Host类的实例称为 扩展接收者
    fun Host.printConnectionString() {
        printHostName() // 调⽤ Host.printHostname()
        print(":")
        printPort() // 调⽤ Connection.printPort()
    }

    fun connect() {
        host.printConnectionString() // 调⽤扩展函数
    }
}

/**
8 扩展方法 扩展属性的作用域
如果定义在顶层的扩展方法和属性 在其他包内都可以使用 使用方法如下
import com.example.lib.d03classobject.addDot
import com.example.lib.d03classobject.size

fun main() {
"aaa".addDot(2)
"aa".size
}

 但是如果添加private修饰符 或者定义在类内部(8 扩展属性demo3)则外部无法使用
 */

// 7 伴生对象的扩展方法Demo
// 定义伴生对象的扩展方法
fun D0306Extends.Companion.printString(string: String){
    println(string)
}


// 6 扩展属性 demo
val <T> D0306Extends<T>.size: Int // = 1 //Initializer is not allowed here because this property has no backing field
    // 扩展属性不支持幕后字段field
    // 它没有默认的set get方法
    // 因此 扩展属性强制我们给他编写get方法
    get() = this.arr.size

// 6 扩展属性 demo2
val String.size: Int
    get() {
        return this.length
    }

// 5 扩展超类 接受可空类型的参数
fun Any?.toString(): String {
    if (this == null) {
        return "null"
    }
    // 空检测之后, “this”会⾃动转换为⾮空类型, 所以下⾯的 toString()
    // 解析为 Any 类的成员函数
    // 因为Any的toString不接受null
    return toString()
}

// 4 扩展函数案例解析
open class Shape
class Rectangle : Shape()

// 创建Shape的扩展方法
fun Shape.getName() = "Shape"

// 创建Rectangle的扩展方法
// 但需要注意的是 getName不是真正的插入到Rectangle内部 因此该方法也不会有覆盖的概念
// 与父类的 getName没有任何关系
fun Rectangle.getName() = "Rectangle"
fun printClassName(s: Shape) {// 这里声明的是什么类型 则调用谁的getName方法
    // 而不会考虑它的实际类型
    // VS java
    // java的父类引用指向子类对象 调用的被覆盖的方法 实际调用的是子类方法
    println(s.getName())
}

// 2 扩展函数demo1
fun D0306Extends<Int>.add(number: Int) {
    this.arr.add(number)
}

// 2 扩展函数demo2
fun String.addDot(count: Int): String {
    return this + ".".repeat(count)
}

/**
 * 反编译出的addDot方法
@NotNull
public static final String addDot(@NotNull String $this$addDot, int count) {
Intrinsics.checkNotNullParameter($this$addDot, "$this$addDot");
return $this$addDot + StringsKt.repeat((CharSequence)".", count);
}
 */
// 3 扩展函数原理
// 扩展不能真正的修改他们所扩展的类。通过定义⼀个扩展,你并没有在⼀个类中插⼊新成员,仅仅是可以通过该
// 类型的变量⽤点表达式去调⽤这个新函数
// 扩展函数原理是 个人觉得是 创建一个静态方法 调用者作为参数传入,在该静态方法内部操作调用者

class D0306Extends<T>() {

    // 8 扩展属性demo3
    fun String.printIt(){
        println(this)
    }

    // 伴生对象
    companion object{

    }

    var arr: MutableList<T> = ArrayList()
    fun printItems() {
        for (item in arr) {
            println(item)
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值