Как создать пустой конструктор для класса данных в Android Kotlin

195

У меня есть 10+ параметр в классе данных, я хочу инициализировать класс данных с помощью пустого конструктора и установить значения только для нескольких параметров с помощью установщика и передать объект на сервер.

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

Использование:

Как то так будет легко

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

Но он требует передачи всех аргументов при создании конструктора. Как я могу упростить как выше?

                val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null);
                sendToServer(activity)
Sai
источник

Ответы:

246

У вас есть 2 варианта здесь:

  1. Назначьте значение по умолчанию для каждого параметра основного конструктора :

    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. Объявите вторичный конструктор, который не имеет параметров:

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

Если вы не полагаться на copyили equalsв Activityклассе или не использовать автогенерируемые data classметоды на все , что вы могли бы использовать обычный класс следующим образом:

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

Не каждый DTO должен быть data classи наоборот. На самом деле, по своему опыту, я считаю, что классы данных особенно полезны в областях, которые включают некоторую сложную бизнес-логику.

miensol
источник
1
Спасибо @miensol, есть ли способ сделать это, используя копирование удовольствия. например. kotlinlang.org/docs/reference/data-classes.html#copying
Саи
@SaiKiran для использования copyвам нужен экземпляр класса данных. Чтобы создать его, вам нужно вызвать конструктор - и здесь была проблема.
miensol
Я использую Kotlin 1.1.2 для Android Studio 2.3, и emptyList недоступен: /
Гонсало
Неважно. Я не добавил kotlin в мой конфигурационный файл build.gradle.
Гонсало
3
@Muhammadchhota emptyListне будет повторно выделять память. Возвращает синглтон .
miensol
71

Если вы задаете значения по умолчанию для всех полей - Kotlin автоматически генерирует пустой конструктор.

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

и вы можете просто позвонить:

val user = User()
Косиара - Бартош Косаржицкий
источник
1
если идентификатор генерируется автоматически, то как использовать?
Сиддхпура Амит
Работал на меня. Для Firebase Чат сообщение:class FeelComChatMessage (messageText: String = "", messageUser: String = "")
Jitendra Surve
14

Наряду с ответом @miensol, позвольте мне добавить некоторые детали:

Если вам нужен Java-видимый пустой конструктор, использующий классы данных, вы должны определить его явно.

Использовать значения по умолчанию + спецификатор конструктора довольно просто:

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

Это означает, что с помощью этого трюка вы теперь можете сериализовать / десериализовать этот объект с помощью стандартных сериализаторов Java (Джексон, Гсон и т. Д.).

Gui13
источник
Последняя рекомендация неверна. По крайней мере, для сериализатора Gson, Gson использует небезопасный механизм для создания объектов, и он не будет вызывать ваш конструктор. Я только что ответил на связанный вопрос здесь stackoverflow.com/questions/59390294/…
Võ Quang Hòa
6

Если вы задаете значение по умолчанию для каждого параметра основного конструктора:

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

и из класса, где экземпляры вы можете вызвать его без аргументов или с аргументами, которые у вас есть в тот момент

var newItem = Item()

var newItem2 = Item(title = "exampleTitle",
            condition = "exampleCondition",
            price = "examplePrice",
            categoryId = "exampleCategoryId")
Йоши
источник
3

Я бы предложил изменить основной конструктор и добавить значение по умолчанию для каждого параметра:

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

Вы также можете сделать значения обнуляемыми, добавив, ?а затем вы можете задавать 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
)

Вообще, хорошей практикой является избегать объектов, которые могут быть обнуляемыми - пишите код так, чтобы нам не нужно было его использовать. Не допускающие обнуления объекты являются одним из преимуществ Kotlin по сравнению с Java. Поэтому первый вариант выше предпочтителен .

Оба варианта дадут вам желаемый результат:

val activity = Activity()
activity.title = "New Computer"
sendToServer(activity)
Micer
источник
2

Непустой вторичный конструктор для класса данных в Котлине:

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)

Пустой вторичный конструктор для класса данных в Котлине:

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

Из документации

ПРИМЕЧАНИЕ. Если в JVM все параметры первичного конструктора имеют значения по умолчанию, компилятор сгенерирует дополнительный конструктор без параметров, который будет использовать значения по умолчанию. Это облегчает использование Kotlin с такими библиотеками, как Jackson или JPA, которые создают экземпляры классов с помощью конструкторов без параметров.

Гастон Сайлен
источник