在Kotlin中没有静态关键字。

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


当前回答

在kotlin中没有静态关键字。如果你想遵循DRY, kotlin文档建议使用包级函数。 创建一个扩展名为.kt的文件,并将您的方法放在其中。

package p
    fun m(){
    //fun body
    }

编译后m将会有一个public static final void的签名

and

import p.m

其他回答

很多人提到伴生对象,这是正确的。但是,正如你所知道的,你也可以使用任何类型的对象(使用对象关键字,而不是类),即,

object StringUtils {
    fun toUpper(s: String) : String { ... }
}

像使用java中的静态方法一样使用它:

StringUtils.toUpper("foobar")

That sort of pattern is kind of useless in Kotlin though, one of its strengths is that it gets rid of the need for classes filled with static methods. It is more appropriate to utilize global, extension and/or local functions instead, depending on your use case. Where I work we often define global extension functions in a separate, flat file with the naming convention: [className]Extensions.kt i.e., FooExtensions.kt. But more typically we write functions where they are needed inside their operating class or object.

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

顶级

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

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");

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

java静态方法到kotlin等效方法的确切转换如下所示。例:这里util类有一个静态方法,它在java和kotlin中都是等效的。@JvmStatic的使用非常重要。

Java代码:

    class Util{
         public static String capitalize(String text){
         return text.toUpperCase();}
       }

芬兰湾的科特林代码:

    class Util {
        companion object {
            @JvmStatic
            fun capitalize(text:String): String {
                return text.toUpperCase()
            }
        }
    }

kotlin文档提供了三种方法, 第一个是在包中定义函数,没有类:

package com.example

fun f() = 1

第二个是使用@JvmStatic注释:

package com.example

class A{
@JvmStatic
fun f() = 1
}

第三个是使用伴侣对象

package com.example

clss A{
companion object{
fun f() = 1
}
}

简单来说,你可以使用“同伴对象”进入Kotlin静态世界,比如:

  companion object {
    const val TAG = "tHomeFragment"
    fun newInstance() = HomeFragment()
}

要创建一个常量字段,请使用代码中的“const val”。 但是尽量避免使用静态类,因为它会给使用Mockito进行单元测试带来困难。