Kotlin中的Java静态方法等效于什么?


618

staticKotlin中没有关键字。

static用Kotlin 表示Java方法的最佳方法是什么?



12
请注意: Kotlin删除了Java样式的静态变量,以鼓励更可维护的(敢于说“更好”)编码实践。静态全局变量通常反对OOP范式,但它们可能非常方便。因此,Kotlin为我们提供了同伴,这是一种对OOP更友好的静态方法。
Nicholas Miller

据谷歌称,Kotlin现在是Android开发的首选语言。
AFD

@NicholasMiller为什么对OOP更友好?我认为在没有反复出现的静电(样板)的情况下,读取和写入更为容易。还是有另一个很好的理由?
Torben G

Answers:


886

您将功能放置在“伴侣对象”中。

所以像这样的java代码:

class Foo {
  public static int a() { return 1; }
}

会变成

class Foo {
  companion object {
     fun a() : Int = 1
  }
}

然后,您可以从Kotlin代码内部使用它,如下所示:

Foo.a();

但是从Java代码中,您需要将其称为

Foo.Companion.a();

(这也来自Kotlin。)

如果您不想指定Companion位,则可以添加@JvmStatic注释或命名伴侣类。

文档

伴侣对象

类内的对象声明可以用伴随关键字标记:

class MyClass {
   companion object Factory {
       fun create(): MyClass = MyClass()
   }
}

可以通过仅使用类名作为限定符来调用伴随对象的成员:

val instance = MyClass.create()

...

但是,在JVM上,如果使用@JvmStatic 批注,则可以将伴随对象的成员生成为实际的静态方法和字段。有关更多详细信息,请参见Java互操作性部分。

添加@JvmStatic注释如下所示

class Foo {
  companion object {
    @JvmStatic
    fun a() : Int = 1;
  }
}

然后它将作为一个真正的Java静态函数存在,可以从Java和Kotlin中以方式访问Foo.a()

如果只是不喜欢该Companion名称,则还可以为伴随对象提供一个明确的名称,如下所示:

class Foo {
  companion object Blah {
    fun a() : Int = 1;
  }
}

它可以让您以相同的方式从Kotlin调用它,但可以从java like Foo.Blah.a()(在Kotlin中也可以)调用它。


4
在科特林,这可能fun a(): Int { return 1 }甚至是fun a(): Int = 1
德米特里·扎伊采夫

3
@DmitryZaitsev fun a() = 1
Moira

工厂是什么意思?
巴古斯·阿吉·桑托索

@BagusAjiSantoso Factory是伴随对象的名称 -但这可用于什么?我不知道,但是我很感兴趣,所以我创建了一个专门针对这个问题:stackoverflow.com/q/45853459/221955
Michael Anderson

1
@ Yajairo87我想你问的是什么太多的盖评论在这里-所以我创建了一个问题,直接解决它:stackoverflow.com/questions/47046474/...
迈克尔·安德森

154

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

宣言

package foo

fun bar() = {}

用法

import foo.bar

或者

import foo.*

您现在可以使用以下命令调用该函数:

bar()

或者,如果您不使用import关键字:

foo.bar()

如果不指定软件包,则可以从根目录访问该功能。

如果您只有Java经验,这似乎有些奇怪。原因是kotlin不是严格的面向对象语言。您可以说它支持类之外的方法。

编辑:他们已编辑文档,不再包含有关推荐软件包级别功能的句子。是上面提到的原稿。


8
请注意,实际上这些“顶层”或“包”功能实际上已编译为它们自己的类。在上面的示例中,编译器将创建一个class FooPackage具有所有顶级属性和函数的,并将所有引用适当地路由到它们。来自jetbrains的更多信息。
米切尔·特雷西

29
+1用于解释如何在Kotlin中实现等效权而不仅仅是Java中的镜像等效权。
凤凰城

1
这应该是接受的答案,或者mod应该更新接受的答案以包含程序包级别的功能
Osama Shabrez,

@MitchellTracy极好的信息!谢谢。
Droid

1
到目前为止,这是更好的解决方案。只是想澄清一下,定义函数的位置bar()与文件名无关,您可以为其命名,也可以使用其他名称BarUtils.kt,然后如文本所示,您将使用import <package name>.bar
Mariano Ruiz

33

A.旧的Java方式:

  1. 声明a companion object包含一个静态方法/变量

    class Foo{
    companion object {
        fun foo() = println("Foo")
        val bar ="bar"  
        }
    }
  2. 采用 :

    Foo.foo()        // Outputs Foo    
    println(Foo.bar) // Outputs bar


B.新科特林方式

  1. 直接在文件上声明,而无需在文件上进行类声明.kt

    fun foo() = println("Foo")
    val bar ="bar"
  2. 使用methods/variables和他们的名字。(导入后

    采用 :

    foo()        // Outputs Foo          
    println(bar) // Outputs bar     


如果我试图在其他类中初始化,它会给出java.lang.ExceptionInInitializerError,而我使用var而不是val
Sudarshan

4
方法调用需要具有这样的INSTANCE关键字:Foo.INSTANCE.sayFoo()
Raeglan,

我认为,如果您static CLASS不只是想要一个解决方案,则此解决方案是首选方法static methdos。因为有了伴随对象,您仍然可以实例化父类。
fabriciorissetto

val不是静态的,等效static final于Java
Farid

23

使用object表示val / var / method使其静态。您也可以使用object而不是singleton类。如果您想在一个类的内部进行静态处理,可以使用同伴

object Abc{
     fun sum(a: Int, b: Int): Int = a + b
    }

如果需要从Java调用它:

int z = Abc.INSTANCE.sum(x,y);

在Kotlin中,请忽略INSTANCE。


11

这也对我有用

object Bell {
    @JvmStatic
    fun ring() { }
}

来自Kotlin

Bell.ring()

来自Java

Bell.ring()


5

您需要为静态方法传递伴随对象,因为kotlin没有static关键字-可以通过仅使用类名作为限定符来调用伴随对象的成员:

package xxx
    class ClassName {
              companion object {
                       fun helloWord(str: String): String {
                            return stringValue
                      }
              }
    }

4

您可以通过2种方式在Kotlin中应用静态

首先在课堂上做一个伴侣对象

例如:

class Test{
    companion object{
          fun isCheck(a:Int):Boolean{
             if(a==0) true else false
          }
     }
}

您可以将该函数称为

Test.Companion.isCheck(2)

我们可以使用的另一种方法是制作一个对象类

object Test{
       fun isCheck(a:Int):Boolean{
            if(a==0) true else false
       }
}

编码愉快!


对于首次使用(即Test.Companion.isCheck(2)),IDE会显示警告并说出Companion reference is redundant。可以简化为Test.isCheck(2),并且简化后的形式更类似于java的等效形式。
VSB

3

Kotlin没有任何静态关键字。您将其用于Java

 class AppHelper {
        public static int getAge() {
            return 30;
        }
    }

和科特林

class AppHelper {
        companion object {
            fun getAge() : Int = 30
        }
    }

呼吁Java

AppHelper.getAge();

呼吁科特林

AppHelper.Companion.getAge();

我认为它运作良好。


3

我想在以上答案中添加一些内容。

是的,您可以在源代码文件(外部类)中定义函数。但是,最好使用Companion Object在类内定义静态函数,因为可以利用Kotlin扩展来添加更多静态函数。

class MyClass {
    companion object { 
        //define static functions here
    } 
}

//Adding new static function
fun MyClass.Companion.newStaticFunction() {
    // ...
}

您可以调用上面定义的函数,因为您将在Companion Object中调用任何函数。


3

即使现在已经有2年多的历史了,并且有很多不错的答案,但我发现缺少一些其他方法来获取“静态”科特林字段。这是Kotlin-Java static互操作的示例指南:

方案1:在Kotlin for Java中创建静态方法

科特林

@file:JvmName("KotlinClass") //This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits

class KotlinClass {
    companion object {

        //This annotation tells Java classes to treat this method as if it was a static to [KotlinClass]
        @JvmStatic
        fun foo(): Int = 1

        //Without it, you would have to use [KotlinClass.Companion.bar()] to use this method.
        fun bar(): Int = 2
    }
}

爪哇

package com.frybits;

class JavaClass {

    void someFunction() {
        println(KotlinClass.foo()); //Prints "1"
        println(KotlinClass.Companion.bar()); //Prints "2". This is the only way to use [bar()] in Java.
        println(KotlinClass.Companion.foo()); //To show that [Companion] is still the holder of the function [foo()]
    }

    //Because I'm way to lazy to keep typing [System.out], but I still want this to be compilable.
    void println(Object o) {
        System.out.println(o);
    }
}

迈克尔·安德森(Michael Anderson)的答案远不止于此,在这种情况下,绝对可以参考。


下一个场景将处理在Kotlin中创建静态字段的问题,这样Java就不必继续调用KotlinClass.foo()那些您不需要静态函数的情况。

方案2:在Kotlin for Java中创建静态变量

科特林

@file:JvmName("KotlinClass") //This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits

class KotlinClass {

    companion object {

        //This annotation tells Kotlin to not generate the getter/setter functions in Java. Instead, this variable should be accessed directly
        //Also, this is similar to [@JvmStatic], in which it tells Java to treat this as a static variable to [KotlinClass].
        @JvmField
        var foo: Int = 1

        //If you want something akin to [final static], and the value is a primitive or a String, you can use the keyword [const] instead
        //No annotation is needed to make this a field of [KotlinClass]. If the declaration is a non-primitive/non-String, use @JvmField instead
        const val dog: Int = 1

        //This will be treated as a member of the [Companion] object only. It generates the getter/setters for it.
        var bar: Int = 2

        //We can still use [@JvmStatic] for 'var' variables, but it generates getter/setters as functions of KotlinClass
        //If we use 'val' instead, it only generates a getter function
        @JvmStatic
        var cat: Int = 9
    }
}

爪哇

package com.frybits;

class JavaClass {

    void someFunction() {
        //Example using @JvmField
        println(KotlinClass.foo); //Prints "1"
        KotlinClass.foo = 3;

        //Example using 'const val'
        println(KotlinClass.dog); //Prints "1". Notice the lack of a getter function

        //Example of not using either @JvmField, @JvmStatic, or 'const val'
        println(KotlinClass.Companion.getBar()); //Prints "2"
        KotlinClass.Companion.setBar(3); //The setter for [bar]

        //Example of using @JvmStatic instead of @JvmField
        println(KotlinClass.getCat());
        KotlinClass.setCat(0);
    }

    void println(Object o) {
        System.out.println(o);
    }
}

Kotlin的一大特色是您可以创建顶级函数和变量。这使得创建常量字段和函数的“无类”列表变得非常有用,这些列表又可以用作staticJava中的函数/字段。

方案3:从Java访问Kotlin中的顶级字段和函数

科特林

//In this example, the file name is "KSample.kt". If this annotation wasn't provided, all functions and fields would have to accessed
//using the name [KSampleKt.foo()] to utilize them in Java. Make life easier for yourself, and name this something more simple
@file:JvmName("KotlinUtils")

package com.frybits

//This can be called from Java as [KotlinUtils.TAG]. This is a final static variable
const val TAG = "You're it!"

//Since this is a top level variable and not part of a companion object, there's no need to annotate this as "static" to access in Java.
//However, this can only be utilized using getter/setter functions
var foo = 1

//This lets us use direct access now
@JvmField
var bar = 2

//Since this is calculated at runtime, it can't be a constant, but it is still a final static variable. Can't use "const" here.
val GENERATED_VAL:Long = "123".toLong()

//Again, no need for @JvmStatic, since this is not part of a companion object
fun doSomethingAwesome() {
    println("Everything is awesome!")
}

爪哇

package com.frybits;

class JavaClass {

    void someFunction() {

        println(KotlinUtils.TAG); //Example of printing [TAG]


        //Example of not using @JvmField.
        println(KotlinUtils.getFoo()); //Prints "1"
        KotlinUtils.setFoo(3);

        //Example using @JvmField
        println(KotlinUtils.bar); //Prints "2". Notice the lack of a getter function
        KotlinUtils.bar = 3;

        //Since this is a top level variable, no need for annotations to use this
        //But it looks awkward without the @JvmField
        println(KotlinUtils.getGENERATED_VAL());

        //This is how accessing a top level function looks like
        KotlinUtils.doSomethingAwesome();
    }

    void println(Object o) {
        System.out.println(o);
    }
}

可以在Java中用作“静态”字段的另一个值得注意的提及是Kotlin object类。这些是零参数单例类,这些类在首次使用时会被延迟实例化。有关它们的更多信息,请参见:https : //kotlinlang.org/docs/reference/object-declarations.html#object-declarations

但是,要访问单例,将INSTANCE创建一个特殊的对象,该对象原样处理起来很麻烦Companion。这是使用注释static在Java中提供清晰感觉的方法:

方案4:使用object

科特林

@file:JvmName("KotlinClass")

//This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits

object KotlinClass { //No need for the 'class' keyword here.

    //Direct access to this variable
    const val foo: Int = 1

    //Tells Java this can be accessed directly from [KotlinClass]
    @JvmStatic
    var cat: Int = 9

    //Just a function that returns the class name
    @JvmStatic
    fun getCustomClassName(): String = this::class.java.simpleName + "boo!"

    //Getter/Setter access to this variable, but isn't accessible directly from [KotlinClass]
    var bar: Int = 2

    fun someOtherFunction() = "What is 'INSTANCE'?"
}

爪哇

package com.frybits;

class JavaClass {

    void someFunction() {
        println(KotlinClass.foo); //Direct read of [foo] in [KotlinClass] singleton

        println(KotlinClass.getCat()); //Getter of [cat]
        KotlinClass.setCat(0); //Setter of [cat]

        println(KotlinClass.getCustomClassName()); //Example of using a function of this 'object' class

        println(KotlinClass.INSTANCE.getBar()); //This is what the singleton would look like without using annotations
        KotlinClass.INSTANCE.setBar(23);

        println(KotlinClass.INSTANCE.someOtherFunction()); //Accessing a function in the object class without using annotations
    }

    void println(Object o) {
        System.out.println(o);
    }
}

3

简而言之,您可以使用“伴侣对象”进入Kotlin静态世界,例如:

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

并使用代码中的“ const val”来使字段恒定。但请尽量避免使用静态类,因为使用Mockito!进行单元测试时会遇到困难。


3

java静态方法到kotlin等效项的确切转换将是这样的。例如,此处util类具有一个静态方法,该方法在java和kotlin中均等效。@JvmStatic的使用很重要。

Java代码:

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

Kotlin代码:

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

2

只需您需要创建一个伴随对象并将函数放入其中

  class UtilClass {
        companion object {
  //        @JvmStatic
            fun repeatIt5Times(str: String): String = str.repeat(5)
        }
    }

要从kotlin类调用方法:

class KotlinClass{
  fun main(args : Array<String>) { 
    UtilClass.repeatIt5Times("Hello")
  }
}

或使用导入

import Packagename.UtilClass.Companion.repeatIt5Times
class KotlinClass{
  fun main(args : Array<String>) { 
     repeatIt5Times("Hello")
  }
}

要从Java类调用方法:

 class JavaClass{
    public static void main(String [] args){
       UtilClass.Companion.repeatIt5Times("Hello");
    }
 }

或通过在方法中添加@JvmStatic批注

class JavaClass{
   public static void main(String [] args){
     UtilClass.repeatIt5Times("Hello")
   }
}

或两者都通过在方法中添加@JvmStatic批注并在Java中进行静态导入

import static Packagename.UtilClass.repeatIt5Times
class JavaClass{
   public static void main(String [] args){
     repeatIt5Times("Hello")
   }
}

2

对于Java:

public class Constants {
public static final long MAX_CLICK_INTERVAL = 1000;}

等效的Kotlin代码:

object  Constants {
const val MAX_CLICK_INTERVAL: Long = 1000}

因此,等效于Java静态方法的是Kotlin中的对象类。


2

对于Android,使用从单个活动到所有必要活动的字符串。就像Java中的static

public final static String TEA_NAME = "TEA_NAME";

Kotlin中的等效方法:

class MainActivity : AppCompatActivity() {
    companion object {
        const val TEA_NAME = "TEA_NAME"
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

需要价值的另一项活动:

val teaName = MainActivity.TEA_NAME

2

除了迈克尔·安德森(Michael Anderson)的答案,我在项目中使用其他两种方式进行编码。

第一:

您可以将所有变量归为一类。创建了一个名为Const的kotlin文件

object Const {
    const val FIRST_NAME_1 = "just"
    const val LAST_NAME_1 = "YuMu"
}

您可以在kotlin和Java代码中使用它

 Log.d("stackoverflow", Const.FIRST_NAME_1)

第二:

您可以使用Kotlin的扩展功能
创建一个名为Ext的kotlin文件,下面的代码是Ext文件中的所有代码

package pro.just.yumu

/**
 * Created by lpf on 2020-03-18.
 */

const val FIRST_NAME = "just"
const val LAST_NAME = "YuMu"

您可以在kotlin代码中使用它

 Log.d("stackoverflow", FIRST_NAME)

您可以在Java代码中使用它

 Log.d("stackoverflow", ExtKt.FIRST_NAME);

1

将它们直接写入文件。

在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也用于控制编译文件名,应将其放在包名声明之前)。


7
您忘记了“科特林(丑陋)” ...科特林:伴侣对象{val handler = object:Handler(Looper.getMainLooper()){] ..... JAVA:静态Handler Handler = new Handler(Looper.getMainLooper() ){};
CmosBattery

1

使用@JVMStatic注释

companion object {

    // TODO: Rename and change types and number of parameters
    @JvmStatic
    fun newInstance(param1: String, param2: String) =
            EditProfileFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
}

1

让我们有一个班级Student。您有一个静态方法getUniversityName()和一个名为totalStudent的静态字段。

您应该在类中声明伴随对象块。

companion object {
 // define static method & field here.
}

然后你的班级看起来像

    class Student(var name: String, var city: String, var rollNumber: Double = 0.0) {

    // use companion object structure
    companion object {

        // below method will work as static method
        fun getUniversityName(): String = "MBSTU"

        // below field will work as static field
        var totalStudent = 30
    }
}

然后,您可以像这样使用那些静态方法和字段。

println("University : " + Student.getUniversityName() + ", Total Student: " + Student.totalStudent)
    // Output:
    // University : MBSTU, Total Student: 30

1

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

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

编译后m将具有public static final void的签名

import p.m


0

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

  • 即使在Kotlin中不存在实际的静态概念,向对象声明中添加伴随对象也可以将静态功能添加 到对象。
  • 一个同伴对象可以访问类的所有成员也包括私有的构造。
  • 实例化类时,将初始化一个伴随对象
  • 一个同伴对象不能在类之外声明。

    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

0

所有静态成员和函数都应位于伴随块内

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

    fun staticMethod() {
    }
  }

0

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

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

就像在Java中使用任何静态方法一样使用它:

StringUtils.toUpper("foobar")

在Kotlin中,这种模式是无用的,其优点之一是它消除了对用静态方法填充的类的需求。根据您的用例,更适当地使用全局,扩展和/或局部功能。在我工作的地方,我们经常在单独的平面文件中使用以下命名约定定义全局扩展功能:[className] Extensions.kt,即FooExtensions.kt。但是更典型的是,我们在操作类或对象中需要的地方编写函数。


0

在Java中,我们可以按以下方式编写

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

在Kotlin中,我们可以通过以下方式编写

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

随播广告在Kotlin中用作静态广告。


0

kotlin文档提供者可以通过三种方式做到这一点,第一种是在package中定义函数,而无需使用类:

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
}
}

-1

如果需要将函数或属性绑定到类而不是实例,可以在一个伴侣对象中声明它:

class Car(val horsepowers: Int) {
    companion object Factory {
        val cars = mutableListOf<Car>()

        fun makeCar(horsepowers: Int): Car {
            val car = Car(horsepowers)
            cars.add(car)
            return car
        }
    }
}

伴随对象是一个单例对象,可以通过包含类的名称直接访问其成员

val car = Car.makeCar(150)
println(Car.Factory.cars.size)

似乎已接受的答案已经在描述伴随对象。因此,还有许多其他答案。您的答案是否有新内容?
Sneftel

为进一步澄清,你可以看看这里kotlinlang.org/docs/tutorials/kotlin-for-py/...
阿萨德马哈茂德

-2

您可以使用随播对象-kotlinlang

首先创建该界面即可显示

interface I<T> {

}

然后,我们必须在该接口内部创建一个函数:

fun SomeFunc(): T

然后,我们需要一个类:

class SomeClass {}

在该类中,我们需要在该类中有一个伴随对象:

companion object : I<SomeClass> {}

在同伴对象内部,我们需要该旧SomeFunc功能,但是我们需要对其进行改写:

override fun SomeFunc(): SomeClass = SomeClass()

最后,在所有这些工作之下,我们需要一些东西来增强静态功能,我们需要一个变量:

var e:I<SomeClass> = SomeClass()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.