Comment créer un constructeur vide pour la classe de données dans Kotlin Android


195

J'ai plus de 10 paramètres dans une classe de données, je veux initialiser la classe de données avec un constructeur vide et définir les valeurs uniquement pour quelques paramètres à l'aide de setter et transmettre l'objet au serveur.

data class Activity(
        var updated_on: String,
        var tags: List<String>,
        var description: String,
        var user_id: List<Int>,
        var status_id: Int,
        var title: String,
        var created_at: String,
        var data: HashMap<*, *>,
        var id: Int,
        var counts: LinkedTreeMap<*, *>,
)

Usage:

Quelque chose comme ça sera facile

                val activity =  Activity();
                activity.title = "New Computer"
                sendToServer(activity)

Mais cela nécessite que tous les arguments soient passés lors de la création du constructeur. Comment puis-je simplifier comme ci-dessus?

                val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null);
                sendToServer(activity)

Réponses:


246

Vous avez 2 options ici:

  1. Attribuez une valeur par défaut à chaque paramètre du constructeur principal :

    data class Activity(
        var updated_on: String = "",
        var tags: List<String> = emptyList(),
        var description: String = "",
        var user_id: List<Int> = emptyList(),
        var status_id: Int = -1,
        var title: String = "",
        var created_at: String = "",
        var data: HashMap<*, *> = hashMapOf<Any, Any>(),
        var id: Int = -1,
        var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
    ) 
  2. Déclarez un constructeur secondaire qui n'a pas de paramètres:

    data class Activity(
        var updated_on: String,
        var tags: List<String>,
        var description: String,
        var user_id: List<Int>,
        var status_id: Int,
        var title: String,
        var created_at: String,
        var data: HashMap<*, *>,
        var id: Int,
        var counts: LinkedTreeMap<*, *>
    ) {
        constructor() : this("", emptyList(), 
                             "", emptyList(), -1, 
                             "", "", hashMapOf<Any, Any>(), 
                             -1, LinkedTreeMap<Any, Any>()
                             )
    }

Si vous ne comptez pas sur copyou equalsde la Activityclasse ou n'utilisez pas du tout les data classméthodes générées automatiquement , vous pouvez utiliser une classe régulière comme ceci:

class ActivityDto {
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
}

Tous les DTO n'ont pas besoin d'être un data classet vice versa. En fait, d'après mon expérience, je trouve que les classes de données sont particulièrement utiles dans les domaines qui impliquent une logique métier complexe.


1
Merci @miensol, y a-t-il un moyen de le faire en utilisant le plaisir de la copie. par exemple. kotlinlang.org/docs/reference/data-classes.html#copying
Sai

@SaiKiran pour l'utiliser, copyvous avez besoin d'une instance de classe de données. Pour le créer, vous devez appeler un constructeur - et voici le problème.
miensol

J'utilise Kotlin 1.1.2 pour Android Studio 2.3 et emptyList n'est pas disponible: /
Gonzalo

Ça ne fait rien. Je n'ai pas ajouté kotlin à mon fichier de configuration build.gradle.
Gonzalo

3
@Muhammadchhota n'allouera emptyListpas de mémoire à plusieurs reprises. Il renvoie un singleton .
miensol

71

Si vous donnez des valeurs par défaut à tous les champs - un constructeur vide est généré automatiquement par Kotlin.

data class User(var id: Long = -1,
                var uniqueIdentifier: String? = null)

et vous pouvez simplement appeler:

val user = User()

1
si l'ID est généré automatiquement, comment l'utiliser?
Siddhpura Amit

A travaillé pour moi. Pour le message Firebase Chat:class FeelComChatMessage (messageText: String = "", messageUser: String = "")
Jitendra Surve

14

En plus de la réponse @miensol, permettez-moi d'ajouter quelques détails:

Si vous voulez un constructeur vide visible par Java utilisant des classes de données, vous devez le définir explicitement.

L'utilisation des valeurs par défaut + spécificateur de constructeur est assez simple:

data class Activity(
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
) {
    constructor() : this(title = "") // this constructor is an explicit
                                     // "empty" constructor, as seen by Java.
}

Cela signifie qu'avec cette astuce, vous pouvez maintenant sérialiser / désérialiser cet objet avec les sérialiseurs Java standard (Jackson, Gson, etc.).


Le dernier éloge est faux. Au moins pour le sérialiseur Gson, en fait, Gson utilise le mécanisme unsafe pour créer des objets et il n'appellera pas votre constructeur. Je viens de répondre à une question connexe ici stackoverflow.com/questions/59390294/…
Võ Quang Hòa

6

Si vous donnez une valeur par défaut à chaque paramètre du constructeur principal:

data class Item(var id: String = "",
            var title: String = "",
            var condition: String = "",
            var price: String = "",
            var categoryId: String = "",
            var make: String = "",
            var model: String = "",
            var year: String = "",
            var bodyStyle: String = "",
            var detail: String = "",
            var latitude: Double = 0.0,
            var longitude: Double = 0.0,
            var listImages: List<String> = emptyList(),
            var idSeller: String = "")

et de la classe où les instances vous pouvez l'appeler sans arguments ou avec les arguments que vous avez à ce moment

var newItem = Item()

var newItem2 = Item(title = "exampleTitle",
            condition = "exampleCondition",
            price = "examplePrice",
            categoryId = "exampleCategoryId")

3

Je suggère de modifier le constructeur principal et d'ajouter une valeur par défaut à chaque paramètre:

data class Activity(
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
)

Vous pouvez également rendre les valeurs nulles en ajoutant ?, puis vous pouvez assing null:

data class Activity(
    var updated_on: String? = null,
    var tags: List<String>? = null,
    var description: String? = null,
    var user_id: List<Int>? = null,
    var status_id: Int? = null,
    var title: String? = null,
    var created_at: String? = null,
    var data: HashMap<*, *>? = null,
    var id: Int? = null,
    var counts: LinkedTreeMap<*, *>? = null
)

En général, il est recommandé d'éviter les objets Nullable - écrivez le code de la manière dont nous n'avons pas besoin de les utiliser. Les objets non nullables sont l'un des avantages de Kotlin par rapport à Java. Par conséquent, la première option ci-dessus est préférable .

Les deux options vous donneront le résultat souhaité:

val activity = Activity()
activity.title = "New Computer"
sendToServer(activity)

2

Constructeur secondaire non vide pour la classe de données dans Kotlin:

data class ChemicalElement(var name: String,
                           var symbol: String,
                           var atomicNumber: Int,
                           var atomicWeight: Double,
                           var nobleMetal: Boolean?) {

    constructor(): this("Silver",
                        "Ag", 
                        47,
                        107.8682,
                        true)
}

fun main() {
    var chemicalElement = ChemicalElement()
    println("RESULT: ${chemicalElement.symbol} means ${chemicalElement.name}")
    println(chemicalElement)
}

// RESULT: Ag means Silver
// ChemicalElement(name=Silver, symbol=Ag, atomicNumber=47, atomicWeight=107.8682, nobleMetal=true)

Constructeur secondaire vide pour la classe de données dans Kotlin:

data class ChemicalElement(var name: String,
                           var symbol: String,
                           var atomicNumber: Int,
                           var atomicWeight: Double,
                           var nobleMetal: Boolean?) {

    constructor(): this("",
                        "", 
                        -1,
                        0.0,
                        null)
}

fun main() {
    var chemicalElement = ChemicalElement()
    println(chemicalElement)
}

// ChemicalElement(name=, symbol=, atomicNumber=-1, atomicWeight=0.0, nobleMetal=null)

2

De la documentation

REMARQUE: Sur la JVM, si tous les paramètres du constructeur principal ont des valeurs par défaut, le compilateur générera un constructeur sans paramètre supplémentaire qui utilisera les valeurs par défaut. Cela facilite l'utilisation de Kotlin avec des bibliothèques telles que Jackson ou JPA qui créent des instances de classe via des constructeurs sans paramètre.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.