在Kotlin中没有静态关键字。

在Kotlin中表示静态Java方法的最佳方法是什么?


当前回答

您可以通过Companion Objects在Kotlin中实现静态功能

Adding companion to the object declaration allows for adding the static functionality to an object even though the actual static concept does not exist in Kotlin. A companion object can access all members of the class too, including the private constructors. A companion object is initialized when the class is instantiated. A companion object cannot be declared outside the class. class MyClass{ companion object { val staticField = "This is an example of static field Object Decleration" fun getStaticFunction(): String { return "This is example of static function for Object Decleration" } } }

伴侣对象的成员可以通过简单地使用类名作为限定符来调用:

输出:

MyClass.staticField // This is an example of static field Object Decleration

MyClass.getStaticFunction() : // This is an example of static function for Object Decleration

其他回答

静态属性的顶级/伴生对象

顶级

当属性与类有些关联时,在类声明之前将它们定义为顶级属性:

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中的静态属性。

当属性完全独立于任何类时,可以将它们定义为不包含类的单独文件中的顶级属性。

伴星

当属性与类密切相关并且只会在该类中使用时,在伴随对象中定义它们:

data class User(val id: String, val name: String = DEFAULT_NAME) {
    companion object {
        const val DEFAULT_NAME = "Guest"
        const val MIN_AGE = 16
    }
}

用于静态方法的顶级/伴生对象

顶级

类似于上面的属性,当函数与类有点关联时,将它们定义在类的上方:

fun getAllUsers() { }

fun getProfileFor(userId: String) { }

data class User(val id: String, val name: String)

用法:

val userList = getAllUsers()

伴星

当函数与类密切相关时,在伴随对象中定义它们:

data class User(val id: String, val name: String) {

    companion object {

        fun getAll() { }

        fun profileFor(userId: String) { }
    }
}

用法:

val userProfile = User.profileFor("34")

这类似于Java中的静态方法。

顶级函数对于Kotlin来说通常更习惯。在伴生对象中定义函数的一个更好的原因是当您使用接口扩展伴生对象时。在单例部分中展示了一个示例。


静态类的嵌套类

当具有相关功能的类属于一起时,可以通过嵌套将它们分组在一起:

class User(val id: String, val name: String) {
    class UserAccess : UserDao {
        override fun add(user: User) { }
        override fun remove(id: String) { }
    }
}

这相当于Java中的静态嵌套类。这里的UserAccess类实现了一个接口UserDao。

用法:

fun main() {
    val john = User("34", "John")
    val userAccess = User.UserAccess()
    userAccess.add(john)
}

用于静态INSTANCE的单例对象

顶级

当您只想要类的单个对象时,您不再需要像在Java中那样在类中创建静态INSTANCE。简单地使用顶级对象声明:

object UserAccess : UserDao {
    override fun add(user: User) { }
    override fun remove(id: String) { }
}

还要注意在单例中扩展接口或类是多么容易。

上面的代码,在底层,在Java中产生以下静态INSTANCE单例模式(简化):

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对象:

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关键字的对象。


静态工厂的伴生对象

Koltin中的工厂函数是使用伴生对象创建的。当您希望提供多种方法来创建对象,而对象构造过程很复杂,或者多个构造函数表达能力不够时,工厂函数非常有用。

例如,下面代码段中的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中的静态工厂方法。

构造函数是私有的,但是伴生对象可以访问构造函数。

在上面的代码中,下一个id生成的一致性得到了保证,因为伴生对象是一个单例对象,只有一个对象会跟踪id,不会有任何重复的id。

还要注意,伴生对象可以具有表示状态的属性(在本例中为currentId)。

用法:

val john = User.newInstance("John")

@JvmStatic用于Java互操作性

Java的静态概念在Kotlin中并不存在。同伴对象是一个称为companion的真实类的实例。因此,当您从Java调用Kotlin代码时,Companion类的对象首先在后台实例化。你需要在Java中使用Companion对象调用该函数:

Profile userProfile = User.Companion.profileFor("34");

为了获得惯用的Java命名和更少的冗长,可以在函数或属性上使用@JvmStatic注释:

companion object {
    @JvmStatic
    fun profileFor(userId: String): Profile { }
}

@JvmStatic注释创建getProfileFor()函数的一个单独的纯静态副本。现在你可以在Java中使用常规语法:

Profile userProfile = User.profileFor("34");

就是这样!希望这些例子对你的项目有用。

Docs建议使用包级函数来解决静态函数的大部分需求。它们只是在源代码文件中的类之外声明的。文件的包可以在文件的开头用关键字package指定。

宣言

package foo

fun bar() = {}

使用

import foo.bar

另外

import foo.*

你现在可以调用函数:

bar()

或者不使用import关键字:

foo.bar()

如果不指定包,则可以从根目录访问该函数。

如果您只有java经验,这可能看起来有点奇怪。原因是kotlin不是严格的面向对象语言。你可以说它支持类之外的方法。

编辑: 他们编辑了文档,不再包含关于推荐包级函数的句子。这是上面提到的原稿。

将它们直接写入文件。

在Java中(丑陋):

package xxx;
class XxxUtils {
  public static final Yyy xxx(Xxx xxx) { return xxx.xxx(); }
}

在芬兰湾的科特林:

@file:JvmName("XxxUtils")
package xxx
fun xxx(xxx: Xxx): Yyy = xxx.xxx()

这两段代码在编译后是相等的(甚至编译后的文件名file:JvmName用于控制编译后的文件名,该文件名应该放在包名声明之前)。

所有静态成员和函数都应该在伴生块中

  companion object {
    @JvmStatic
    fun main(args: Array<String>) {
    }

    fun staticMethod() {
    }
  }

在Java中,我们可以这样写

class MyClass {
  public static int myMethod() { 
  return 1;
  }
}

在Kotlin中,我们可以用下面的方式写

class MyClass {
  companion object {
     fun myMethod() : Int = 1
  }
}

在Kotlin中,一个同伴被用作静态。