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

我在Kotlin数据类中声明了10+变量,我想为它创建一个空构造函数,就像我们通常在Java中做的那样。

数据类:

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)

但是data类要求在创建构造函数时传递所有参数。我们如何像Java POJO类构造函数那样简化它?

val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null)
sendToServer(activity)
182114 次浏览

你有两个选择:

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

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,反之亦然。事实上,根据我的经验,我发现数据类在涉及一些复杂业务逻辑的领域特别有用。

除了@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等)序列化/反序列化这个对象。

如果你给所有字段的默认值 -空构造函数自动生成由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<String> = emptyList(),
var idSeller: String = "")

从课堂上的实例中你可以不带参数地调用它或者用你当时的参数

var newItem = Item()


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

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)

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)

我建议修改主构造函数,并在每个形参中添加默认值:

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相比,非空对象是Kotlin的优点之一。因此,上面的第一个选项更可取

这两种选择都会给你想要的结果:

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

文档

注意:在JVM上,如果主构造函数的所有参数 有默认值,编译器会生成一个额外的 将使用默认值的无参数构造函数。这 使Kotlin更容易与Jackson或JPA等库一起使用 通过无参数构造函数创建类实例

这个问题的现代答案应该是使用Kotlin的no-arg compiler plugin,它为经典的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构造函数作为接受的答案,这是我通过搜索得到的,但后来这个插件发布了什么的,我发现它更干净。