Come creare un costruttore vuoto per la classe di dati in Kotlin Android


195

Ho 10+ parametri in una classe di dati, voglio inizializzare la classe di dati con un costruttore vuoto e impostare i valori solo per alcuni parametri utilizzando setter e passare l'oggetto al server.

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<*, *>,
)

Uso:

Qualcosa del genere sarà facile

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

Ma richiede che tutti gli argomenti vengano passati durante la creazione del costruttore. Come posso semplificare come sopra?

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

Risposte:


246

Hai 2 opzioni qui:

  1. Assegna un valore predefinito a ciascun parametro del costruttore principale :

    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. Dichiarare un costruttore secondario che non ha parametri:

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

Se non fai affidamento su copyo equalsdella Activityclasse o non usi affatto i data classmetodi generati automaticamente , puoi usare la classe normale in questo modo:

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

Non tutti i DTO devono essere a data classe viceversa. In effetti, nella mia esperienza, trovo che le classi di dati siano particolarmente utili in settori che implicano una complessa logica aziendale.


1
Grazie @miensol, c'è un modo per farlo usando il divertimento della copia. per esempio. kotlinlang.org/docs/reference/data-classes.html#copying
Sai

@SaiKiran per utilizzare copyè necessaria un'istanza della classe di dati. Per crearlo devi invocare un costruttore - ed ecco il problema.
Miensol,

Sto usando Kotlin 1.1.2 per Android Studio 2.3 e emptyList non è disponibile: /
Gonzalo

Non importa. Non ho aggiunto kotlin al mio file di configurazione build.gradle.
Gonzalo,

3
@Muhammadchhota emptyListnon allocherà ripetutamente la memoria. Restituisce un singleton .
miensol,

70

Se dai valori predefiniti a tutti i campi, Kotlin genera automaticamente un costruttore vuoto.

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

e puoi semplicemente chiamare:

val user = User()

1
se l'id viene generato automaticamente, come si usa?
Siddhpura dal

Ha funzionato per me. Per il messaggio Chat di Firebase:class FeelComChatMessage (messageText: String = "", messageUser: String = "")
Jitendra Surve

14

Insieme alla risposta di @miensol, vorrei aggiungere alcuni dettagli:

Se si desidera un costruttore vuoto visibile Java che utilizza le classi di dati, è necessario definirlo esplicitamente.

L'uso di valori predefiniti + identificatore costruttore è abbastanza semplice:

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

Ciò significa che con questo trucco è ora possibile serializzare / deserializzare questo oggetto con i serializzatori Java standard (Jackson, Gson ecc.).


L'ultimo encomio è sbagliato. Almeno per il serializzatore Gson, infatti, Gson utilizza il meccanismo non sicuro per creare oggetti e non chiamerà il costruttore. Ho appena risposto a una domanda correlata qui stackoverflow.com/questions/59390294/…
Võ Quang Hòa

6

Se dai un valore predefinito a ciascun parametro del costruttore principale:

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 = "")

e dalla classe in cui le istanze puoi chiamarlo senza argomenti o con gli argomenti che hai in quel momento

var newItem = Item()

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

3

Suggerirei di modificare il costruttore principale e aggiungere un valore predefinito a ciascun parametro:

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

È inoltre possibile rendere i valori nulla annullabili aggiungendo ?e quindi si può valutare 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
)

In generale, è buona norma evitare oggetti nullable: scrivere il codice nel modo in cui non è necessario utilizzarli. Gli oggetti non annullabili sono uno dei vantaggi di Kotlin rispetto a Java. Pertanto, la prima opzione sopra è preferibile .

Entrambe le opzioni ti daranno il risultato desiderato:

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

2

Costruttore secondario non vuoto per la classe di dati in 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)

Costruttore secondario vuoto per la classe di dati in 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

Dalla documentazione

NOTA: sulla JVM, se tutti i parametri del costruttore principale hanno valori predefiniti, il compilatore genererà un costruttore senza parametri aggiuntivo che utilizzerà i valori predefiniti. Ciò semplifica l'utilizzo di Kotlin con librerie come Jackson o JPA che creano istanze di classe tramite costruttori senza parametri.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.