Як створити порожній конструктор для класу даних в 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)

Відповіді:


245

Тут у вас є два варіанти:

  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і навпаки. Насправді в моєму досвіді я вважаю, що класи даних є особливо корисними в областях, що передбачають складну бізнес-логіку.


1
Дякую @miensol, чи є це, як це зробити, використовуючи копію веселощів. напр. kotlinlang.org/docs/reference/data-classes.html#copying
Сай

@SaiKiran для використання copyпотрібен екземпляр класу даних. Щоб його створити, потрібно викликати конструктор - і ось в чому виникла проблема.
miensol

Я використовую Kotlin 1.1.2 для Android Studio 2.3, а emptyList недоступний: /
Gonzalo

Не звертай уваги. Я не додав kotlin до конфігураційного файлу build.gradle.
Гонсало

3
@Muhammadchhota emptyListне раз виділятиме пам’ять. Він повертає сингл .
miensol

70

Якщо ви задаєте значення за замовчуванням для всіх полів - Котлін автоматично генерує порожній конструктор.

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

і ви можете просто зателефонувати:

val user = User()

1
якщо ідентифікатор автоматично генерується, то як це використовувати?
Сіддхпура Аміт

Працювали для мене. Для Firebase Chat повідомлення: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 (Jackson, Gson тощо).


Остання похвала помилкова. Принаймні, для серіалізатора 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
)

Взагалі, це хороша практика уникати змінних об'єктів - записуйте код так, як нам не потрібно їх використовувати. Незмінні об'єкти - одна з переваг Котліна порівняно з Java. Тому перший варіант є кращим .

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

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

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, які створюють екземпляри класу через конструктори без параметрів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.