En este artículo, aprenderá sobre la herencia. Más específicamente, qué es la herencia y cómo implementarla en Kotlin (con la ayuda de ejemplos).
La herencia es una de las características clave de la programación orientada a objetos. Permite al usuario crear una nueva clase (clase derivada) a partir de una clase existente (clase base).
La clase derivada hereda todas las características de la clase base y puede tener características adicionales propias.
Antes de entrar en detalles sobre la herencia de Kotlin, le recomendamos que consulte estos dos artículos:
- Objetos y clase de Kotlin
- Constructor principal de Kotlin
¿Por qué la herencia?
Suponga que en su solicitud desea tres personajes: un profesor de matemáticas , un futbolista y un empresario .
Dado que todos los personajes son personas, pueden caminar y hablar. Sin embargo, también tienen algunas habilidades especiales. Un profesor de matemáticas puede enseñar matemáticas , un futbolista puede jugar al fútbol y un empresario puede dirigir un negocio .
Puede crear individualmente tres clases que puedan caminar, hablar y realizar su habilidad especial.
En cada una de las clases, estaría copiando el mismo código para caminar y hablar para cada personaje.
Si desea agregar una nueva característica, comer, debe implementar el mismo código para cada carácter. Esto puede volverse fácilmente propenso a errores (al copiar) y códigos duplicados.
Sería mucho más fácil si tuviéramos una Person
clase con características básicas como hablar, caminar, comer, dormir y agregar habilidades especiales a esas características según nuestros personajes. Esto se hace mediante herencia.
El uso de la herencia, ahora no aplicar el mismo código para walk()
, talk()
y eat()
para cada clase. Solo necesitas heredarlos .
Entonces, para MathTeacher
(clase derivada), hereda todas las características de una Person
(clase base) y agrega una nueva característica teachMath()
. Del mismo modo, para la Footballer
clase, hereda todas las características de la Person
clase y agrega una nueva característica playFootball()
y así sucesivamente.
Esto hace que su código sea más limpio, comprensible y ampliable.
Es importante recordar: cuando se trabaja con herencia, cada clase derivada debe satisfacer la condición de si "es" una clase base o no. En el ejemplo anterior, MathTeacher
es a Person
, Footballer
es a Person
. No puedes tener algo como, Businessman
es un Business
.
Herencia de Kotlin
Intentemos implementar la discusión anterior en el código:
clase abierta Person (edad: Int) (// código para comer, hablar, caminar) clase MathTeacher (edad: Int): Persona (edad) (// otras características del profesor de matemáticas) clase Futbolista (edad: Int): Persona ( edad) (// otras características del futbolista) clase Hombre de negocios (edad: Int): Persona (edad) (// otras características del empresario)
Aquí, Person
es una clase base, y las clases MathTeacher
, Footballer
y Businessman
se derivan de la clase de la persona.
Aviso, la palabra clave open
antes de la clase base, Person
. Es importante.
Por defecto, las clases en Kotlin son definitivas. Si está familiarizado con Java, sabrá que una clase final no puede ser subclasificada. Al usar la anotación abierta en una clase, el compilador le permite derivar nuevas clases de ella.
Ejemplo: herencia de Kotlin
open class Person(age: Int, name: String) ( init ( println("My name is $name.") println("My age is $age") ) ) class MathTeacher(age: Int, name: String): Person(age, name) ( fun teachMaths() ( println("I teach in primary school.") ) ) class Footballer(age: Int, name: String): Person(age, name) ( fun playFootball() ( println("I play for LA Galaxy.") ) ) fun main(args: Array) ( val t1 = MathTeacher(25, "Jack") t1.teachMaths() println() val f1 = Footballer(29, "Christiano") f1.playFootball() )
Cuando ejecute el programa, la salida será:
Mi nombre es Jack. Mi edad es de 25 años y enseño en la escuela primaria. Mi nombre es Cristiano. Tengo 29 años y juego para LA Galaxy.
Aquí, dos clases MathTeacher
y Footballer
se derivan de la Person
clase.
El constructor principal de la Person
clase declaró dos propiedades: edad y nombre, y tiene un bloque inicializador. Los Person
objetos de las clases derivadas ( MathTeacher
y Footballer
) pueden acceder al bloque de inicio (y funciones miembro) de la clase base .
Las clases derivadas MathTeacher
y Footballer
tienen sus propias funciones miembro teachMaths()
y playFootball()
respectivamente. Estas funciones son accesibles solo desde los objetos de su clase respectiva.
Cuando MathTeacher
se crea el objeto t1 de clase,
val t1 = MathTeacher (25, "Jack")
Los parámetros se pasan al constructor principal. En Kotlin, el init
bloque se llama cuando se crea el objeto. Dado que, MathTeacher
se deriva de la Person
clase, busca el bloque inicializador en la clase base (Persona) y lo ejecuta. Si el MathTeacher
bloque init tuviera, el compilador también habría ejecutado el bloque init de la clase derivada.
A continuación, la teachMaths()
función para el objeto t1
se llama using t1.teachMaths()
statement.
El programa funciona de manera similar cuando se crea un objeto f1
de Footballer
clase. Ejecuta el bloque init de la clase base. Entonces, el playFootball()
método de Footballer
clase se llama using statement f1.playFootball()
.
Notas importantes: herencia de Kotlin
- Si la clase tiene un constructor primario, la base debe inicializarse usando los parámetros del constructor primario. En el programa anterior, ambas clases derivadas tienen dos parámetros
age
yname
, y ambos parámetros se inicializan en el constructor primario en la clase base.
Aquí hay otro ejemplo:open class Person(age: Int, name: String) ( // some code ) class Footballer(age: Int, name: String, club: String): Person(age, name) ( init ( println("Football player $name of age $age and plays for $club.") ) fun playFootball() ( println("I am playing football.") ) ) fun main(args: Array) ( val f1 = Footballer(29, "Cristiano", "LA Galaxy") )
- En caso de que no haya un constructor principal, cada clase base tiene que inicializar la base (usando super palabra clave), o delegar a otro constructor que lo haga. Por ejemplo,
fun main(args: Array) ( val p1 = AuthLog("Bad Password") ) open class Log ( var data: String = "" var numberOfData = 0 constructor(_data: String) ( ) constructor(_data: String, _numberOfData: Int) ( data = _data numberOfData = _numberOfData println("$data: $numberOfData times") ) ) class AuthLog: Log ( constructor(_data: String): this("From AuthLog -> + $_data", 10) ( ) constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) ( ) )
Anulación de funciones y propiedades de miembros
If the base class and the derived class contains a member function (or property) with the same name, you can need to override the member function of the derived class using override
keyword, and use open
keyword for the member function of the base class.
Example: Overriding Member Function
// Empty primary constructor open class Person() ( open fun displayAge(age: Int) ( println("My age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )
When you run the program, the output will be:
My fake age is 26.
Here, girl.displayAge(31)
calls the displayAge()
method of the derived class Girl
.
You can override property of the base class in similar way.
Visit how Kotlin getters and setters work in Kotlin before you check the example below.
// Empty primary constructor open class Person() ( open var age: Int = 0 get() = field set(value) ( field = value ) ) class Girl: Person() ( override var age: Int = 0 get() = field set(value) ( field = value - 5 ) ) fun main(args: Array) ( val girl = Girl() girl.age = 31 println("My fake age is $(girl.age).") )
When you run the program, the output will be:
My fake age is 26.
As you can see, we have used override
and open
keywords for age property in derived class and base class respectively.
Calling Members of Base Class from Derived Class
Puede llamar a funciones (y acceder a propiedades) de la clase base desde una clase derivada usando una super
palabra clave. Así es cómo:
open class Person() ( open fun displayAge(age: Int) ( println("My actual age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( // calling function of base class super.displayAge(age) println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )
Cuando ejecute el programa, la salida será:
Mi edad es 31. Mi edad falsa es 26.