1. 概述

Kotlin 与 Java 的一个重要区别在于:Kotlin 没有 static 关键字。对于习惯了 Java 的开发者来说,这可能一开始有点不适应。

那么问题来了:如果不能用 static,我们该如何实现类似“静态方法”的功能?本文将介绍几种在 Kotlin 中模拟 Java 静态方法行为的常用方式,帮你少踩坑。

2. 包级函数(Package-Level Functions)

Kotlin 允许我们在 .kt 文件中直接定义函数,而无需将其包裹在类中——这种函数称为 包级函数。它们在编译后会变成 JVM 上的静态方法,非常适合用来替代工具类中的静态方法。

举个例子,创建一个 LoggingUtils.kt 文件:

fun debug(debugMessage: String) {
    println("[DEBUG] $debugMessage")
}

这个 debug 函数不在任何类内部,是一个典型的包级函数。

✅ 编译后效果

反编译后的 Java 代码如下:

public final class LoggingUtilsKt {
    public static final void debug(@NotNull String debugMessage) {
        Intrinsics.checkParameterIsNotNull(debugMessage, "debugMessage");
        String var1 = "[DEBUG] " + debugMessage;
        System.out.println(var1);
    }
}

⚠️ 注意:

  • 文件名决定了类名(LoggingUtils.ktLoggingUtilsKt
  • 所有包级函数都会被编译为该类中的 public static final 方法
  • Kotlin 自动生成了 Intrinsics.checkParameterIsNotNull 来确保非空参数安全

这种方式简单直接,✅ 推荐用于纯工具函数,比如日志、校验、格式化等场景。

3. Companion 对象

如果你希望某些“静态”方法和某个类紧密绑定(比如像 Java 工具类中常见的 StringUtils.isEmpty()),可以使用 companion object

3.1 基本用法

class ConsoleUtils {
    companion object {
        fun debug(debugMessage: String) {
            println("[DEBUG] $debugMessage")
        }
    }
}

上面这段代码中,companion object 创建了一个与类关联的单例对象。所有实例共享同一个 companion 实例。

❌ 默认调用方式不够优雅

默认情况下,从 Java 调用需要这样写:

ConsoleUtils.Companion.debug("Hello");

这显然不够简洁,也不符合我们对“静态方法”的预期。

3.2 使用 @JvmStatic 提升体验

为了让方法真正表现为 Java 中的静态方法,我们需要加上 @JvmStatic 注解:

class ConsoleUtils {
    companion object {
        @JvmStatic
        fun debug(debugMessage: String) {
            println("[DEBUG] $debugMessage")
        }
    }
}
}

✅ 编译后效果

反编译结果如下:

public final class ConsoleUtils {
    public static final ConsoleUtils.Companion Companion
      = new ConsoleUtils.Companion((DefaultConstructorMarker) null);

    @JvmStatic
    public static final void debug(@NotNull String debugMessage) {
        Companion.debug(debugMessage);
    }

    public static final class Companion {
        @JvmStatic
        public final void debug(@NotNull String debugMessage) {
            Intrinsics.checkParameterIsNotNull(debugMessage, "debugMessage");
            String var2 = "[DEBUG] " + debugMessage;
            System.out.println(var2);
        }

        private Companion() {}

        public Companion(DefaultConstructorMarker $constructor_marker) {
            this();
        }
    }
}

现在你可以直接通过类名调用:

ConsoleUtils.debug("Hello"); // ✅ 简洁!就像真正的静态方法

3.3 自定义 Companion 名称(可选)

你还可以给 companion object 起个名字,提高可读性:

class ConsoleUtils {
    companion object Helper {
        @JvmStatic
        fun debug(debugMessage: String) {
            println("[DEBUG] $debugMessage")
        }
    }
}

虽然名字变了,但 @JvmStatic 依然能生成顶层静态方法,不影响 Java 调用。

💡 小贴士:即使你命名了 companion(如 Helper),Java 中仍可通过 ConsoleUtils.Helper 访问原始对象,保留灵活性。

4. 总结

方式 适用场景 是否推荐 Java 互操作
包级函数 工具函数、独立逻辑 ✅ 强烈推荐
companion object + @JvmStatic 与类强相关的“静态”行为 ✅ 推荐
普通 companion 方法(无注解) 仅 Kotlin 内部使用 ⚠️ 不推荐用于 Java 调用

✅ 正确选择方式的关键:

  • 如果是通用工具函数,优先使用 包级函数
  • 如果方法逻辑与某个类密切相关,使用 companion object + @JvmStatic

最终目标:让 Kotlin 代码既 idiomatic,又能无缝对接 Java 生态。

所有示例代码均可在 GitHub 获取:https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-lang-oop


原始标题:Static Methods Behavior in Kotlin