programar - Cómo crear un constructor vacío para la clase de datos en Kotlin Android
kotlin vs java (7)
Constructor secundario no vacío para la clase de datos en 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)
Constructor secundario vacío para la clase de datos en 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)
Tengo más de 10 parámetros en una clase de datos, quiero inicializar la clase de datos con un constructor vacío y establecer los valores solo para algunos parámetros usando setter y pasar el objeto al servidor.
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<*, *>,
)
Uso:
Algo así será fácil
val activity = Activity();
activity.title = "New Computer"
sendToServer(activity)
Pero requiere que se pasen todos los argumentos mientras se crea el constructor. ¿Cómo puedo simplificar como arriba?
val activity = Activity(null,null,null,null,null,"New Computer",null,null,null,null);
sendToServer(activity)
De la documentación
NOTA: en la JVM, si todos los parámetros del constructor primario tienen valores predeterminados, el compilador generará un constructor adicional sin parámetros que utilizará los valores predeterminados. Esto facilita el uso de Kotlin con bibliotecas como Jackson o JPA que crean instancias de clase a través de constructores sin parámetros.
Junto con la respuesta @miensol, permítanme agregar algunos detalles:
Si desea un constructor vacío visible en Java que use clases de datos, debe definirlo explícitamente.
Usar valores predeterminados + especificador de constructor es bastante fácil:
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.
}
Esto significa que con este truco ahora puede serializar / deserializar este objeto con los serializadores Java estándar (Jackson, Gson, etc.).
Si le da un valor predeterminado a cada parámetro de constructor primario:
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 = "")
y desde la clase donde las instancias puedes llamarlo sin argumentos o con los argumentos que tienes en ese momento
var newItem = Item()
var newItem2 = Item(title = "exampleTitle",
condition = "exampleCondition",
price = "examplePrice",
categoryId = "exampleCategoryId")
Si proporciona valores predeterminados a todos los campos , Kotlin genera automáticamente un constructor vacío.
data class User(var id: Long = -1,
var uniqueIdentifier: String? = null)
y simplemente puedes llamar:
val user = User()
Sugeriría modificar el constructor primario y agregar un valor predeterminado a cada parámetro:
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>()
)
También puede hacer que los valores sean anulables agregando
?
y luego puedes evaluar
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
)
En general, es una buena práctica evitar los objetos anulables: escriba el código de la forma en que no necesitemos usarlos. Los objetos no anulables son una de las ventajas de Kotlin en comparación con Java. Por lo tanto, la primera opción anterior es preferible .
Ambas opciones le darán el resultado deseado:
val activity = Activity()
activity.title = "New Computer"
sendToServer(activity)
Tienes 2 opciones aquí:
-
Asigne un valor predeterminado a cada parámetro de constructor primario :
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>() )
-
Declare un constructor secundario que no tiene parámetros:
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>() ) }
Si no confía en la
copy
o
equals
de la clase
Activity
o no usa los métodos de
data class
autogenerados, puede usar la clase regular de la siguiente manera:
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>()
}
No todos los
DTO
deben ser una
data class
y viceversa.
De hecho, en mi experiencia, encuentro que las clases de datos son particularmente útiles en áreas que involucran cierta lógica empresarial compleja.