English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Herança no Kotlin

Neste artigo, você aprenderá sobre herança. Mais especificamente, o que é herança e como implementar em Kotlin usando herança (com exemplos).

Herança é uma das funcionalidades principais da programação orientada a objetos. Permite que o usuário crie uma nova classe (classe derivada) a partir de uma classe existente (classe base).

As classes derivadas herdaram todas as funcionalidades da classe base e podem ter outras funcionalidades próprias.

Antes de detalhar a herança em Kotlin, recomenda-se que você leia os seguintes dois artigos:

Por que herança?

Suponha que suas aplicações precisem de três papéis-umprofessor de matemáticaumatleta de futebole umcomerciante (Businessman).

Como todos os papéis são pessoas, eles podem andar e falar. Mas, eles também têm habilidades especiais. O professor de matemática podetreinador de futebol (teachMath)e ojogar futebol(playFootball), o comerciante podeAdministrar negócios (runBusiness).

Você pode criar três classes separadas que podem andar, falar e executar suas habilidades especiais.

Em cada classe, você replicará o mesmo código de caminhada e fala para cada papel.

Se precisar adicionar novas funcionalidades - Para comer (eat), você precisaria implementar o mesmo código para cada papel. Isso facilmente pode levar a erros (ao copiar) e código repetido.

Se tivermos uma classe Person com funcionalidades básicas, por exemplo, andar, comer, dormir e adicionar habilidades especiais para esses funcionalidades com base em nosso papel, isso tornaria tudo mais fácil. Isso é feito através da herança.

Usando herança, você não precisa implementar o mesmo código walk(), talk() e eat() para cada classe. Você só precisaHerançaElas são suficientes.

Portanto, para MathTeacher (classe derivada), você pode herdar todas as funcionalidades da classe Person (classe base) e adicionar uma nova função teachingMath(). Da mesma forma, para a classe Footballer, você herda todas as funcionalidades da classe Person e adiciona a nova função playFootball(), e assim por diante.

Isso torna seu código mais conciso, compreensível e extensível.

É importante lembrar:Ao lidar com herança, cada classe derivada deve atender aos critérios de ser uma 'classe base'. No exemplo acima, MathTeacher é uma Pessoa (pessoa), Footballer é uma Pessoa (pessoa). Você não pode considerar 'comerciante (Businessman) como empresa (Business)'.

Herança em Kotlin

Vamos tentar implementar no código o que discutimos acima:

open class Person(age: Int) {
    //Código para comer, falar e andar
}
class MathTeacher(age: Int): Person(age) {
    //Outras características do professor de matemática
}
class Footballer(age: Int): Person(age) {
    //Outras características do jogador de futebol
}
class Businessman(age: Int): Person(age) {
    // Outras características do comerciante
}

Aqui, Person é a classe base, enquanto as classes MathTeacher, Footballer e Businessman são derivadas da classe Person.

Atenção, a palavra-chave open antes da classe base Person é muito importante.

Por padrão, as classes no Kotlin são finais. Se você estiver familiarizado com Java, saberá que as classes finais não podem ser derivadas. Ao usar a anotação em uma classe, o compilador permite que você derive novas classes dela.

Exemplo: Herança Kotlin

open class Person(age: Int, name: String) {
    init {
        println("Meu nome é $name.")
        println("Minha idade é $age")
    }
}
class MathTeacher(age: Int, name: String): Person(age, name) {
    fun teachMaths() {
        println("Eu ensino na escola primária.")
    }
}
class Footballer(age: Int, name: String): Person(age, name) {
    fun playFootball() {
        println("Eu joguei pelo Los Angeles Galaxy.")
    }
}
fun main(args: Array<String>) {
    val t1 = MathTeacher(25, "Jack")
    t1.teachMaths()
    println()
    val f1 = Footballer(29, "Christiano")
    f1.playFootball()
}

A saída do programa ao executar é:

Meu nome é Jack.
Minha idade é 25
Eu ensino na escola primária.
Meu nome é Cristiano.
Minha idade é 29
Eu joguei pelo Los Angeles Galaxy.

Aqui, duas classes MathTeacher e Footballer são derivadas da classe Person.

O construtor principal da classe Person declara duas propriedades: age e name, e possui um bloco de inicialização. Os objetos das classes derivadas de Person (MathTeacher e Footballer) podem acessar o bloco de inicialização (e os métodos) da classe base.

As classes MathTeacher e Footballer têm seus próprios métodos membros teachMaths() e playFootball(). Esses métodos podem ser acessados apenas pelos objetos de suas próprias classes.

ao criar um objeto da classe MathTeacher t1 ao invés de

val t1 = MathTeacher(25, "Jack")

os parâmetros serão passados para o construtor principal. No Kotlin, ao criar um objeto, é chamado o bloco init. Como o MathTeacher é derivado da classe Person, ele encontrará e executará o bloco de inicialização na classe base (Person). Se o MathTeacher tiver um bloco init, o compilador também executará o bloco de inicialização da classe derivada.

Em seguida, usando t1.teachMaths() chama a função teachMaths() do objeto t1função teachMaths().

criar um objeto da classe f1 ao invés de1.playFootball() chama o método playFootball() da classe Footballer.

Nota importante: Herança em Kotlin

  • Se a classe tiver um construtor primário, deve usar os parâmetros do construtor primário para inicializar a classe base. No programa acima, os dois subclasses têm dois parâmetros age e name, e esses parâmetros estão inicializados no construtor principal da classe base.
    Este é outro exemplo:

    open class Person(age: Int, name: String) {
        // algum código
    }
    class Footballer(age: Int, name: String, club: String): Person(age, name) {
        init {
            println("O jogador de futebol de $age anos, $name, joga pelo $club.")
        }
        fun playFootball() {
            println("Estou jogando futebol.")
        }
    }
    fun main(args: Array<String>) {
        val f1 = Footballer(29, "Cristiano", "LA Galaxy")
    }

      Aqui, o construtor principal da classe derivada possui3parâmetros, enquanto a classe base possui2parâmetros. Observe que os dois parâmetros da classe base já foram inicializados.

  • Se não houver construtor primário, cada classe base deve inicializar a classe base (usando a palavra-chave super) ou delegar a outro construtor que execute essa operação. Por exemplo

    fun main(args: Array<String>) {
        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 vezes")
        }
    }
    class AuthLog: Log {
        constructor(_data: String): this("From AuthLog -> + $_data", 10) {
        }
        constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
        }
    }

      Para obter mais informações sobre como o programa funciona, acesseConstrutor secundário do Kotlin.

Sobrescrever função de membro e propriedade

Se a classe base e a classe derivada contiverem membros com o mesmo nome (ou propriedades), pode ser necessário usar a palavra-chave override para sobrescrever a função do membro da classe derivada e usar a palavra-chave open para a função do membro da classe base.

Exemplo: Sobrescrever função de membro

// Construtor principal vazio
open class Person() {
    open fun displayAge(age: Int) {
        println("Minha idade é $age.")
    }
}
class Girl: Person() {
    override fun displayAge(age: Int) {}}
        println("Minha idade virtual é ${age - 5}.
    }
}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
}

A saída do programa ao executar é:

sua idade virtual é 26.

Aqui, girl.displayAge(31) Chame o método displayAge() da classe derivada Girl.

Você pode sobrescrever atributos da classe base de uma forma semelhante.

Antes de aprender os seguintes exemplos, você pode acessar Getter e Setter no Kotlin Veja como funciona.

//Construtor principal vazio
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<String>) {
    val girl = Girl()
    girl.age = 31
    println("Minha idade virtual é ${girl.age}.")
}

A saída do programa ao executar é:

Minha idade virtual é 26.

Como você vê, usamos as palavras-chave override e open para a propriedade age tanto na classe derivada quanto na classe base.

Chamada de membros da classe base a partir da classe derivada

Você pode usar a palavra-chave super para chamar funções da classe base a partir da classe derivada (e acessar atributos). Veja como fazer:

open class Person() {
    open fun displayAge(age: Int) {
        println("Minha idade real é $age.")
    }
}
class Girl: Person() {
    override fun displayAge(age: Int) {}}
        //Chamada de função da classe base
        super.displayAge(age)
        
        println("Minha idade virtual é ${age - 5}.
    }
}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
}

A saída do programa ao executar é:

Minha idade real é 31.
Minha idade virtual é 26.