将静态变量从 Java 转换为 Kotlin

Convert static variables from Java to Kotlin

我正在尝试将以下代码转换为 Kotlin,并且仍然有 Java 使用的 classes (Foo) 之一。进行此转换的正确方法是什么?

原文Java:

public class Foo {
   public static final String C_ID = "ID";
   public static final String C_NAME = "NAME";
   public static final String[] VALUES = {"X", "Y", "Z"};

   public static String[] getAll() {
       return new String[] {C_ID, C_NAME};
   }
}

public class Bar {
    public void doStuff() {
        String var1 = Foo.C_ID;
        String[] array1 = Foo.VALUES;
        String[] array2 = Foo.getAll();
    }
}

将 Foo 自动转换为 Kotlin

object Foo {
    val C_ID = "ID"
    val C_NAME = "NAME"
    val VALUES = arrayOf("X", "Y", "Z")

    val all: Array<String>
        get() = arrayOf(C_ID, C_NAME)
}

问题:

栏 class 无法再访问 C_ID 或 VALUES(错误:"private access")

如果我把 "const" 放在 C_ID 前面,它会起作用...但是我不能对 VALUES 做同样的事情("const" 只能用于原始类型或字符串)

我应该采用不同的方式来执行此操作吗(因此 Java 代码和 Kotlin 代码都可以访问 Foo 中的所有内容)?

您应该能够访问值 "the kotlin way":

object Foo {
val C_ID = "ID"
val C_NAME = "NAME"
val VALUES = arrayOf("X", "Y", "Z")

val all: Array<String>
    get() = arrayOf(C_ID, C_NAME)
}

fun main(args: Array<String>) {
    Foo.all.forEach { it->println(it) }
}

结果为:

ID
NAME

Process finished with exit code 0

当前语义来自Kotlin Beta Candidate:

@JvmField and objects

We have made the strategy for generating pure fields (as opposed to get/set pairs) more predictable: from now on only properties annotated as @JvmField, lateinit or const are exposed as fields to Java clients. Older versions used heuristics and created static fields in objects unconditionally, which is against our initial design goal of having binary-compatibility-friendly APIs by default.

Also, singleton instances are now accessible by the name INSTANCE (instead of INSTANCE$).

根据这个和 reference,有三种方法可以使用来自 Java 的 Kotlin object 的属性:

  • 使用Foo.INSTANCE.

    默认情况下,object的属性不会是Java的静态字段,但Java可以通过Foo对象实例访问属性--Foo.INSTANCE.

    所以表达式将是 Foo.INSTANCE.getC_ID().

  • @JvmStatic注释标记一个属性:

    object Foo {
        @JvmStatic val C_ID = "ID"
        //...
    }
    

    这将为 C_ID 而不是 Foo 实例 getter 生成静态 getter,后者可以作为 Foo.getC_ID().

    [ 访问=66=]
  • 在 属性 声明上使用 @JvmField 注释:

    object Foo {
        @JvmField val C_ID = "ID"
        //...
    }
    

    这将使 Kotlin 编译器为 Java 而不是 属性 生成静态字段。 然后在 Java 中,您可以将其作为静态字段访问:Foo.C_ID.

    但是在您的示例中,如果没有像 all 这样的支持字段,它就无法处理属性。

对于基元,正如您所说,可以使用 const,就 Java.

中的可见性而言,它与 @JvmField 具有相同的效果

顺便说一句,在方法方面,情况也是一样的,并且有@JvmStatic注解。

在您的 foo class 中,您可以将这些属性和方法放在伴随对象中:

class Foo {

  companion object {
     val C_ID:String = "ID"
     val C_NAME:String = "NAME"
     @JvmField val VALUES = arrayOf("X", "Y", "Z")

     fun getAll():Array<String> {
        return arrayOf(C_ID, C_NAME)
     }
  }
}

然后你可以调用Foo.getAll(),然后Foo.C_ID、Foo.C_NAME和Foo.VALUES。

最好为常量创建新的 kotlin 文件。

创建 Constants.kt 文件并粘贴以下代码。

object Constants {
val C_ID = "ID"
val C_NAME = "NAME"
val VALUES = arrayOf("X", "Y", "Z")

val all: Array<String>
    get() = arrayOf(C_ID, C_NAME)
}

在您的主 activity 中,您可以通过常量名称访问常量,android 工作室将自动导入常量。这是我的主要活动:

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.example.architecturecompintro.Constants.C_ID
import com.example.architecturecompintro.Constants.C_NAME
import com.example.architecturecompintro.Constants.VALUES
import com.example.architecturecompintro.Constants.all

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val TAG = "info"

        Log.i(TAG, C_ID)
        Log.i(TAG,C_NAME)

        for(item in VALUES) {
            Log.i(TAG,item)
        }
        val arrayItem = all

        for(item in arrayItem) {
            Log.i(TAG,item)
        }
    }
}

我能够成功获得日志输出