Convertir des variables statiques de Java en Kotlin

j'essaie de convertir le code suivant en Kotlin et j'ai toujours l'une des classes (Foo) utilisées par Java. Quelle est la bonne façon de faire cette conversion?

Java Original:

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();
    }
}

conversion Automatique fo Foo de 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)
}

Problème:

la classe Bar ne peut plus accéder à C_ID ou à des valeurs (erreur: "private access")

si je mets "const" devant C_ID, ça marche... mais je ne peux pas faire la même chose avec les valeurs ("const" peut Ne doit être utilisé que sur les primatifs ou String)

y a-t-il une autre façon de faire cela (pour que le code Java et le code Kotlin puissent accéder à tout dans Foo)?

21
demandé sur hotkey 2016-01-31 22:41:46

4 réponses

la sémantique actuelle vient de Kotlin Bêta Candidat:

@JvmField et objets

nous avons fait la stratégie pour générer des champs purs (par opposition à get/set paires) plus prévisible: désormais seules les propriétés annotées comme @JvmField,lateinit ou const sont exposés comme champs aux clients Java. Les versions plus anciennes utilisaient l'heuristique et créaient des champs statiques dans les objets inconditionnellement, ce qui est contre notre initiale objectif de conception d'avoir des API compatibles binaires par défaut.

de plus, les instances singleton sont maintenant accessibles par le nom INSTANCE (au lieu de INSTANCE$).

selon ceci et le référence, il y a trois façons de travailler avec les propriétés d'un Kotlin object à partir de Java:

  • Utiliser Foo.INSTANCE.

    Par défaut, les propriétés de object ne seront pas des champs statiques pour Java, mais Java pouvez accéder aux propriétés par Foo instance de l'objet -- Foo.INSTANCE.

    Donc l'expression Foo.INSTANCE.getC_ID().

  • Marquer une propriété avec @JvmStatic note:

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

    cela générera des getter statiques pour C_ID au lieu de Foo instance getter qui sera accessible comme Foo.getC_ID().

  • Utiliser @JvmField annotation sur la déclaration de la propriété:

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

    Cela va faire Kotlin compiler génère un champ statique pour Java au lieu de propriété. Puis, en Java, vous pouvez y accéder comme un champ statique: Foo.C_ID.

    mais il ne fonctionnera pas sur les propriétés sans les champs de soutien comme all dans ton exemple.

Pour les primitives, comme vous l'avez dit, on peut utiliser const qui aura le même effet que @JvmField en termes de visibilité en Java.

Par le chemin, quand il s'agit de méthodes, la situation est la même, et il est @JvmStatic annotation pour eux.

32
répondu hotkey 2017-05-03 14:44:46

dans votre classe foo vous pouvez placer ces propriétés et la méthode dans un objet compagnon:

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)
     }
  }
}

alors vous pouvez appeler Foo.getAll (), and Foo.C_ID, Foo.C_NAME et Foo.VALEUR.

6
répondu Felipe R. Saruhashi 2017-05-31 01:12:01

Vous devriez être en mesure d'accéder aux valeurs "de la kotlin chemin":

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) }
}

Avec comme résultat:

ID
NAME

Process finished with exit code 0
1
répondu Ron 2016-01-31 20:18:41

c'est mieux si vous créez un nouveau fichier kotlin juste pour les constantes.

créer Constantes.kt fichier et collez code ci-dessous.

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)
}

dans votre activité principale, vous pouvez accéder aux constantes par le nom de la constante le studio android importera automatiquement les constantes. voici mon activité principale:

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)
        }
    }
}

j'ai réussi à obtenir la sortie log avec succès

logcat output

0
répondu sudesh 2018-07-08 13:28:07