Introducción a las clases en Kotlin
Kotlin, como lenguaje de Programación Orientado a Objetos (POO u OOP según sus siglas en inglés), utiliza las clases para definir las propiedades y los comportamientos de un tipo de objeto y declara objetos que son instancias de una clase.
Las clases en Kotlin son declaradas usando la palabra reservada class:
class Libro { ... }La declaración de una clase consiste, en este orden, en un nombre, un encabezado y un cuerpo. El nombre identifica a la clase, le sigue un encabezado opcional que puede especificar un constructor y parámetros, y termina con el cuerpo de la clase entre llaves donde se sitúan las propiedades y métodos si los hubiera. Si la clase no tiene cuerpo se pueden omitir las llaves y declararla simplemente así:
class Libro
Y ya podemos instanciar esta clase de esta manera, utilizando su constructor por defecto que se omite:
val libro = Libro()En Kotlin una clase puede tener un constructor primario y uno o más constructores secundarios. El constructor principal forma parte del encabezado de la clase y va después del nombre de la clase:
class Libro constructor(titulo: String) { ... }Pero si este constructor principal no tiene anotaciones o modificadores de visibilidad (como private, protected, internal o public que veremos en futuras entradas), la palabra clave constructor se puede omitir:
class Libro(titulo: String) { ... }Además del constructor primario que no contiene código aparte de sus parámetros, podemos crear otros constructores secundarios:
class Libro { // propiedades var titulo: String var isbn: Long // constructor secundario constructor(titulo: String, isbn: Long) { this.titulo = title this.isbn = isbn } }También podemos crear uno o varios bloques con la palabra clave init que se ejecutan de manera ordenada según aparecen en el cuerpo de la clase durante la inicialización de una instancia:
class Libro (titulo: String, isbn: Long) { var titulo: String var isbn: Long init { this.titulo = titulo this.isbn = isbn } }Hay que tener en cuenta que el código en los bloques init se convierte en parte del constructor primario, por lo que el código en todos los bloques de inicialización se ejecuta antes que el cuerpo del constructor secundario:
class Constructores { var paso = 1 init { println("$paso. Bloque init 1") paso++ } constructor(i: Int) { println("$paso. Constructor secundario $i") } init { println("$paso. Bloque init 2") paso++ } } fun main() { Constructores(1) }Este código muestra el siguiente resultado:
1. Bloque init 1 2. Bloque init 2 3. Constructor secundario 1Además de usarse en los bloques de init, los parámetros del constructor primario también se pueden usar directamente en las propiedades declaradas en el cuerpo de la clase:
class Libro(titulo: String) { val libroMay = titulo.toUpperCase() }De hecho, podemos declarar propiedades e inicializarlas directamente desde el constructor principal con una sintaxis concisa:
class Persona(val nombre: String, val apellido: String, var edad: Int) { ... } class Libro(val titulo: String = "")Y para crear una instancia de una clase, llamamos al constructor como si fuera una función:
val libro = Libro("Don Quijote")También podemos agregar valores por defecto a cualquiera de las propiedades de la clase directamente dentro del constructor primario. Un par de ejemplos:
class Usuario (var nombre: String, var clave: Long = 123456) fun main(args: Array<String>) { val usuario1 = Usuario("Torpedo", 238732) val usuario2 = Usuario("Demo") // utiliza el valor por defecto de la propiedad clave println(usuario1.nombre + ": " + usuario1.clave) // Torpedo: 238732 println(usuario2.nombre + ": " + usuario2.clave) // Demo: 123456 }
class Usuario (var nombre: String = "Demo", var clave: Long) fun main(args: Array<String>) { val usuario1 = Usuario("Torpedo", 238732) val usuario2 = Usuario(clave=123456) // utiliza el valor por defecto de la propiedad nombre println(usuario1.nombre + ": " + usuario1.clave) // Torpedo: 238732 println(usuario2.nombre + ": " + usuario2.clave) // Demo: 123456 }Además de constructores y bloques de inicialización, las clases contienen básicamente propiedades y métodos (funciones). Para referirnos a las propiedades (y a los métodos) utilizamos el nombre del objeto seguido por un punto y el nombre de la propiedad, que es lo que se conoce como sintaxis de acceso de propiedad:
class Persona { var nombre: String = "" var edad: Int = 0 } fun clonarPersona(persona: Persona): Persona { val clon = Persona() clon.nombre = persona.nombre clon.edad = persona.edad return clon } fun main(args: Array<String>) { val persona1 = Persona() persona1.nombre = "Pepe" persona1.edad = 32 val persona2 = clonarPersona(persona1) println(persona1.nombre) // Pepe println(persona2.nombre) // Pepe }Esto mismo lo podríamos escribir así:
class Persona (var nombre: String, var edad: Int) fun clonarPersona(persona: Persona): Persona { val clon = Persona(persona.nombre, persona.edad) return clon } fun main(args: Array<String>) { val persona1 = Persona("Pepe", 32) // inicializamos directamente desde el constructor val persona2 = clonarPersona(persona1) println(persona1.nombre) // Pepe println(persona2.nombre) // Pepe }Como hemos visto, las propiedades de una clase pueden declararse como mutables usando var o como de solo lectura con val:
class Libro ( var titulo: String, val isbn: Long ) fun main(args: Array<String>) { val libro = Libro("Don Quijote", 4771599780007) libro.titulo = "Don Quijote de la Mancha" // la propiedad titulo es reasignada a otro valor libro.isbn = 599780007123 // error: propiedad de solo lectura no puede ser reasignada }También hay que tener en cuenta que Kotlin no permite definir una propiedad y no asignarle ningún valor y que quede con el valor null.
Un ejemplo de clase con propiedades y métodos:
class Bombilla { // creamos la clase Bombilla // propiedad de clase var isOn: Boolean = false // métodos de clase (funciones) fun encender() { isOn = true } fun apagar() { isOn = false } fun muestraEstado(bombilla: String) { if (isOn == true) println("La bombilla $bombilla está encendida.") else println("La bombilla $bombilla está apagada.") } } fun main(args: Array<String>) { // creamos objetos de la clase Bombilla val b1 = Bombilla() val b2 = Bombilla() // invocamos los métodos de la clase para cada objeto // métodos que cambian el valor de la propiedad b1.encender() b2.apagar() // no es necesario porque el valor isOn se inicializa en false para cada nuevo objeto // métodos que muestran el estado de la proiedad b1.muestraEstado("b1") b2.muestraEstado("b2") }Un ejemplo de una clase con constructor primario con valores por defecto y un bloque inicializador:
fun main(args: Array<String>) { val persona1 = Persona("juan", 25) val persona2 = Persona("pepe") val persona3 = Persona() } class Persona(_nombre: String = "DESCONOCIDO", _edad: Int = 0) { // es común usar los mismos nombres para el parámetro y la propiedad // y para distinguirlos se suele usar un guión bajo val nombre = _nombre.capitalize() var edad = _edad // bloque inicializador que se ejecuta cuando se instancia un objeto de la clase init { println("Nombre: $nombre - Edad: $edad") } }
Comentarios
Publicar un comentario