[英]What is the equivalent of Java static methods in Kotlin?
Kotlin 中没有static
关键字。
在 Kotlin 中表示static
Java 方法的最佳方式是什么?
您将函数放置在“伴随对象”中。
所以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
注释或命名您的伴生类。
从文档:
伴随对象
类中的对象声明可以用
companion
关键字标记: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 调用它,但是从像Foo.Blah.a()
这样的 Java 调用它(它也可以在 Kotlin 中工作)。
Docs建议使用包级函数来解决大部分静态函数的需求。 它们只是在源代码文件中的类之外声明。 文件的包可以在文件的开头用 package 关键字指定。
声明
package foo
fun bar() = {}
用法
import foo.bar
或者
import foo.*
您现在可以使用以下命令调用该函数:
bar()
或者如果您不使用 import 关键字:
foo.bar()
如果您不指定包,则可以从根访问该函数。
如果您只有 Java 经验,这可能看起来有点奇怪。 原因是 kotlin 不是严格的面向对象语言。 你可以说它支持类之外的方法。
编辑:他们编辑了文档,不再包含关于推荐包级功能的句子。 这是上面提到的原文。
A. 旧的 Java 方式:
声明一个companion object
来包含一个静态方法/变量
class Foo{ companion object { fun foo() = println("Foo") val bar ="bar" } }
使用:
Foo.foo() // Outputs Foo println(Foo.bar) // Outputs bar
B. 新的 Kotlin 方式
直接在文件上声明.kt
文件上没有类。
fun foo() = println("Foo") val bar ="bar"
使用methods/variables
及其名称。 (导入后)
使用:
foo() // Outputs Foo println(bar) // Outputs bar
使用object表示 val/var/method 使其成为静态。 您也可以使用 object 而不是单例类。 如果您想在类中静态化,可以使用伴侣
object Abc{
fun sum(a: Int, b: Int): Int = a + b
}
如果您需要从 Java 调用它:
int z = Abc.INSTANCE.sum(x,y);
在 Kotlin 中,忽略 INSTANCE。
这也对我有用
object Bell {
@JvmStatic
fun ring() { }
}
来自科特林
Bell.ring()
来自爪哇
Bell.ring()
object objectName {
fun funName() {
}
}
尽管这已经有 2 年多的历史了,并且有很多很好的答案,但我发现缺少其他一些获取“静态”Kotlin 字段的方法。 以下是 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); } }
迈克尔安德森的回答提供了比这更深入的内容,并且绝对应该在这种情况下被引用。
下一个场景处理在 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 的一大特色是您可以创建顶级函数和变量。 这使得创建常量字段和函数的“无类”列表非常有用,这些列表又可以用作 Java 中的static
函数/字段。
场景 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
一样难以处理。 以下是在 Java 中如何使用注解赋予它干净的static
感觉:
场景 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); } }
您需要为静态方法传递伴随对象,因为 kotlin 没有 static 关键字 - 可以通过简单地使用类名作为限定符来调用伴随对象的成员:
package xxx
class ClassName {
companion object {
fun helloWord(str: String): String {
return stringValue
}
}
}
有两种方法可以在 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
}
}
快乐编码!
static
属性的顶级/ companion 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 中的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
}
}
static
方法的顶级/ companion object
顶级
与上面的属性类似,当函数与类有些相关时,将它们定义在类的正上方:
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)
}
static INSTANCE
单例object
顶级
当您只需要一个类的单个对象时,您不再需要像在 Java 中那样在类中创建static INSTANCE
。 只需使用顶级object
声明:
object UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
还要注意在单例中扩展interface
或class
是多么容易。
上面的代码,在底层,在 Java(简化)中产生了以下static 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 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
。
static
工厂的companion object
Koltin 中的工厂函数是使用companion object
创建的。 当您想要提供多种方法来创建对象时,工厂函数非常有用,但对象构造过程很复杂,或者当多个构造函数不够表达时。
例如,以下代码段中的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 互操作性 Kotlin 中不存在 Java 的静态概念。 companion object
是名为Companion
的真实class
的实例。 因此,当您从 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");
就是这样! 希望这些示例对您的项目有用。
只需创建一个伴随对象并将函数放入其中
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")
}
}
Kotlin 没有任何静态关键字。 您可以将以下代码用于 Java 和 Kotlin
object AppHelper {
@JvmStatic
fun getAge() : Int = 30
}
调用 Java 类
AppHelper.getAge();
呼吁 Kotlin 课程
AppHelper.getAge()
它非常适合我。 谢谢
伴随对象是java static关键字的替代形式,您可以通过将它们声明为伴随对象来使类或方法成为静态对象。
如果您是从同一个类中调用伴随对象,则也不需要使用该类名来限定伴随对象。
例如:
class SomeClass() {
val id: Int
init {
id = nextId++
}
private companion object {
var nextId = 1
}
}
fun main(args: Array<String>) {
repeat(2) {
println(SomeClass().id)
}
}
我想在上面的答案中添加一些内容。
是的,您可以在源代码文件(类外)中定义函数。 但是如果您使用Companion Object在类中定义静态函数会更好,因为您可以通过利用Kotlin Extensions添加更多静态函数。
class MyClass {
companion object {
//define static functions here
}
}
//Adding new static function
fun MyClass.Companion.newStaticFunction() {
// ...
}
您可以调用上面定义的函数,就像调用 Companion Object 中的任何函数一样。
对于 Java:
public class Constants {
public static final long MAX_CLICK_INTERVAL = 1000;}
等效的 Kotlin 代码:
object Constants {
const val MAX_CLICK_INTERVAL: Long = 1000}
因此,对于 Java 静态方法的等价物是 Kotlin 中的对象类。
简而言之,您可以使用“伴随对象”进入 Kotlin 静态世界,例如:
companion object {
const val TAG = "tHomeFragment"
fun newInstance() = HomeFragment()
}
并在代码中使用“const val”作为常量字段。 但是尽量避免使用静态类,因为它在使用 Mockito! 进行单元测试时会遇到困难。
对于 Android 使用从单个活动到所有必要活动的字符串。 就像java中的静态一样
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
java 静态方法到 kotlin 等效方法的确切转换是这样的。 例如,这里的 util 类有一个静态方法,它在 java 和 kotlin 中都是等价的。 @JvmStatic的使用很重要。
爪哇代码:
class Util{
public static String capitalize(String text){
return text.toUpperCase();}
}
科特林代码:
class Util {
companion object {
@JvmStatic
fun capitalize(text:String): String {
return text.toUpperCase()
}
}
}
除了迈克尔安德森的回答,我在我的项目中用其他两种方式编码。
您可以将所有变量都设置为一个类。 创建了一个名为 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);
将它们直接写入文件。
在 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
用于控制编译后的文件名,应该放在包名声明之前)。
让,你有一个类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
您可以通过Companion Objects实现 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
java代码如下:
class Foo { public static int a() { return 1; } }
将在kotlin中变为如下:
class Foo { companion object { fun a() : Int = 1 } }
但是,在JVM上使用@JvmStatic注释,我们可以将伴随对象的成员生成为真正的静态方法和字段。
使用@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)
}
}
}
很多人提到伴随对象,这是正确的。 但是,正如您所知,您也可以使用任何类型的对象(使用 object 关键字,而不是类),即,
object StringUtils {
fun toUpper(s: String) : String { ... }
}
像java中的任何静态方法一样使用它:
StringUtils.toUpper("foobar")
不过,这种模式在 Kotlin 中是无用的,它的优势之一是它摆脱了对充满静态方法的类的需求。 根据您的用例,使用全局、扩展和/或本地函数更合适。 在我工作的地方,我们经常使用命名约定在一个单独的平面文件中定义全局扩展函数:[className]Extensions.kt,即 FooExtensions.kt。 但更常见的是,我们在操作类或对象中需要的地方编写函数。
kotlin 中没有 static 关键字。 如果你想遵循 DRY,kotlin docs 建议使用包级函数。 创建一个扩展名为.kt的文件并将您的方法放入其中。
package p
fun m(){
//fun body
}
编译后m将有一个public static final void的签名
和
import p.m
☺
只需使用这种方法
object Foo{
fun foo() = println("Foo")
val bar ="bar"
}
Foo.INSTANCE.foo()
在Java中,我们可以用下面的方式编写
class MyClass {
public static int myMethod() {
return 1;
}
}
在 Kotlin 中,我们可以这样写
class MyClass {
companion object {
fun myMethod() : Int = 1
}
}
同伴在 Kotlin 中用作静态。
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
}
}
所有静态成员和函数都应该在伴随块内
companion object {
@JvmStatic
fun main(args: Array<String>) {
}
fun staticMethod() {
}
}
如果您需要将一个函数或属性绑定到一个类而不是它的实例,您可以在伴随对象中声明它:
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)
您可以使用伴随对象 - kotlinlang
它可以通过首先创建该接口来显示
interface I<T> {
}
然后我们必须在该接口内创建一个函数:
fun SomeFunc(): T
然后,我们需要一个类:
class SomeClass {}
在该类中,我们需要该类中的一个伴生对象:
companion object : I<SomeClass> {}
在 Companion 对象中,我们需要旧的SomeFunc
函数,但我们需要覆盖它:
override fun SomeFunc(): SomeClass = SomeClass()
最后,在所有这些工作之后,我们需要一些东西来为静态函数提供动力,我们需要一个变量:
var e:I<SomeClass> = SomeClass()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.