简体   繁体   English

如何在 Kotlin Android 中为数据类创建空构造函数

[英]How to create empty constructor for data class in Kotlin Android

I have 10+ variables declared in Kotlin data class, and I would like to create an empty constructor for it like how we typically do in Java.我在 Kotlin 数据类中声明了 10 多个变量,我想为它创建一个空的构造函数,就像我们通常在 Java 中所做的那样。

Data class:数据类:

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

Expected usage:预期用途:

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

But the data class requires all arguments to be passed while creating a constructor.但是数据类要求在创建构造函数时传递所有参数。 How can we simplify this like the Java POJO class constructor?我们如何像 Java POJO 类构造函数一样简化它?

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

You have 2 options here:您在这里有 2 个选择:

  1. Assign a default value to eachprimary constructor 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>() )
  2. Declare a secondary constructor that has no parameters:声明一个没有参数的二级构造函数:

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

If you don't rely on copy or equals of the Activity class or don't use the autogenerated data class methods at all you could use regular class like so:如果您不依赖Activity类的copyequals ,或者根本不使用自动生成的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>()
}

Not every DTO needs to be a data class and vice versa.并非每个DTO 都需要是data class ,反之亦然。 In fact in my experience I find data classes to be particularly useful in areas that involve some complex business logic.事实上,根据我的经验,我发现数据类在涉及一些复杂业务逻辑的领域特别有用。

If you give default values to all the fields - empty constructor is generated automatically by Kotlin.如果您为所有字段提供默认值- Kotlin 会自动生成空构造函数。

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

and you can simply call:你可以简单地调用:

val user = User()

Along with @miensol answer, let me add some details:随着@miensol 的回答,让我补充一些细节:

If you want a Java-visible empty constructor using data classes, you need to define it explicitely.如果您想要使用数据类的 Java 可见的空构造函数,则需要明确定义它。

Using default values + constructor specifier is quite easy:使用默认值 + 构造函数说明符非常简单:

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

This means that with this trick you can now serialize/deserialize this object with the standard Java serializers (Jackson, Gson etc).这意味着通过这个技巧,您现在可以使用标准 Java 序列化程序(Jackson、Gson 等)序列化/反序列化这个对象。

the modern answer for this should be using Kotlin's no-arg compiler plugin which creates a non argument construct code for classic apies more about here对此的现代答案应该是使用 Kotlin 的no-arg compiler plugin ,它为经典猿创建了一个非参数构造代码,更多关于这里

simply you have to add the plugin class path in build.gradle project level只需在 build.gradle 项目级别添加插件类路径

    dependencies {
    ....

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

    ....
    }

then configure your annotation to generate the no-arg constructor然后配置您的注释以生成no-arg构造函数

apply plugin: "kotlin-noarg"

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

then define your annotation file NoArg.kt然后定义您的注释文件NoArg.kt

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

finally in any data class you can simply use your own annotation最后在任何数据类中,您都可以简单地使用自己的注释

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

I used to create my own no-arg constructor as the accepted answer , which i got by search but then this plugin released or something and I found it way cleaner .我曾经创建我自己的no-arg构造函数作为接受的答案,这是我通过搜索得到的,但后来这个插件发布了,我发现它更干净了。

If you give a default value to each primary constructor parameter:如果为每个主构造函数参数提供默认值:

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

and from the class where the instances you can call it without arguments or with the arguments that you have that moment并且从您可以在不带参数的情况下调用它的实例的类中或使用您当时拥有的参数调用它

var newItem = Item()

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

From thedocumentation文档

NOTE: On the JVM, if all of the parameters of the primary constructor have default values, the compiler will generate an additional parameterless constructor which will use the default values.注意:在 JVM 上,如果主构造函数的所有参数都有默认值,编译器将生成一个额外的无参数构造函数,它将使用默认值。 This makes it easier to use Kotlin with libraries such as Jackson or JPA that create class instances through parameterless constructors.这使得将 Kotlin 与通过无参数构造函数创建类实例的库(例如 Jackson 或 JPA)一起使用变得更加容易。

I'd suggest to modify the primary constructor and add a default value to each 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>()
)

You can also make values nullable by adding ?您还可以通过添加? and then you can assing null :然后你可以赋值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
)

In general, it is a good practice to avoid nullable objects - write the code in the way that we don't need to use them.一般来说,避免可空对象是一个很好的做法——以我们不需要使用它们的方式编写代码。 Non-nullable objects are one of the advantages of Kotlin compared to Java.与 Java 相比,不可为空的对象是 Kotlin 的优势之一。 Therefore, the first option above is preferable .因此,上面的第一个选项是可取的

Both options will give you the desired result:这两个选项都会给你想要的结果:

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

Non-empty secondary constructor for data class in Kotlin: 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)

Empty secondary constructor for data class in Kotlin: 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM