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

Класс данных:

data class Activity(
    var updated_on: String,
    var tags: List,
    var description: String,
    var user_id: List,
    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)

Но класс данных требует, чтобы все аргументы были переданы при создании конструктора. Как мы можем упростить это, как конструктор класса Java POJO?

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

Sai

Ответов: 8

Ответы (8)

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

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

    класс данных Activity (
        var updated_on: String = "",
        теги var: List  = emptyList (),
        var description: String = "",
        var user_id: List  = emptyList (),
        var status_id: Int = -1,
        var title: String = "",
        var created_at: String = "",
        var data: HashMap <*, *> = hashMapOf  (),
        var id: Int = -1,
        var counts: LinkedTreeMap <*, *> = LinkedTreeMap  ()
    )
    
  2. Объявить вторичный конструктор без параметров:

    класс данных Activity (
        var updated_on: строка,
        теги var: список ,
        описание var: строка,
        var user_id: Список ,
        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 <Любой, Любой> (),
                             -1, LinkedTreeMap <Любой, Любой> ()
                             )
    }
    

Если вы не полагаетесь на copy или , равно класса Activity или не используйте автоматически сгенерированный класс данныхметоды, вы можете использовать обычный класс, например:

class ActivityDto {
    var updated_on: String = "",
    var tags: List = emptyList(),
    var description: String = "",
    var user_id: List = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap()
}

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

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

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

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

val user = User()

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

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 = emptyList(),
            var idSeller: String = "")

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

var newItem = Item()

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

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

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

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

data class Activity(
    var updated_on: String = "",
    var tags: List = emptyList(),
    var description: String = "",
    var user_id: List = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap()
) {
    constructor() : this(title = "") // this constructor is an explicit
                                     // "empty" constructor, as seen by Java.
}

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

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

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

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

data class Activity(
    var updated_on: String = "",
    var tags: List = emptyList(),
    var description: String = "",
    var user_id: List = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap()
)

Вы также можете сделать значения обнуляемыми, добавив ?, а затем вы можете присвоить null:

data class Activity(
    var updated_on: String? = null,
    var tags: List? = null,
    var description: String? = null,
    var user_id: List? = 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
)

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

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

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

Непустой вторичный конструктор для класса данных в 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)

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

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)

современный ответ на этот вопрос должен заключаться в использовании плагина компилятора Kotlin no-arg, который создает код конструкции без аргументов для классических apies подробнее здесь

просто вам нужно добавить путь к классу плагина на уровне проекта build.gradle

    dependencies {
    ....

    classpath "org.jetbrains.kotlin:kotlin-noarg:1.4.10"

    ....
    }

затем настройте аннотацию для создания no-arg конструктора

apply plugin: "kotlin-noarg"

noArg {
      annotation("your.path.to.annotaion.NoArg")
      invokeInitializers = true
}

затем определите свой файл аннотации NoArg.kt

 @Target(AnnotationTarget.CLASS)
 @Retention(AnnotationRetention.SOURCE)
 annotation class NoArg

наконец, в любом классе данных вы можете просто использовать свою аннотацию

@NoArg
data class SomeClass( val datafield:Type , ...   )

Я использовал для создания своего собственного no-arg конструктора в качестве принятого ответа, который я получил при поиске, но затем этот плагин был выпущен или что-то в этом роде, и я нашел его более чистым.

2022 WebDevInsider