Kotlin数据类可以有多个构造函数吗?

Ede*_*lla 32 constructor kotlin

我知道数据类就像kotlin中的简单模型,默认情况下使用getter和setter,就像这样简单:

data class User(val name: String, val age: Int)
Run Code Online (Sandbox Code Playgroud)

是否可以为该数据类声明第二个构造函数?

Jay*_*ard 20

Kotlin数据类必须具有定义至少一个成员的主构造函数.除此之外,您可以按照类和继承 - 辅助构造函数中的说明添加辅助构造函数.

对于您的类和示例辅助构造函数:

data class User(val name: String, val age: Int) {
    constructor(name: String): this(name, -1) { ... }
}
Run Code Online (Sandbox Code Playgroud)

请注意,辅助构造函数必须在其定义中委托给主构造函数.

虽然辅助构造函数的许多共同点可以通过使用参数的默认值来解决.在上面的例子中,您可以简化为:

data class User(val name: String, val age: Int = -1) 
Run Code Online (Sandbox Code Playgroud)

如果从Java调用它们,您应该阅读Java interop - Java调用Kotlin文档,了解如何生成重载,有时可能是NoArg Compiler Plugin用于其他特殊情况.


Rob*_*ert 18

数据类的更新答案:

是的,您可以,但是您需要将所有内容都委托给主构造函数

data class User(val name: String, val age: Int)
{
    constructor(name: String): this(name, -1) {
    }

    constructor(age: Int): this("Anon", age) {
    }
}

// Anon name: Anon
println("Anon name: " + User(30).name)

// No age: -1
println("No age: " + User("Name").age)

// Name: Name age: 20
val u = User("Name", 20)
println("Name: " + u.name + " age: " + u.age)
Run Code Online (Sandbox Code Playgroud)

您还可以像 Alexey 那样在主构造函数中设置默认值。


Ale*_*nko 18

是的,但是应该初始化每个变量,因此您可以在数据类构造函数中设置默认参数,如下所示:

data class Person(val age: Int, val name: String = "Person without name")
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过两种方式创建此数据类的实例

  • Person(30)
  • Person(20, "Bob")

  • 这与辅助构造函数有什么关系? (12认同)
  • 上面提到的问题是"如果可以为该数据类声明第二个构造函数?" 你的答案根本没有提到二级构造函数. (12认同)

Mik*_*fey 12

主构造函数中的默认值消除了对辅助构造函数的许多需求,但如果所需的实例依赖于基于必须分析的数据的逻辑,则更好的答案可能是使用伴随对象。

data class KeyTag(val a: String, val b: Int, val c: Double) {
    companion object Factory {
        val empty = KeyTag("", 0, 0.0)

        fun create(bigString: String): KeyTag {
            // Logic to extract appropriate values for arguments a, b, c
            return KeyTag(a, b, c)
        }

        fun bake(i: Int): KeyTag = KeyTag("$i", i, i.toDouble())
    }
}
Run Code Online (Sandbox Code Playgroud)

用法是:

val ks = KeyTag.create("abc:1:10.0")
val ke = KeyTag.empty
val kb = KeyTag.bake(2)
Run Code Online (Sandbox Code Playgroud)


boo*_*aja 10

数据类将确保一致性和有意义的行为,我们还需要 val 来实现不变性。

data class SampleData(val name: String, val age: Int, val email: String ?= null) {
constructor(name: String, age: Int) : this(name, age, null) {

    }
}
Run Code Online (Sandbox Code Playgroud)

辅助构造函数必须在其定义中委托给主构造函数,因此为了保持不变性,使用“null”将起作用。


Ede*_*lla 9

您可以像这样设置数据类

data class User(val name: String? = null, val id: String? = null, val email: String? = null)
Run Code Online (Sandbox Code Playgroud)

你可以使用多个构造函数来实例化对象

val userId = User(id = "123456")
        val userMail = User(email= "email@email.com")
        val userName = User("Name")
Run Code Online (Sandbox Code Playgroud)


Ran*_*mer 6

指示 Kotlin 编译器为此函数生成替换默认参数值的重载。如果一个方法有 N 个参数,其中 M 个具有默认值,则会生成 M 个重载:第一个参数采用 N-1 个参数(除了最后一个参数外,所有参数均采用默认值),第二个参数采用 N-2 个参数,依此类推在。

 data class User @JvmOverloads  constructor(
var email: String="",
var password: String="")
Run Code Online (Sandbox Code Playgroud)


Hac*_*ck5 6

我想要一个类似于下面的类(带有一个解析输入的构造函数)

data class Data(val a: String, val b: String) {
    constructor(spaceSeparated: String) { // error because we don't call this()
        val split = spaceSeparated.split(" ")
        this(split.first(), split.last()) // error again because it's not valid there
    }
}
Run Code Online (Sandbox Code Playgroud)

解决方案是这样做:

data class Data(val a: String, val b: String) {
    companion object {
        operator fun invoke(spaceSeparated: String): Data {
            val split = spaceSeparated.split(" ")
            return Data(split.first(), split.last())
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它可以像构造函数一样被调用

  • 这比接受的答案更好 (4认同)

Mut*_*ran 5

是的,我们可以使用如下代码,并且在数据类的主构造函数中应该至少有一个参数。

data class SampleData(val name: String, val age: Int) {
    constructor(name: String, age: Int, email: String) : this(name, age) {

    }
}
Run Code Online (Sandbox Code Playgroud)