Cara membuat konstruktor kosong untuk kelas data di Kotlin Android

195

Saya memiliki 10+ parameter dalam kelas data, saya ingin menginisialisasi kelas data dengan konstruktor kosong dan menetapkan nilai hanya untuk beberapa parameter menggunakan setter dan meneruskan objek ke 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<*, *>,
)

Pemakaian:

Sesuatu seperti ini akan mudah

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

Tapi itu membutuhkan semua argumen untuk diteruskan saat membuat konstruktor. Bagaimana saya bisa menyederhanakan seperti di atas?

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

Jawaban:

245

Anda memiliki 2 opsi di sini:

  1. Tetapkan nilai default untuk setiap parameter konstruktor utama :

    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. Deklarasikan konstruktor sekunder yang tidak memiliki parameter:

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

Jika Anda tidak bergantung pada copyatau equalsdari Activitykelas atau tidak menggunakan data classmetode autogenerated sama sekali Anda bisa menggunakan kelas reguler seperti:

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

Tidak setiap DTO perlu menjadi data classdan sebaliknya. Bahkan dalam pengalaman saya, saya menemukan kelas data menjadi sangat berguna di bidang yang melibatkan beberapa logika bisnis yang kompleks.

miensol
sumber
1
Terima kasih @miensol, Apakah ada cara ini bisa dilakukan dengan menggunakan copy fun. misalnya. kotlinlang.org/docs/reference/data-classes.html#copying
Sai
@SaiKiran untuk menggunakan copyAnda membutuhkan instance kelas data. Untuk membuatnya, Anda perlu memanggil konstruktor - dan inilah masalahnya.
miensol
Saya menggunakan Kotlin 1.1.2 untuk Android Studio 2.3 dan blankList tidak tersedia: /
Gonzalo
Lupakan. Saya tidak menambahkan kotlin ke file konfigurasi build.gradle saya.
Gonzalo
3
@Muhammadchhota emptyListtidak akan berulang kali mengalokasikan memori. Ia mengembalikan singleton .
miensol
70

Jika Anda memberikan nilai default ke semua bidang - konstruktor kosong dihasilkan secara otomatis oleh Kotlin.

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

dan Anda cukup menelepon:

val user = User()
kosiara - Bartosz Kosarzycki
sumber
1
jika id dihasilkan otomatis lalu bagaimana cara menggunakannya?
Siddhpura Amit
Bekerja untukku. Untuk pesan Firebase Chat:class FeelComChatMessage (messageText: String = "", messageUser: String = "")
Jitendra Surve
14

Bersamaan dengan jawaban @miensol, izinkan saya menambahkan beberapa detail:

Jika Anda menginginkan konstruktor kosong yang terlihat-Java menggunakan kelas data, Anda perlu mendefinisikannya secara eksplisit.

Menggunakan nilai default + specifier konstruktor cukup mudah:

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

Ini berarti bahwa dengan trik ini Anda sekarang dapat membuat cerita bersambung / deserialize objek ini dengan serializers Java standar (Jackson, Gson dll).

Gui13
sumber
Perintah terakhir salah. Setidaknya untuk serializer Gson, sebenarnya, Gson menggunakan mekanisme tidak aman untuk membuat objek dan itu tidak akan memanggil konstruktor Anda. Saya baru saja menjawab pertanyaan terkait di sini stackoverflow.com/questions/59390294/...
Võ Quang Hòa
6

Jika Anda memberikan nilai default ke setiap parameter konstruktor utama:

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

dan dari kelas di mana instance Anda dapat menyebutnya tanpa argumen atau dengan argumen yang Anda miliki saat itu

var newItem = Item()

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

Saya sarankan untuk memodifikasi konstruktor utama dan menambahkan nilai default ke setiap parameter:

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

Anda juga dapat membuat nilai nullable dengan menambahkan ?dan kemudian Anda dapat mengasumsikan 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
)

Secara umum, ini adalah praktik yang baik untuk menghindari objek yang tidak dapat dibatalkan - tulis kode sedemikian rupa sehingga kita tidak perlu menggunakannya. Objek yang tidak dapat dibatalkan adalah salah satu kelebihan Kotlin dibandingkan dengan Jawa. Oleh karena itu, opsi pertama di atas lebih disukai .

Kedua opsi akan memberi Anda hasil yang diinginkan:

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

Konstruktor sekunder tidak kosong untuk kelas data di 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)

Kosong konstruktor sekunder untuk kelas data di 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)
Andy Fedoroff
sumber
2

Dari dokumentasi

CATATAN: Pada JVM, jika semua parameter konstruktor utama memiliki nilai default, kompiler akan menghasilkan konstruktor tanpa parameter tambahan yang akan menggunakan nilai default. Ini membuatnya lebih mudah untuk menggunakan Kotlin dengan perpustakaan seperti Jackson atau JPA yang membuat instance kelas melalui konstruktor tanpa parameter.

Gastón Saillén
sumber