Im trying to overload a constructor of a class, so that it accepts Strings as well as Ints.
class Load (val duration: Int = 0,val minrep: Int = 0,val maxrep: Int = 0): Serializable{
constructor(duration: String = "0",minrep: String = "0",maxrep: String = "0")
: this(duration.toInt(),minrep.toInt(),maxrep.toInt())
The Problem is since I am forced to call the superconstructor immediatly, I cannot check for "" in the variables which is a possible state which then crashes the app in to .toInt().
So what I would want to do is something like this:
constructor(duration: String = "0",minrep: String = "0",maxrep: String = "0") {
if(duration == "")
duration = "0"
...
this(duration.toInt(),minrep.toInt(),maxrep.toInt())
}
But How?
There's a quick-and-dirty method; you just need to know that if
is an expression in Kotlin:
class Load(val duration: Int = 0, val minrep: Int = 0, val maxrep: Int = 0): Serializable {
constructor(duration: String = "0", minrep: String = "0", maxrep: String = "0")
: this(if (duration == "") 0 else duration.toInt(), minrep.toInt(), maxrep.toInt())
}
However, that gets unwieldy very quickly, and there's a limit to the sort of processing you can do that way. (As another answer shows, you can call helper methods, but it's still awkward.)
So a more general solution is to use a factory method: one which does whatever processing it needs to, and then calls the constructor. In Java this would be a static method; the Kotlin equivalent is a method on the class's companion object
:
class Load(val duration: Int = 0, val minrep: Int = 0, val maxrep: Int = 0): Serializable {
companion object {
operator fun invoke(duration: String = "0", minrep: String = "0", maxrep: String = "0"): Load {
val dur = if (duration == "") 0 else duration.toInt()
// ...
return Load(dur, minrep.toInt(), maxrep.toInt())
}
}
}
The magic here is that by making it operator fun invoke()
, you can then call it as Load(…)
, so it looks just like calling a normal constructor!
(This is only appropriate if it's obvious what it does, just from the parameter types alone. If it's not obvious, or if you need two factory methods with the same parameter types, a regular named method is better.)
Factory methods give you a lot more control over how your objects get created: they let you do arbitrary amounts of processing before calling the constructor; they can return a cached object instead of creating a new instance each time; and they can return a subclass if that's appropriate. (However, one drawback is that they don't work well with inheritance.)