Neste artigo, você aprenderá sobre herança. Mais especificamente, o que é herança e como implementá-la em Kotlin (com a ajuda de exemplos).
Herança é um dos principais recursos da programação orientada a objetos. Ele permite ao usuário criar uma nova classe (classe derivada) a partir de uma classe existente (classe base).
A classe derivada herda todos os recursos da classe base e pode ter recursos adicionais próprios.
Antes de entrar em detalhes sobre a herança do Kotlin, recomendamos que você verifique estes dois artigos:
- Classe e objetos Kotlin
- Construtor primário Kotlin
Por que herança?
Suponha que, em seu aplicativo, você queira três personagens - um professor de matemática , um jogador de futebol e um empresário .
Visto que todos os personagens são pessoas, eles podem andar e falar. No entanto, eles também têm algumas habilidades especiais. Um professor de matemática pode ensinar matemática , um jogador de futebol pode jogar futebol e um empresário pode dirigir um negócio .
Você pode criar individualmente três classes que podem andar, falar e realizar suas habilidades especiais.
Em cada uma das aulas, você estaria copiando o mesmo código para andar e falar para cada personagem.
Se você quiser adicionar um novo recurso - comer, você precisa implementar o mesmo código para cada personagem. Isso pode facilmente tornar-se sujeito a erros (ao copiar) e códigos duplicados.
Seria muito mais fácil se tivéssemos uma Person
aula com recursos básicos como falar, andar, comer, dormir e adicionar habilidades especiais a esses recursos de acordo com nossos personagens. Isso é feito por meio de herança.
Usando herança, agora você não implementar o mesmo código para walk()
, talk()
e eat()
para cada classe. Você só precisa herdá- los.
Portanto, para MathTeacher
(classe derivada), você herda todos os recursos de uma Person
(classe base) e adiciona um novo recurso teachMath()
. Da mesma forma, para a Footballer
classe, você herda todos os recursos da Person
classe e adiciona um novo recurso playFootball()
e assim por diante.
Isso torna seu código mais limpo, compreensível e extensível.
É importante lembrar: Ao trabalhar com herança, cada classe derivada deve satisfazer a condição de " ser " uma classe base ou não. No exemplo acima, MathTeacher
é a Person
, Footballer
é a Person
. Você não pode ter algo como, Businessman
é a Business
.
Herança de Kotlin
Vamos tentar implementar a discussão acima no código:
classe aberta Person (idade: Int) (// código para comer, falar, caminhar) class MathTeacher (age: Int): Person (age) (// outras características do professor de matemática) class Footballer (age: Int): Person ( idade) (// outras características do jogador de futebol) classe Empresário (idade: Int): Pessoa (idade) (// outras características do empresário)
Aqui, Person
é uma classe base, e as classes MathTeacher
, Footballer
e Businessman
são derivadas da classe Person.
Observe, a palavra-chave open
antes da classe base Person
,. É importante.
Por padrão, as aulas em Kotlin são finais. Se você está familiarizado com Java, sabe que uma classe final não pode ser subclassificada. Ao usar a anotação aberta em uma classe, o compilador permite derivar novas classes dela.
Exemplo: Herança 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() )
Quando você executa o programa, a saída será:
Meu nome é Jack. Minha idade é 25 anos, leciono na escola primária. Meu nome é Cristiano. Tenho 29 anos e jogo no LA Galaxy.
Aqui, duas classes MathTeacher
e Footballer
são derivadas da Person
classe.
O construtor primário da Person
classe declarou duas propriedades: idade e nome, e tem um bloco inicializador. O bloco initilizer (e funções de membro) da classe base Person
pode ser acessado pelos objetos de classes derivadas ( MathTeacher
e Footballer
).
Classes derivadas MathTeacher
e Footballer
têm suas próprias funções-membro teachMaths()
e, playFootball()
respectivamente. Essas funções são acessíveis apenas a partir dos objetos de suas respectivas classes.
Quando o objeto t1 da MathTeacher
classe é criado,
val t1 = MathTeacher (25, "Jack")
Os parâmetros são passados para o construtor primário. No Kotlin, o init
bloco é chamado quando o objeto é criado. Como MathTeacher
é derivado da Person
classe, ele procura o bloco inicializador na classe base (Pessoa) e o executa. Se o MathTeacher
bloco de inicialização tivesse, o compilador também teria executado o bloco de inicialização da classe derivada.
Em seguida, a teachMaths()
função para o objeto t1
é chamada usando a t1.teachMaths()
instrução.
O programa funciona de forma semelhante quando o objeto f1
da Footballer
classe é criado. Ele executa o bloco de inicialização da classe base. Então, o playFootball()
método da Footballer
classe é chamado usando a instrução f1.playFootball()
.
Observações importantes: herança de Kotlin
- Se a classe tiver um construtor primário, a base deve ser inicializada usando os parâmetros do construtor primário. No programa acima, ambas as classes derivadas têm dois parâmetros
age
ename
, e esses dois parâmetros são inicializados no construtor primário na classe base.
Aqui está outro exemplo: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") )
- No caso de nenhum construtor primário, cada classe base tem que inicializar a base (usando a palavra-chave super), ou delegar a outro construtor que faça isso. Por exemplo,
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) ( ) )
Substituindo Funções e Propriedades de Membro
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
Você pode chamar funções (e acessar propriedades) da classe base de uma classe derivada usando a super
palavra-chave. Veja como:
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) )
Quando você executa o programa, a saída será:
Minha idade é 31 anos. Minha falsa idade é 26.