顶级/companion object 用于 static 属性
顶级
当属性与类有些相关时,在类声明之前将它们定义为顶级属性:
const val MAX_ATTEMPTS = 3
private const val DEFAULT_NAME = "Guest"
private const val MIN_AGE = 16
data class User(val id: String, val name: String = DEFAULT_NAME)
这类似于 Java 中的 static 属性。
当属性完全独立于任何类时,您可以在没有类的单独文件中将它们定义为顶级。
companion object
当属性与一个类密切相关并且只在该类中使用时,在companion object中定义它们:
data class User(val id: String, val name: String = DEFAULT_NAME) {
companion object {
const val DEFAULT_NAME = "Guest"
const val MIN_AGE = 16
}
}
顶级/companion object 用于static 方法
顶级
与上面的属性类似,当函数与某个类有些相关时,将它们定义在类的上方:
fun getAllUsers() { }
fun getProfileFor(userId: String) { }
data class User(val id: String, val name: String)
用法:
val userList = getAllUsers()
companion object
当函数与类密切相关时,在companion object 中定义它们:
data class User(val id: String, val name: String) {
companion object {
fun getAll() { }
fun profileFor(userId: String) { }
}
}
用法:
val userProfile = User.profileFor("34")
这类似于 Java 中的 static 方法。
顶级函数对于 Kotlin 来说通常更惯用。在companion object 中定义函数的更好理由是当您使用interface 扩展companion object 时。单例部分显示了这方面的一个示例。
static 类的嵌套类
当具有相关功能的类属于同一类时,可以通过嵌套将它们组合在一起:
class User(val id: String, val name: String) {
class UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
这相当于Java 中的static 嵌套类。这里的UserAccess 类实现了一个interface UserDao。
用法:
fun main() {
val john = User("34", "John")
val userAccess = User.UserAccess()
userAccess.add(john)
}
单例object 为static INSTANCE
顶级
当您只需要一个类的单个对象时,您不再需要像在 Java 中那样在类中创建 static INSTANCE。只需使用顶级object 声明:
object UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
还要注意在单例中扩展 interface 或 class 是多么容易。
上面的代码在后台生成了以下static INSTANCE Java 中的单例模式(简化):
public final class UserAccess implements UserDao {
public static final UserAccess INSTANCE;
public void add(User user) { }
public void remove(String id) { }
private UserAccess() { }
static { INSTANCE = new UserAccess();}
}
companion object
当单例与类密切相关时,使用companion object:
data class User(val id: String, val name: String) {
companion object : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
这样你可以得到更优雅的命名:User.add(john)。此外,您明确表明此单例仅用作User 类的实用程序。如果您需要多个单例或函数/属性组,也可以在类中使用不带 companion 关键字的 object。
companion object 为static 工厂
Koltin 中的工厂函数是使用companion object 创建的。当您想要提供多种方法来创建对象且对象构造过程很复杂或多个构造函数不够表达时,工厂函数非常有用。
例如下面sn -p中的newInstance()工厂函数通过自动生成id来创建用户:
class User private constructor(val id: Long, val name: String) {
companion object {
private var currentId = 0L;
fun newInstance(name: String) = User(currentId++, name)
}
}
这相当于 Java 中的 static 工厂方法。
constructor 保留为private,但companion object 可以访问constructor。
在上面的代码中,保证了下一个id 生成的一致性,因为companion object 是一个单例,只有一个对象会跟踪id,不会有任何重复的ID。
还请注意,伴随对象可以具有表示状态的属性(在本例中为currentId)。
用法:
val john = User.newInstance("John")
@JvmStatic 用于 Java 互操作性
Java 的静态概念在 Kotlin 中不存在。 companion object 是真正的 class 的实例,称为 Companion。因此,当您从 Java 调用 Kotlin 代码时,Companion 类的对象首先在幕后实例化。您需要在 Java 中使用 Companion 对象调用该函数:
Profile userProfile = User.Companion.profileFor("34");
为了使用惯用的 Java 命名并减少冗长,请在该函数或属性上使用 @JvmStatic 注释:
companion object {
@JvmStatic
fun profileFor(userId: String): Profile { }
}
@JvmStatic 注释创建了 getProfileFor() 函数的单独的纯 static 副本。现在您可以使用常规语法从 Java 中使用它:
Profile userProfile = User.profileFor("34");
就是这样!希望这些示例对您的项目有用。