Clases en Kotlin: Constructores y Propiedades, Herencia, abstractas, abiertas (open) y data class

Video thumbnail

Las clases en Kotlin como veremos en las siguientes dos entradas están simplificadas para escribir la mayor cantidad de funcionalidades con la menor cantidad de código ya vimos el uso de las funciones en Kotlin, como pieza clave para reutilizar código, vamos al siguiente bloque, las clases.

La sintaxis es simple o en el peor de los casos similares a los de otro lenguaje como Java cuenta (recordemos que sigue el mismo paradigma de orientado a objetos) con los mismos conceptos de constructores, herencia, interfaces, clases abstractas que en Java (aunque con una diferencia sustancial en el manejo de las propiedades).

Las clases son la forma en la que definimos objetos del mundo real en nuestro código. Por ejemplo, si nuestra aplicación vende coches, crearíamos una clase Carro con atributos específicos (marca, modelo, etc.) para tipificarlos y organizarlos.

Clases vacías

Para definir una clase en Kotlin en su mínima expresión tenemos que:

class Vacia

Como vemos, en Kotlin, para crear una clase pública (por defecto al no estar definido otro tipo de clase) no hace falta definir llaves ni nada por el estilo, ya que no tiene propiedades u otro método; también podríamos definir la clase anterior con las llaves:

class Vacia {}

Aunque las mismas son opcionales dependiendo de si definimos propiedades y métodos dentro de la clase; pero como mínimo debemos definir una clase que podemos llamar como vacía, es decir que no cuente con ningún tipo de propiedades o métodos en la misma y las llaves.

Instanciar clases

Para instanciar la clase anterior sería de la siguiente manera:

val vacia = Vacia ()

Los () sirven para indicar el método constructor, que para este ejemplo es el por defecto de la clase Vacia; Ademas note que no empleamos la palabra reservada de otros lenguajes de programación como Java new que es empleada en Java para indicar la creación de un nuevo objeto.

Aunque una clase sin nada adentro o nada definido no nos sirve de mucho; para eso tenemos las propiedades que veremos a continuación.

Propiedades de las clases en Kotlin

Las clases nos sirven para referenciar objetos del mundo real, y mediante las propiedades podemos definir las distintas características que nos interese manipular con las cuales conste ese objeto; por ejemplo, para definir una clase Persona en Kotlin con algunas propiedades (sí, propiedades y no atributos) podemos hacer lo siguiente:

class Persona {
  var nombre: String = ""
  var apellido: String = ""
  var edad: Int = 0
}

Las properties o propiedades en sustitución de las variables

Las properties o propiedades en Kotlin son algo innovador que nos facilitarán bastantes las cosas al momento de construir nuestras clases; ya que sustituyen a los getters y setters que tenemos que emplear en otros lenguajes como Java.

Con esto logramos una simplificación enorme en la cantidad de código que tenemos que crear en nuestras clases orientadas a objetos o que definen una entidad o algo por el estilo; por ejemplo, una persona, no tenemos que definir los gets y sets para el nombre, apellido, etc, si no simplemente declarar la propiedad como si de una variable se tratase.

Ahora vamos a volver a crear una instancia de una clase, en este caso de la clase llamada Persona y vamos a acceder a las propiedades que definimos anteriormente:

val persona = Persona()
persona.nombre = "Andrés"
persona.apellido = "Cruz"

Para acceder a cada uno de ellos podemos es igual de fácil:

println(persona.nombre) 
println(persona.apellido)

Propiedades, mas no variables en las clases de Kotlin

Un punto muy importante es lo que veníamos diciendo antes hay un cambio de concepto entre Kotlin y Java, mientras que en Java las propiedades nombre y apellido para este ejemplo serían campos en Kotlin son propiedades, esto nos trae que en Java se considera una mala práctica de programación que accedemos a las campos directamente como hicimos anteriormente, pero en Kotlin.

En Kotlin los métodos GET y SET son inferidos por el compilador, cosa que no ocurre en Java y esto se debe a esta diferencia de conceptos que señalamos anteriormente; puedes obtener más información en Kotlin Getters and Setters y es importante que sepas este cambio de paradigma y sepas aprovecharlo.

Sobreescribiendo los métodos get y set

Por supuesto podemos definir nuestros propios métodos gets y sets que sobrescriben a los que están por defectos o inferidos por el compilador de Kotlin:

class Persona {
var nombre: String = ""
    get() = field
    set(value) {
      field = value
    }
var apellido: String = ""
var edad: Int = 0
}

En Kotlin no es necesario definir explícitamente los métodos Get y Set, ya que el lenguaje los genera automáticamente. Sin embargo, puedes personalizarlos si necesitas lógica adicional (como convertir un texto a mayúsculas al asignarlo) usando el campo especial field.

Constructores de las clases

Constructor principal

Como todo lenguaje de programación orientado a objetos, Kotlin cuenta con métodos constructores en las clases que sirven para inicializar valores de la clase, al igual que en Java; pero a diferencia de este último, Kotlin incorpora una forma muy interesante con la cual ahorramos unas líneas de código cambia la metodología y no define el constructor principal como un método dentro de la función si no embebido dentro de la clase:

class Persona(nombre: String, apellido: String, edad: Int) {
  var nombre: String = nombre
  var apellido: String = apellido
  var edad: Int = edad
}

Kotlin define el constructor principal como parte de la clase en la cabecera/header de la misma, en donde los parámetros son opcionales.

Constructores en la Firma

A diferencia de otros lenguajes, Kotlin permite definir el constructor primario directamente en la firma de la clase. Esto permite recibir parámetros y asignar propiedades de forma compacta:

class Persona(val nombre: String, var edad: Int)

Ya con esto, de manera automática Koltin hace la equivalencia entre los parámetros en el constructor con las propiedades definidas en la clase.

Propiedades y Protección contra Nulos

Las clases contienen propiedades (nombre, apellido, edad). Al definirlas, es vital recordar la protección contra nulos de Kotlin. Debemos evitar que una propiedad sea nula; por ello, es recomendable asignar valores iniciales por defecto.

  • Val (Constante): Se usa para valores que no cambian (como el nombre).
  • Var (Variable): Se usa para valores que pueden mutar (como la edad).

Por optimización y buenas prácticas, intenta que todo sea un val a menos que sea estrictamente necesario cambiarlo.

Para crear una instancia inicializando desde el constructor tenemos: 

var persona = Persona("Andrés", "Cruz", 27)    

Constructor init

También existe el bloque init, que actúa como el cuerpo del constructor primario para realizar inicializaciones o validaciones. Si necesitas variantes, puedes crear constructores secundarios usando la palabra clave constructor.

class Persona(nombre: String, apellido: String, edad: Int) {
  var nombre: String = ""
  var apellido: String = ""
  var edad: Int = 0
  init {
	this.nombre = nombre
	this.apellido = apellido
	this.edad = edad
  }
}

Este último código sería "la manera Java" en la que especificamos qué parámetros del constructor inicializan las propiedades de la clase, internamente, esto es lo que hace Kotlin con la estructura del init{}.

O podríamos simplificarlo aún más:

class Persona(nombre: String, apellido: String, edad: Int) {
    var nombre: String = nombre
    var apellido: String = apellido
    var edad: Int = edad
}

Y con esto eliminamos la estructura del init de nuestro código.

También podemos colocar la palabra constructor luego de indicar el nombre de la clase:

class Persona constructor (nombre: String, apellido: String, edad: Int) { 
   var nombre: String = nombre 
   var apellido: String = apellido 
   var edad: Int = edad 
}

Todo estos ejemplos de constructores principales son equivalentes, pero si no vamos a realizar ninguna validación podemos dejarlo empleando el constructor por defecto:

class Persona(nombre: String, apellido: String, edad: Int) { 
   var nombre: String = "" 
   var apellido: String = "" 
   var edad: Int = 0 
}

Independientemente el esquema que prefieras, para crear una instancia de la clase persona empleando el constructor, podemos hacer lo siguiente:

var persona = Persona("Andrés"," Cruz",27)

Múltiples constructores (constructores secundarios)

Teniendo como constructor principal el que define (nombre: String, apellido: String, edad: Int) también definimos un constructor secundario, los cuales se encuentran definidos fuera del header de la clase pero dentro del cuerpo de la clase como para este ejemplo constructor (nombre: String, apellido: String):

class Persona constructor (nombre: String, apellido: String, edad: Int) {
  var nombre: String = ""
  var apellido: String = ""
  var edad: Int = 0
  constructor (nombre: String, apellido: String) : this(nombre, apellido, 0)
}

De esta manera, puedes definir cuántos constructores secundarios desees.

O lo que es lo mismo:

class Persona (nombre: String, apellido: String, edad: Int) {
  var nombre: String = nombre
  var apellido: String = apellido
  var edad: Int = edad
  
  constructor (nombre: String, apellido: String) : this(nombre, apellido, 0)
}

Como podemos ver, existen múltiples combinaciones según nuestro esquema preferido; en la siguiente entrada veremos los tipos de clases en Kotlin, herencia, interfaces y clases abstractas en Kotlin.

Clases abiertas (Open class) y herencia en Kotlin

Lo primero que trataremos aquí son como crear una clase en Kotlin y como son declaradas dichas clases en Kotlin; las clases en Kotlin son por defecto declaradas como finales, lo que significa que no podemos heredar de una clase que creemos como en este ejemplo:

class Padre
class Hija : Padre()

Porque el compilador de Kotlin nos daría un error; las clases en Kotlin heredan por defecto de una superclase llamada Any; por lo tanto, la clase llamada Padre hereda por defecto de la clase Any:

class Padre // de manera implicita hereda de la clase Any

Si queremos heredar de una clase que definamos, debemos declararla como una "open class" o clase abierta; esta anotación tiene un comportamiento opuesto que tienen los finals en las clases en Java y por ende nos permite realizar la herencia, empleando la anotación siguiente manera:

open class Padre
class Hija : Padre()

Esto es una diferencia importante con Java, en donde podemos heredar de una clase sin necesidad de incorporar una palabra reservada que especifique que queremos que podamos heredar de la misma; esto es un principio muy importante en Kotlin para ayudarnos a mantener organizados nuestras clases.

Al agregar open en nuestras clases estamos indicando que queremos diseñar dicha clase para que pueda ser heredada, lo que a la final permite facilitar la lectura del código de alguna aplicación realizada con Kotlin, independientemente si es una aplicación para Android, o para otra plataforma; también es importante señalar que no podemos heredar de múltiples clases o herencia múltiple.

Clases Abiertas (open)

Por defecto, todas las clases en Kotlin son final (no se pueden heredar, son de tipo final). Para permitir la herencia, debemos marcar la clase padre con la palabra open.

Herencia y Polimorfismo

Para que una clase hija herede de una padre, usamos los dos puntos : 

Por ejemplo, una clase Forma puede tener un método calcularArea(). 

Clases como Circulo o Rectangulo heredarán de Forma y usarán la palabra override para proporcionar su propia implementación del área.

open class Forma {
    open fun calcularArea() = 0.0
}
class Circulo(val radio: Double) : Forma() {
    override fun calcularArea() = Math.PI * radio * radio
}

Ejemplo de clases y herencia

Esto sería lo esencial aquí para heredar de clases, por lo demás podemos hacer lo mismo que hacemos en otros lenguajes de programación; por ejemplo, el siguiente esquema es válido para declarar una serie de clases para especificar formas geométricas que es lo que veremos a continuación:

open class Forma(val nombre: String) {
   open fun area() = 0.0
}
class Circulo(nombre: String, val radius: Double): Forma(nombre)

En el ejemplo anterior definimos una clase llamada Forma que tendría las primitivas para especificar las formas geométricas, que en nuestro caso solo es un nombre de la forma geométrica, y una función que sobreescribimos para especificar el área de la forma geométrica.

Luego creamos una clase Circulo y su constructor, que para el caso del círculo debemos agregar un parámetro extra que es el radio del mismo:

class Circulo(name: String, val radius: Double)

Luego, como queremos que nuestra clase Circulo herede las propiedades de Forma, especificamos la herencia indicando el nombre de la clase a heredar luego de indicar los dos puntos, en donde referenciamos al constructor de la clase Forma (vendría siendo como emplear la palabra reservada super en Java):

class Circulo(name: String, val radius: Double): Forma(nombre)

Ahora podemos sobrescribir el método área para nuestro circulo:

Para también sobrescribir cualquier propiedad o método de la clase heredada, debemos especificar la palabra reservada open sobre dicho propiedad o método.

open class Forma(val nombre: String) {
  open fun area() = 0.0
}
class Circulo(nombre: String, val radio: Double): Forma(nombre) {
  override fun area() = Math.PI * Math.pow(radio, 2.0)
}
fun main(args: Array<String>) {
  val circulo = Circulo("Circulo", 4.0)
  println(circulo.nombre)
  println(circulo.radio)
  println(circulo.area())
}

Clases abstractas en Kotlin

Las clases abstractas prácticamente siguen el mismo principio que en otros lenguajes de programación orientados a objetos como Java; las clases abstractas son aquellas que no tienen implementación y se usa la palabra reservada abstract en las clases para tal fin.

Cómo puedes recordar en este caso no es necesario especificar un valor de retorno para nuestro método area igual que hicimos anteriormente ya que el mismo va a ser sobrescrito en nuestra clase hija:

abstract class Forma(val nombre: String) {
   abstract fun area(): Double
   fun printName(){
       println("el nombre es: ${nombre}")
   }
}
class Circulo(nombre: String, val radio: Double): Forma(nombre) {
   override fun area() = Math.PI * Math.pow(radio, 2.0)
}
fun main(args: Array<String>) {
   val circulo = Circulo("Circulo", 4.0)
   println(circulo.nombre)
   println(circulo.radio)
   println(circulo.area())
   println(circulo.printName())
}

Podemos emplear la palabra reservada en los métodos (fun) para especificar que la clase que la definan sobreescriba dichos métodos, o podemos implementar algunos dentro de la clase abstracta y de esta forma, poder emplearlos en la clase que definen dicha clase abstracta.

Como en cualquier otro lenguaje, debemos sobrescribir cualquier método o propiedad que contenga la palabra reservada abstract en la clase hija.

Las interfaces en Kotlin

Como último concepto de programación orientada a objetos que trataremos en esta entrada, las interfaces se declaran con la palabra reservada interface; debes saber que todos los métodos son públicos y pueden ser sobrescritos; también podemos definir métodos con cuerpo o contenido, lo que es una gran ventaja, ya que no tenemos que estar repitiendo código en otras clases y podemos definirlo como base en la interfaz.

Una característica primordial de las interfaces es que no implementan métodos, ni constructores, lo que es una distinción con la herencia o clases abstractas que vimos anteriormente.

Las interfaces no encapsulan datos, solo definen cuales son los métodos que se deben implementar en las clases que la definan.

Por lo tanto nuestro ejemplo quedaría de la siguiente forma:

interface Forma {
   fun area(): Double
   fun printName();
}
class Circulo(val nombre: String, val radio: Double): Forma {
   override fun area() = Math.PI * Math.pow(radio, 2.0)
   override fun printName(){}
}
fun main(args: Array<String>) {
   val circulo = Circulo("Circulo", 4.0)
   println(circulo.nombre)
   println(circulo.radio)
   println(circulo.area())
}

También podemos definir una implementación por defecto en nuestra interfaz:

interface Forma {
   fun area(): Double = 0.0
   fun printName();
}

Copiar instancias

Al asignar un objeto a otro, ambos apuntan a la misma memoria. Para tener una instancia independiente, se debe realizar una copia:

class Persona(var nombre: String)
fun main() {
    val persona1 = Persona("Juan")
    val persona2 = persona1 // Copia de referencia
    persona2.nombre = "Carlos"
    println(persona1.nombre) // Resultado: "Carlos" (¡El original cambió!)
}

La forma más eficiente y común de copiar en Kotlin es usar una data class. Estas clases incluyen automáticamente el método copy(), que crea una instancia nueva con los mismos valores.

class Usuario(val id: Int, val email: String)
fun main() {
   val user1 = Usuario(1, "ana@correo.com")
   val user2 = user1.copy() // Es un objeto totalmente nuevo en memoria
   println(user1 == user2) // true (tienen el mismo contenido)
   println(user1 === user2) // false (son diferentes objetos físicamente)
}

Lo más potente de copy() es que puedes cambiar solo algunas propiedades mientras mantienes el resto igual. Esto es ideal para seguir el principio de inmutabilidad.

val original = Usuario(id = 1, email = "pedro@correo.com")
// Creamos una copia pero actualizamos solo el email
val actualizado = original.copy(email = "pedro_nuevo@correo.com")
println(original.email)    // "pedro@correo.com"
println(actualizado.email) // "pedro_nuevo@correo.com"

¿Por qué es importante copiar?

En el desarrollo de aplicaciones modernas (especialmente con Jetpack Compose o arquitecturas de estado), la inmutabilidad es clave.

En lugar de modificar un objeto existente, "copiamos" el estado anterior, aplicamos el cambio y generamos un nuevo estado.

Esto evita errores difíciles de rastrear donde los datos cambian "por debajo" sin previo aviso.

Los data class en Kotlin para almacenar y procesar datos de manera sencilla

Video thumbnail

Vamos a conocer otra estructura muy interesante: el Data Class. Como su nombre indica, es una clase pensada específicamente para trabajar con datos.

Vamos a conocer otra estructura muy interesante que también estaba en la sección de clases: las data class.
Su nombre ya dice bastante, pero aun así es algo abstracto, así que vamos a conocerlas en detalle.

El “problema” de las clases tradicionales

Primero, ¿cuál es el problema (entre comillas) que tenemos con las clases normales?

Usualmente, las clases se emplean muchas veces solo como un depósito de datos, como si fueran un repositorio. Por ejemplo, cuando queremos crear un modelo de usuarios, un listado de publicaciones, o cualquier estructura similar, simplemente almacenamos datos y no usamos lógica adicional.

El problema es que una clase tradicional termina siendo bastante grande y compleja, con todas las características que ya vimos anteriormente (constructores, open, final, herencia, etc.), cosas que muchas veces no necesitamos cuando solo queremos manejar datos.

Por eso aparece el concepto de data class, que es una clase pensada específicamente para trabajar con datos, así de simple.
De hecho, Kotlin es uno de los pocos lenguajes que incorpora este concepto de forma nativa.

¿Qué ventajas tienen las Data Class?

Al usar data class:

  • Te olvidas de cosas como open, final y demás configuraciones innecesarias.
  • Son ideales cuando queremos manejar listados de datos (usuarios, productos, publicaciones, etc.).
  • Son más eficientes que una clase normal.
  • Las comparaciones son muchísimo más sencillas.

Si quieres que una clase pueda heredarse, debes marcarla como open.

Con las data class no tenemos que preocuparnos por nada de eso.

En resumen:

  1. Eficiencia: Son más ligeros que una clase normal al tener menos sobrecarga.
  2. Comparaciones sencillas: Facilitan enormemente la comparación de objetos, algo que en las clases tradicionales es un dolor de cabeza.

El Problema de la Referencia de Memoria

Para entender por qué son útiles, debemos recordar cómo funcionan las clases normales. Cuando creas un objeto, no estás asignando el valor directamente, sino una posición de memoria (una referencia).

class Contact(val id: Int, var email: String)
fun main() {
    val contact = Contact(1, "mary@gmail.com")
    var contact2 = contact
    println(contact == contact2) // false           
}

Si tienes contact1 y creas contact2 igualándolo al primero, ambos apuntan al mismo sitio, la misma posición en memoria. Si cambias el email en uno, cambiará automáticamente en el otro porque comparten la misma instancia.

fun main() {
    val contact = Contact(1, "mary@gmail.com")
    var contact2 = contact
    // Prints the value of the property: email
    println(contact.email)           
    // mary@gmail.com
    // Updates the value of the property: email
    contact.email = "jane@gmail.com"
    
    // Prints the new value of the property: email
    println(contact2.email)           
    // jane@gmail.com
}

En cambio, con tipos primitivos (como números), la asignación sí crea una copia del valor. Si comparas dos instancias de una clase normal con los mismos datos, el resultado será false porque están en posiciones de memoria distintas, a menos que implementes manualmente métodos como equals o toString.

var n = 5
var n2 = n
println(n2 = n)

El problema de comparar objetos

Cuando trabajamos con datos reales y queremos hacer comparaciones entre objetos, la cosa se complica:

  • Dos objetos pueden tener exactamente los mismos datos…
  • …pero apuntar a posiciones de memoria distintas.
  • Y por lo tanto, la comparación da false.

Esto nos obliga a implementar métodos como equals, hashCode, y otros mecanismos adicionales solo para poder comparar datos.

Y justamente ahí es donde entran las data class.

Data Class en acción

Una data class se define casi igual que una clase normal:

  • Nombre en mayúscula.
  • Constructor.
  • Propiedades.

La diferencia está en lo que Kotlin genera automáticamente por nosotros.

data class User(val name: String, val id: Int)
val user = User("Alex", 1)
val user2 = User("Andres", 1)
println(user == user2) // false, compara datos            

Por ejemplo, al imprimir una clase normal, lo que vemos suele ser una referencia rara de memoria:

class User(val name: String, val id: Int)
val user = User("Alex", 1)
val user2 = User("Alex", 1)
println(user) // FileKt$main$User@3d494fbf    
println(user == user2) // false, compara posición de memoria y no datos           

Con una data class, en cambio, Kotlin imprime directamente los valores del objeto, lo cual ya es una ventaja enorme.

println(user)
 //User(name=Alex, id=1)

Comparaciones simples y claras

Otra gran ventaja es que las comparaciones son muy sencillas.

Si creamos dos instancias de una data class con los mismos valores y las comparamos, el resultado será true, porque se comparan los datos, no la posición de memoria.

data class User(val name: String, val id: Int)
val user = User("Alex", 1)
val user2 = User("Alex", 1)
println(user == user2) // true, compara datos          

Si cambiamos uno de los valores, la comparación pasa a ser false.

data class User(val name: String, val id: Int)
val user = User("Alex", 1)
val user2 = User("Andres", 1)
println(user == user2) // false, compara datos     

Así de simple y claro.

Copiar objetos con copy()

En lugar de modificar directamente una instancia existente (lo cual no siempre es buena práctica), las data class nos permiten usar el método copy().

Esto es muy útil cuando:

  • Queremos crear una nueva entidad a partir de otra.
  • Solo necesitamos cambiar uno o dos valores.
  • Queremos mantener las instancias separadas.

Por ejemplo, podemos copiar un usuario y cambiar solo el nombre, manteniendo el resto de los datos intactos.

Cada copia tendrá su propia posición de memoria, evitando errores inesperados.

val user = User("Alex", 1)
// Creates an exact copy of user
println(user.copy())       
// User(name=Alex, id=1)
// Creates a copy of user with name: "Max"
println(user.copy("Max"))  
// User(name=Max, id=1)
// Creates a copy of user with id: 3
println(user.copy(id = 3)) 
// User(name=Alex, id=3)

Desestructuración de Data Class

Otra característica muy potente es la desestructuración.

Podemos obtener los valores de un objeto de varias formas:

Accediendo directamente a cada propiedad (obj.nombre, obj.precio, etc.).

Usando desestructuración por orden:

data class Product(val nombre: String, val precio: Double)
fun main() {
	val myProduct = Product("Laptop", 1200.0)
	val (nombre, precio) = myProduct //("Laptop", 1200.0)
}

Usando los métodos componentN() (component1(), component2(), etc.).

Esto es especialmente útil cuando trabajamos con objetos genéricos o cuando no nos importa el nombre de las propiedades, sino su posición.

data class Product(val nombre: String, val precio: Double)
fun main() {
	val myProduct = Product("Laptop", 1200.0)
	println(myProduct.component1() // "Laptop"
}

Los data class Pair y Triple en Kotlin para almacenar valores pares

Siguiendo con los tutoriales de Kotlin, hoy veremos los data class Pair en Kotlin, que simplemente son una representación genérica (cualquier tipo de datos o clases) de dos valores (pares); son una especie de tupla pero con algunas variantes.

Los data class Pair son una estructura que permite guardar dos valores.

Los valores pares son excelente cuando queremos guardar parejas de datos; y así de simple, es una estructura que nos sirve solo para eso; el método constructor o mejor dicho la estructura básica de un valor par en Kotlin luce como el siguiente:

Pair(first: A, second: B)

El valor first corresponde al primer valor y el de second, como podrás imaginar.

Ya estando en la práctica, para emplear los valores pares en Kotlin es tan fácil como hacer lo siguiente:

var pair = Pair("Kotlin Pair",2)

Como puedes ver, no estamos obligados a tener valores pares del mismo tipo, son independientes y pueden tomar cualquier valor que necesitemos.

Palabra reservada Pair o to para crear valores pares

También podemos crear valores pares empleando la variable reservada to de la siguiente forma:

var pair = "Kotlin Pair" to 2

Esto en Android es muy útil ya que podemos emplear los Pair Para guardar una pareja de valores, por ejemplo un usuario y contraseña o cualquier pareja de valores que tengan alguna relación.

¿Cómo acceder a los valores Pair en Koltin?

Ya teniendo claro para qué sirve la estructura de los Pair en Kotlin, lo siguiente que nos interesa saber es cómo acceder a cada uno de estos valores embebidos dentro de un data class Pair; para esto se emplean las palabras reservadas first y second respectivamente de la siguiente forma; teniendo nuestra variable llamada pair definida de cualquiera de las formas anteriores:

println(pair.first) //Kotlin
println(pair.second) //Pair2

Y obtenemos como salida:

Kotlin 
Pair2

También podemos emplear los métodos component1() y component2() respectivamente para obtener la misma salida anterior:

println(pair.component1()) //Kotlin
println(pair.component2()) //Pair2

Para cada uno de los println respectivamente.

Descomposición de los valores par Pair en Kotlin

También podemos separar o descomponer los valores de los pares en variables individuales e independientes de la siguiente forma; tal cual hicimos antes con los mismos data class en la entrada anterior:

val (user, password) = Pair("usuario", "contrasena") 
println(user) // usuario
println(password) // contrasena

Y se obtiene:

usuario
contrasena

Métodos de los valores pares

Los Pair en Kotlin cuentan con un par de métodos que podemos emplear para emplear toda la estructura al 100%; el primero de ellos es el toString que imprime un string con los valores dos valores:

var pair = Pair("Kotlin Pair",2)
fun main(args: Array<String>) {
    println(pair.toString()) // imprime (Kotlin Pair, 2)
}

Y también tenemos el método toList() que nos retorna una lista con ambos valores pares:

var pair = Pair("Kotlin Pair",2)
fun main(args: Array<String>) {
    println(pair.toList()) // imprime [Kotlin Pair, 2]
}

Inspiración para emplear valores pares

Con los valores pares podemos hacer muchas cosas, hay muchas estructuras que nos quedan perfecto emplear un Pair de Kotlin; por ejemplo la ubicación de una pareja de puntos en un plano 2D:

data class Punto<T>(var x: T, var y: T)

Que pueden ser serializables para que puedas colocar cualquier valor, como enteros o flotantes; podemos emplearlo como pareja como hicimos anteriormente para una pareja de usuario y contraseña, también podemos emplearlo para configurar una URL y un único parámetro:

var url = Pair("https://x.com/","ACY291190")

Ahora, conoce otro tipo de clases como vienen siendo las clases enumeradas en Kotlin.

Acepto recibir anuncios de interes sobre este Blog.

En esta entrada veremos cómo manejar las clases en Kotlin, constructor principal, constructores secundarios, propiedades, métodos set y get, crear instancias de clases, clases vacías, data class, Pair y Triple.

| 👤 Andrés Cruz

🇺🇸 In english