在 Kotlin 中使用静态 Java 方法作为静态(或单例)属性

use static Java methods as static (or singleton) properties in Kotlin

我的 SDK 暴露了一个只有静态方法的 Java 接口,例如

public interface MyDevice { 
  public static void setLocation(Location location) {…}
  public static Location getLocation() {…}
}

在使用 SDK 的 Java 应用程序中,我的客户可以使用这些 就好像 它是一个单例,例如

Location currentLocation = MyDevice.getLocation();

当此 SDK 集成到 Kotlin 应用程序中时,很自然地表示与 属性 相同:

val currentLocation = MyDevice.location

问题是,此内置互操作仅适用于非静态方法。

我可以在 Kotlin 中创建一个单例并让它处理翻译:

object myDevice {
    var location: Location
    get() = MyDevice.getLocation()
    set(location) = MyDevice.setLocation(location)
}

但是,在其他 Java-only SDK 中,这个单一的 Kotlin 文件不会对不使用 Kotlin 的客户产生负面影响吗?同样可以用Java来表达吗?

或者我应该简单地将 MyDevice.java 转换为 Kotlin?此步骤对仍在使用 Java 的客户有何负面影响?

在 Kotlin 中,为了获得与 Java 接口中的静态方法相同的结果,您应该使用 companion object 来声明您的静态方法。示例:

interface MyDevice {

    // instance methods   

    companion object {
        // static methods

        @JvmStatic
        fun setLocation(location: Location) {...}

        @JvmStatic
        fun getLocation(): Location {...}
    }
}

注意 @JvmStatic 注释。当您从 Java class 调用这些 Kotlin 函数时,它们将被解释为静态方法。示例:

public void myJavaMethod() {
    Location location = MyDevice.getLocation();
}

您描述的问题是缺少元数据 Kotlin 需要将静态方法视为 Class 扩展函数的扩展属性。

连同问题KT-11968,至少目前无法实现。

最好的选择是 API 转换为 Kotlin,并在必要时支持 @JvmStaic/@JvmField 和 @JvmDefault 以实现向后兼容性。

interface MyDevice {
  companion object {
    // nullable type or explicit init
    var location: Location? 
      @JvmStatic get
      @JvmStatic set


// kotlin
val x = MyDevice.location
MyDevice.location = x


// java
var x = MyDevice.getLocation();
MyDevice.setLocation(x);

kotlin lang 提供的解决方案很少,我们可以使用这些解决方案来简化您的案例。在 Java 之间做出更好的工作是 kotlin 的本质,对我来说,我没有看到使用 Companion/Object 创建类似于 Java 的静态方法有任何缺点。为了简单起见,kotlin 语言本身也为开发人员提供了许多方便的帮助程序。以下是我们可以申请的:

  1. 对象
    object MyDevice {
    
        @JvmStatic
        fun getLocation(): Location {
        }
    
        @JvmStatic
        fun setLocation(location: Location) {
    
        }
    }
  1. 同伴
    class MyDevice {
        companion object {
    
            @JvmStatic
            fun getLocation(): Location {
    
            }
    
            @JvmStatic
            fun setLocation(location: Location) {
    
            }
        }
    }

来电Java:

MyDevice.setLocation(location);
final Location location = MyDevice.getLocation();

阅读了专家的回答,研究了他们提供的链接,反编译了包装器的 Kotlin 代码 class 并分析了一个演示应用程序(纯 Java) Kotlin-wrapped 库,我决定更改 Java API.

现在我有一个 class 和一个 public 静态对象:

public class MyDevice { 
  public static MyDevice myDevice;
  public void setLocation(Location location) {…}
  public Location getLocation() {…}
}

现在 Java 消费者将使用

import static com.example.sdk.MyDevice.myDevice;

Kotlin 消费者不需要 static:

import com.example.sdk.MyDevice.myDevice

所以,我的库不需要单独的 Kotlin 风格!