1. 概述

在本文中,我们将对比 Java 和 Kotlin 中的默认访问修饰符行为。接着我们会介绍 Kotlin 中模块(module)的概念,最后展示如何在 Kotlin 中封装内部逻辑。

2. Java 中的 package-private

Java 中的默认访问修饰符(即无显式修饰符)允许同一包下的类访问该类的成员。这个修饰符无需关键字,是 Java 中类和成员的默认访问级别。

⚠️ 需要注意的是,这种修饰符并不能提供真正的封装。比如,只要新建一个类放在同一个包下,就可以访问 package-private 成员。这也是为什么 Kotlin 中没有直接对应的 package-private 修饰符的原因之一。

此外,如果希望一个类对外暴露,必须使用 public。但一旦设为 public,就相当于对所有人开放了访问权限。

3. Kotlin 中的默认访问修饰符

Kotlin 中有以下几种可见性修饰符:

  • public(默认)
  • private
  • internal
  • protected

Kotlin 默认使用 public 修饰符,其行为与 Java 类似:允许外部代码访问。

但 Kotlin 并没有直接对应 Java 的 package-private 的修饰符

4. Kotlin 中的模块定义

在 Kotlin 中,模块(module)通常指的是:

一组一起被编译成一个 jar 文件的源码文件。

常见的模块包括:

  • IntelliJ 中的 module
  • Maven 项目
  • Gradle 的 source set
  • 使用 Ant 编译的一组文件

模块这个概念在理解 internal 修饰符时非常重要。

5. 使用 internal 封装内部逻辑

在 Java 中我们用 package-private 来限制访问范围,但在 Kotlin 中,**internal 是更优的替代方案**。

internal 的作用是:仅在模块内可见。相比 package-private,它提供了更强的封装性。

主要优势包括:

  • 不会暴露内部类或方法给外部模块
  • 同一模块内任意包都可以访问
  • 更适合用于封装库内部逻辑,对外不暴露

示例代码

我们定义一个 internal 类:

internal class InternalClass {
    internal fun helloFromInternalFunction(): String {
        return "Hello"
    }
}

然后在另一个包中调用它(但仍在同一模块中):

fun whenCallInternalClass_thenItWorks() {
    val internalClass = InternalClass()
    assertThat(internalClass.helloFromInternalFunction()).isEqualTo("Hello")
}

虽然调用类在不同包中,但因为处于同一模块,所以可以访问 internal 方法

6. 总结

本文对比了 Java 和 Kotlin 中默认访问修饰符的行为差异。我们还介绍了 Kotlin 中模块的概念,并展示了如何使用 internal 来封装内部逻辑。

如果你正在从 Java 迁移到 Kotlin,或者设计一个 Kotlin 库,建议使用 internal 替代 Java 的 package-private,以获得更好的封装性和模块级控制。

完整示例代码可在 GitHub 上查看。


原始标题:Package-Private Alternative in Kotlin