Преобразование статических переменных из Java в Kotlin
Я пытаюсь преобразовать следующий код в Kotlin И еще есть один из классов (Foo), используемых Java. Каков правильный способ сделать это преобразование?
Оригинальная 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)
}
Проблема:
Класс Bar больше не может обращаться к C_ID или VALUES (ошибка: "частный доступ" )
если я поставил "const" перед C_ID, он работает... но я не могу сделать то же самое с VALUES ( "const" может ТОЛЬКО использоваться на примитивах или String)
Есть ли другой способ, которым я должен это делать (так как код Java и код Kotlin могут получить доступ ко всему в Foo)?
Ответы
Ответ 1
Текущая семантика исходит из Kotlin Beta Candidate:
@JvmField и объекты
Мы создали стратегию для создания чистых полей (в отличие от пар get
/set
) более предсказуемым: теперь только свойства, аннотированные как @JvmField
, lateinit
или const
, отображаются как поля для клиентов Java. Старые версии использовали эвристику и создавали статические поля в объектах безоговорочно, что противоречит нашей первоначальной цели дизайна по умолчанию для API, совместимых с двоичной совместимостью.
Кроме того, экземпляры singleton теперь доступны по имени INSTANCE
(вместо INSTANCE$
).
В соответствии с этим и reference существует три способа работы со свойствами Kotlin object
от Java:
-
Используйте Foo.INSTANCE
.
По умолчанию свойства object
не будут статическими полями для Java, но Java может получить доступ к свойствам через экземпляр объекта Foo
- Foo.INSTANCE
.
Таким образом, выражение будет Foo.INSTANCE.getC_ID()
.
-
Отметьте свойство с помощью @JvmStatic
аннотации:
object Foo {
@JvmStatic val C_ID = "ID"
//...
}
Это будет генерировать статический getter для C_ID
вместо Foo
экземпляра getter, который будет доступен как Foo.getC_ID()
.
-
Использовать аннотацию @JvmField
для объявления свойства:
object Foo {
@JvmField val C_ID = "ID"
//...
}
Это заставит компилятор Kotlin генерировать статическое поле для Java вместо свойства.
Затем в Java вы можете получить к нему доступ как статическое поле: Foo.C_ID
.
Но он не будет работать на свойствах без полей поддержки, таких как all
в вашем примере.
Для примитивов, как вы сказали, можно использовать const
, который будет иметь тот же эффект, что и @JvmField
с точки зрения видимости в Java.
Кстати, когда дело доходит до методов, ситуация такая же, и для них есть аннотация @JvmStatic
.
Ответ 2
В вашем классе foo вы можете поместить эти свойства и метод внутри объекта-компаньона:
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.
Ответ 3
Вы должны иметь доступ к значениям "путь 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)
}
fun main(args: Array<String>) {
Foo.all.forEach { it->println(it) }
}
В результате:
ID
NAME
Process finished with exit code 0