Cách tạo hàm tạo trống cho lớp dữ liệu trong Kotlin Android


190

Tôi có hơn 10 tham số trong một lớp dữ liệu, tôi muốn khởi tạo lớp dữ liệu với một hàm tạo trống và chỉ đặt các giá trị cho một vài tham số bằng cách sử dụng setter và truyền đối tượng đến máy chủ.

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

Sử dụng:

Một cái gì đó như thế này sẽ dễ dàng

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

Nhưng nó đòi hỏi tất cả các đối số được thông qua trong khi tạo hàm tạo. Làm thế nào tôi có thể đơn giản hóa như trên?

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

Câu trả lời:


240

Bạn có 2 lựa chọn ở đây:

  1. Gán một giá trị mặc định cho từng tham số hàm tạo chính :

    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. Khai báo một hàm tạo thứ cấp không có tham số:

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

Nếu bạn không dựa vào copyhoặc equalscủa Activitylớp hoặc không sử dụng các data classphương thức được tạo tự động, bạn hoàn toàn có thể sử dụng lớp thông thường như vậy:

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

Không phải mọi DTO cần phải là một data classvà ngược lại. Trong thực tế theo kinh nghiệm của tôi, tôi thấy các lớp dữ liệu đặc biệt hữu ích trong các lĩnh vực liên quan đến một số logic kinh doanh phức tạp.


1
Cảm ơn @miensol, Có cách nào có thể được thực hiện bằng cách sử dụng bản sao vui vẻ không. ví dụ. kotlinlang.org/docs/reference/data-groupes.html#copying
Sai

@SaiKiran để sử dụng copybạn cần một cá thể lớp dữ liệu. Để tạo nó, bạn cần phải gọi một hàm tạo - và đây là vấn đề.
miensol

Tôi đang sử dụng Kotlin 1.1.2 cho Android Studio 2.3 và blankList không khả dụng: /
Gonzalo

Đừng bận tâm. Tôi đã không thêm kotlin vào tập tin cấu hình build.gradle của mình.
Gonzalo

3
@Muhammadchhota emptyListsẽ không phân bổ bộ nhớ nhiều lần. Nó trả về một singleton .
miensol

69

Nếu bạn cung cấp các giá trị mặc định cho tất cả các trường - hàm tạo rỗng được tạo tự động bởi Kotlin.

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

và bạn chỉ cần gọi:

val user = User()

Nếu id được tạo tự động thì sử dụng như thế nào?
Siddhpura Amit

Đã làm cho tôi. Đối với tin nhắn trò chuyện Firebase:class FeelComChatMessage (messageText: String = "", messageUser: String = "")
Jitendra Survey

13

Cùng với câu trả lời @miensol, hãy để tôi thêm một số chi tiết:

Nếu bạn muốn một hàm tạo trống có thể nhìn thấy Java bằng các lớp dữ liệu, bạn cần xác định rõ ràng nó.

Sử dụng các giá trị mặc định + trình xác định hàm tạo khá dễ dàng:

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

Điều này có nghĩa là với thủ thuật này, giờ đây bạn có thể tuần tự hóa / giải tuần tự hóa đối tượng này bằng các trình tuần tự hóa Java tiêu chuẩn (Jackson, Gson, v.v.).


Lời khen cuối cùng là sai. Ít nhất là đối với bộ nối tiếp Gson, trên thực tế, Gson sử dụng cơ chế không an toàn để tạo các đối tượng và nó sẽ không gọi hàm tạo của bạn. Tôi vừa trả lời một câu hỏi liên quan ở đây stackoverflow.com/questions/59390294/ Khắc
Võ Quang Hòa

6

Nếu bạn đưa ra một giá trị mặc định cho từng tham số hàm tạo chính:

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

và từ lớp nơi các trường hợp bạn có thể gọi nó mà không có đối số hoặc với các đối số mà bạn có thời điểm đó

var newItem = Item()

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

3

Tôi đề nghị sửa đổi hàm tạo chính và thêm một giá trị mặc định cho mỗi tham số:

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

Bạn cũng có thể làm cho các giá trị trở nên vô giá trị bằng cách thêm ?và sau đó bạn có thể khẳng định 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
)

Nói chung, nên tránh các đối tượng không thể thực hiện được - viết mã theo cách mà chúng ta không cần sử dụng chúng. Các đối tượng không nullable là một trong những lợi thế của Kotlin so với Java. Do đó, lựa chọn đầu tiên ở trên là thích hợp hơn .

Cả hai tùy chọn sẽ cung cấp cho bạn kết quả mong muốn:

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

2

Hàm tạo thứ cấp không trống cho lớp dữ liệu trong 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)

Hàm tạo thứ cấp trống cho lớp dữ liệu trong 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

Từ tài liệu

LƯU Ý: Trên JVM, nếu tất cả các tham số của hàm tạo chính có các giá trị mặc định, trình biên dịch sẽ tạo ra một hàm tạo không tham số bổ sung sẽ sử dụng các giá trị mặc định. Điều này giúp sử dụng Kotlin dễ dàng hơn với các thư viện như Jackson hoặc JPA tạo các thể hiện lớp thông qua các hàm tạo không tham số.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.