Преобразование статических переменных из 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)
        }
    }
}

Мне удалось получить вывод журнала успешно

выход logcat

Другие вопросы по тегам