web-dev-qa-db-fra.com

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 d'origine:

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

Problème:

La classe de barres ne peut plus accéder à C_ID ou à VALUES (erreur: "accès privé")

si je mets "const" devant C_ID, ça marche ... mais je ne peux pas faire la même chose avec VALUES ("const" ne peut être utilisé que sur des primatives ou des chaînes)

Y a-t-il une manière différente de faire cela (pour que le code Java et le code Kotlin puissent accéder à tout dans Foo)?

22
Jeff Campbell

La sémantique actuelle provient de Kotlin Beta Candidate :

@JvmField et objets

Nous avons rendu plus prévisible la stratégie de génération de champs purs (par opposition aux paires get/set): désormais, seules les propriétés annotées avec @JvmField, lateinit ou const sont exposées en tant que champs aux clients Java. Les versions plus anciennes utilisaient des méthodes heuristiques et créaient des champs statiques dans des objets sans condition, ce qui va à l'encontre de notre objectif de conception initial consistant à avoir par défaut des API conviviales compatibles avec la compatibilité binaire.

De plus, les instances singleton sont désormais accessibles sous le nom INSTANCE (au lieu de INSTANCE$).

Selon cela et la référence , il existe trois manières de travailler avec les propriétés d'un Kotlin object de Java:

  • Utilisez Foo.INSTANCE.

    Par défaut, les propriétés de object ne seront pas des champs statiques pour Java, mais Java peut accéder aux propriétés par le biais de Foo instance_objet - Foo.INSTANCE.

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

  • Marquer une propriété avec l'annotation @JvmStatic:

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

    Cela générera un getter statique pour C_ID au lieu de Foo instance getter qui sera accessible en tant que Foo.getC_ID().

  • Utilisez l'annotation @JvmField sur la déclaration de propriété:

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

    Cela fera que le compilateur Kotlin génère un champ statique pour Java au lieu de la propriété . En Java, vous pouvez y accéder en tant que champ statique: Foo.C_ID.

    Mais cela ne fonctionnera pas sur les propriétés sans sauvegarder les champs tels que all dans votre exemple.

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

À propos, en ce qui concerne les méthodes, la situation est la même et il existe une annotation @JvmStatic pour elles.

34
hotkey

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

Ensuite, vous pouvez appeler Foo.getAll () et Foo.C_ID, Foo.C_NAME et Foo.VALUES.

7

Vous devriez pouvoir accéder aux valeurs "de la manière 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) }
}

Avec comme résultat:

ID
NAME

Process finished with exit code 0
1
Ron

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

créez le fichier Constants.kt et collez le 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 que le studio Android importera automatiquement. 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 pu obtenir la sortie du journal avec succès 

 logcat output

0
sudesh