Can Kotlin data class have more than one construct

2019-04-18 03:40发布

问题:

I know that data class are like simple models in kotlin with getters and setter by default and are as simple this:

data class User(val name: String, val age: Int)

Is it possible to declare a second constructor for that data class?

回答1:

Yes, but each variable should be initialized, so you may set default arguments in your data class constructor, like this:

data class Person(val age: Int, val name: String = "Person without name")

Now you can create instance of this data class in two ways

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


回答2:

A Kotlin data class must have a primary constructor that defines at least one member. Other than that, you can add secondary constructors as explained in Classes and Inheritance - Secondary Constructors.

For your class, and example secondary constructor:

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

Notice that the secondary constructor must delegate to the primary constructor in its definition.

Although many things common to secondary constructors can be solved by having default values for the parameters. In the case above, you could simplify to:

data class User(val name: String, val age: Int = -1) 

If calling these from Java, you should read the Java interop - Java calling Kotlin documentation on how to generate overloads, and maybe sometimes the NoArg Compiler Plugin for other special cases.



回答3:

Updated answer for data classes:

Yes you can, but you will need to delegate everything to the primary constructor

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)

You can also set default values in your primary constructor as Alexey did.



回答4:

Yes, we can use like below code, and in primary constructor for data class should have min one parameter.

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

    }
}


回答5:

Data class will ensure consistency and meaningful behavior also we need to have val for immutability.

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

}

}

secondary constructor must delegate to the primary constructor in its definition, so to maintain the immutability, having "null" will work.



回答6:

Default values in the primary constructor eliminates many needs for secondary constructors, but if the needed instance depends on logic based on data that must be analyzed the better answer may be to use a companion object.

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

Usage is then:

val ks = KeyTag.create("abc:1:10.0")
val ke = KeyTag.empty
val kb = KeyTag.bake(2)