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

Sai*_*Sai 148 android kotlin

我在数据类中有10+参数,我想用空构造函数初始化数据类,并使用setter仅为少数参数设置值,并将对象传递给服务器.

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<*, *>,
)
Run Code Online (Sandbox Code Playgroud)

用法:

这样的事情很容易

                val activity =  Activity();
                activity.title = "New Computer"
                sendToServer(activity)
Run Code Online (Sandbox Code Playgroud)

但它需要在创建构造函数时传递所有参数.我怎样才能像上面这样简化?

                val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null);
                sendToServer(activity)
Run Code Online (Sandbox Code Playgroud)

mie*_*sol 195

这里有2个选项:

  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>()
    ) 
    
    Run Code Online (Sandbox Code Playgroud)
  2. 声明没有参数的辅助构造函数:

    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>()
                             )
    }
    
    Run Code Online (Sandbox Code Playgroud)

如果不依靠copyequals在的Activity阶级或不使用自动生成的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>()
}
Run Code Online (Sandbox Code Playgroud)

并非每个DTO都需要一个data class,反之亦然.事实上,根据我的经验,我发现数据类在涉及一些复杂业务逻辑的领域特别有用.

  • @Muhammadchhota` emptyList`不会重复分配内存.[它返回单例](https://github.com/JetBrains/kotlin/blob/1.1.3/libraries/stdlib/src/kotlin/collections/Collections.kt#L77). (3认同)

kos*_*cki 58

如果为所有字段赋予默认值 - 空构造函数由Kotlin自动生成.

data class User(var id: Long = -1,
                var uniqueIdentifier: String? = null)
Run Code Online (Sandbox Code Playgroud)

你可以简单地打电话:

val user = User()
Run Code Online (Sandbox Code Playgroud)


mxm*_*xml 16

对此的现代答案应该是使用 Kotlin 的no-arg compiler plugin,它为经典猿创建了一个非参数构造代码,更多关于这里

只需在 build.gradle 项目级别添加插件类路径

    dependencies {
    ....

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

    ....
    }
Run Code Online (Sandbox Code Playgroud)

然后配置您的注释以生成no-arg构造函数

apply plugin: "kotlin-noarg"

noArg {
      annotation("your.path.to.annotaion.NoArg")
      invokeInitializers = true
}
Run Code Online (Sandbox Code Playgroud)

然后定义您的注释文件 NoArg.kt

 @Target(AnnotationTarget.CLASS)
 @Retention(AnnotationRetention.SOURCE)
 annotation class NoArg
Run Code Online (Sandbox Code Playgroud)

最后在任何数据类中,您都可以简单地使用自己的注释

@NoArg
data class SomeClass( val datafield:Type , ...   )
Run Code Online (Sandbox Code Playgroud)

我曾经创建我自己的no-arg构造函数作为接受的答案,我通过搜索得到了它,但后来这个插件发布或其他东西,我发现它更干净。


Gui*_*i13 12

与@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.
}
Run Code Online (Sandbox Code Playgroud)

这意味着使用此技巧,您现在可以使用标准Java序列化程序(Jackson,Gson等)序列化/反序列化此对象.


ARG*_*Geo 10

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)


yOs*_*shi 9

如果为每个主构造函数参数提供默认值:

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 = "")
Run Code Online (Sandbox Code Playgroud)

并且从您可以在不带参数的情况下调用它的实例或使用您当时拥有的参数调用它的类

var newItem = Item()

var newItem2 = Item(title = "exampleTitle",
            condition = "exampleCondition",
            price = "examplePrice",
            categoryId = "exampleCategoryId")
Run Code Online (Sandbox Code Playgroud)


Mic*_*cer 7

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

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>()
)
Run Code Online (Sandbox Code Playgroud)

您还可以通过添加使值可以为空?,然后可以进行分配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
)
Run Code Online (Sandbox Code Playgroud)

一般来说,避免可为 null 的对象是一个很好的做法 - 以我们不需要使用它们的方式编写代码。与 Java 相比,不可为 null 的对象是 Kotlin 的优势之一。因此,上述第一种方案更可取

这两个选项都会给你想要的结果:

val activity = Activity()
activity.title = "New Computer"
sendToServer(activity)
Run Code Online (Sandbox Code Playgroud)


Gas*_*lén 6

文档

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