跳转到内容

Kotlin可见性修饰符

来自代码酷

Kotlin可见性修饰符[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

Kotlin中的可见性修饰符(Visibility Modifiers)用于控制类、对象、接口、构造函数、函数、属性及其setter的访问范围。Kotlin提供了四种可见性修饰符:`public`、`private`、`protected`和`internal`。这些修饰符决定了代码中的哪些部分可以被其他代码访问,从而帮助开发者实现封装和信息隐藏。

如果没有显式指定可见性修饰符,Kotlin会使用默认的`public`修饰符。

可见性修饰符类型[编辑 | 编辑源代码]

public[编辑 | 编辑源代码]

`public`是默认的可见性修饰符。如果一个声明被标记为`public`,或者没有显式指定修饰符,那么它可以被任何地方的代码访问。

// 默认是public
fun sayHello() {
    println("Hello, World!")
}

// 显式指定public
public class PublicClass {
    public val publicProperty: String = "I am public"
}

private[编辑 | 编辑源代码]

`private`修饰符将声明限制在其所在的文件(对于顶层声明)或类(对于类成员)内部。

// 顶层private函数,只能在当前文件内访问
private fun privateFunction() {
    println("This is private")
}

class PrivateExample {
    // 类内部的private属性,只能在类内部访问
    private val privateProperty: String = "I am private"

    fun accessPrivate() {
        println(privateProperty) // 可以访问
    }
}

fun main() {
    // privateFunction() // 编译错误:无法在文件外部访问
    val example = PrivateExample()
    // println(example.privateProperty) // 编译错误:无法在类外部访问
    example.accessPrivate() // 输出: I am private
}

protected[编辑 | 编辑源代码]

`protected`修饰符只能用于类成员(不能用于顶层声明),并且允许子类访问该成员。

open class Parent {
    protected val protectedProperty: String = "I am protected"

    protected fun protectedFunction() {
        println("Protected function called")
    }
}

class Child : Parent() {
    fun accessProtected() {
        println(protectedProperty) // 可以访问
        protectedFunction() // 可以访问
    }
}

fun main() {
    val child = Child()
    child.accessProtected() // 输出: I am protected \n Protected function called
    // child.protectedProperty // 编译错误:无法在类外部访问
}

internal[编辑 | 编辑源代码]

`internal`修饰符表示声明在同一个模块(module)内可见。模块是一组一起编译的Kotlin文件(例如一个IntelliJ IDEA模块、一个Maven项目或一个Gradle源代码集)。

internal class InternalClass {
    internal val internalProperty: String = "I am internal"
}

fun main() {
    val internalObj = InternalClass()
    println(internalObj.internalProperty) // 在同一个模块内可以访问
}

可见性修饰符的应用场景[编辑 | 编辑源代码]

封装实现细节[编辑 | 编辑源代码]

使用`private`修饰符可以隐藏类的内部实现细节,只暴露必要的接口。

class BankAccount {
    private var balance: Double = 0.0

    fun deposit(amount: Double) {
        if (amount > 0) balance += amount
    }

    fun withdraw(amount: Double): Boolean {
        if (amount <= balance) {
            balance -= amount
            return true
        }
        return false
    }

    fun getBalance(): Double = balance
}

模块化开发[编辑 | 编辑源代码]

`internal`修饰符在大型项目中特别有用,它可以限制某些API只在模块内部使用,防止被其他模块误用。

继承控制[编辑 | 编辑源代码]

`protected`修饰符允许子类访问父类的成员,同时对外部代码隐藏这些成员。

可见性修饰符的规则总结[编辑 | 编辑源代码]

flowchart TD A[可见性修饰符] --> B[public: 任何地方可见] A --> C[private: 文件或类内可见] A --> D[protected: 类内和子类可见] A --> E[internal: 模块内可见]

特殊情况的可见性[编辑 | 编辑源代码]

构造函数的可见性[编辑 | 编辑源代码]

主构造函数的可见性可以通过在`constructor`关键字前添加修饰符来指定:

class PrivateConstructor private constructor(val name: String) {
    companion object {
        fun create(name: String): PrivateConstructor {
            return PrivateConstructor(name)
        }
    }
}

fun main() {
    // val obj = PrivateConstructor("Test") // 编译错误:构造函数是private的
    val obj = PrivateConstructor.create("Test") // 通过工厂方法创建
}

getter和setter的可见性[编辑 | 编辑源代码]

属性的getter和setter可以有自己的可见性修饰符,但setter的可见性不能比属性本身更宽松。

class VisibilityExample {
    var property: String = "default"
        private set // setter是private的

    val readOnlyProperty: String = "read-only"
        get() = field.toUpperCase() // getter默认与属性可见性相同

    fun changeProperty(newValue: String) {
        property = newValue // 可以在类内部修改
    }
}

fun main() {
    val example = VisibilityExample()
    println(example.property) // 可以读取
    // example.property = "new value" // 编译错误:setter是private的
    example.changeProperty("new value") // 通过方法修改
}

可见性修饰符的数学表示[编辑 | 编辑源代码]

我们可以用集合论的概念来表示可见性范围:

public:所有代码private:文件或类内部protected:类内部子类internal:模块内部

最佳实践[编辑 | 编辑源代码]

1. 默认使用`private`,只在需要时放宽可见性 2. 使用`internal`来保护模块内部API 3. 避免过度使用`protected`,考虑是否真的需要继承 4. 谨慎设计`public` API,因为它们构成了与外部代码的契约

总结[编辑 | 编辑源代码]

Kotlin的可见性修饰符提供了精细的访问控制机制,帮助开发者构建健壮、可维护的代码。通过合理使用这些修饰符,可以实现良好的封装,减少代码耦合,提高模块化程度。理解并正确应用这些修饰符是成为Kotlin开发高手的重要一步。