Преобразование статических переменных из 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, и код Котлина могли получить доступ ко всему в Foo)?
4 ответа
Нынешняя семантика исходит от кандидата в бета-версии Kotlin:
@JvmField и объекты
Мы разработали стратегию генерации чистых полей (в отличие от
get
/set
пары) более предсказуемо: теперь только свойства, помеченные как@JvmField
,lateinit
или жеconst
выставляются как поля для клиентов Java. В более старых версиях использовалась эвристика и создавались статические поля в объектах безоговорочно, что противоречит нашей первоначальной цели разработки иметь API-интерфейсы, совместимые с бинарной совместимостью, по умолчанию.Кроме того, единичные экземпляры теперь доступны по имени
INSTANCE
(вместоINSTANCE$
).
В соответствии с этим и ссылкой, есть три способа работы со свойствами Kotlin object
с Java:
использование
Foo.INSTANCE
,По умолчанию свойства
object
не будет статическими полями для Java, но Java может получить доступ к свойствам черезFoo
экземпляр объекта -Foo.INSTANCE
,Так что выражение будет
Foo.INSTANCE.getC_ID()
,Пометьте недвижимость с помощью
@JvmStatic
аннотация:object Foo { @JvmStatic val C_ID = "ID" //... }
Это сгенерирует статический геттер для
C_ID
вместоFoo
Получение экземпляра, который будет доступен какFoo.getC_ID()
,использование
@JvmField
аннотация на декларацию собственности:object Foo { @JvmField val C_ID = "ID" //... }
Это заставит компилятор Kotlin генерировать статическое поле для Java вместо свойства. Затем в Java вы можете получить к нему доступ в виде статического поля:
Foo.C_ID
,Но это не будет работать со свойствами без поддержки полей, таких как
all
в вашем примере.
Для примитивов, как вы сказали, можно использовать const
который будет иметь тот же эффект, что и @JvmField
с точки зрения видимости в Java.
Кстати, когда дело доходит до методов, ситуация такая же, и есть @JvmStatic
аннотация для них.
В вашем классе 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.
Вы должны быть в состоянии получить доступ к значениям "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 только для констант.
создайте файл 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)
}
в своей основной деятельности вы можете получить доступ к константам по имени константы, и 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)
}
}
}
Мне удалось получить вывод журнала успешно