Herança e polimorfismo
Explore princípios da orientação a objetos, como herança, classes abstratas e polimorfismo em Scala.
Herança e polimorfismo é uma aula grátis de Scala for Backend Engineering & Functional Programming no CoddyKit. Esta é a aula 2 de 2. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Scala for Backend Engineering & Functional Programming, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Scala for Backend Engineering & Functional Programming inclui 2 aulas no total.
O que é herança?
Herança é um conceito fundamental da Programação Orientada a Objetos (POO) que permite que uma nova classe herde propriedades e comportamentos (métodos) de uma classe existente.
Pense nisso como uma relação entre "pai e filho". A classe "filha" (subclasse) reutiliza código da classe "pai" (superclasse), economizando tempo e garantindo consistência.
- Promove a reutilização de código.
- Estabelece uma relação "é um" (por exemplo, um Dog é um Animal).
- Ajuda a organizar o código em uma hierarquia.
Sua primeira classe-base
Vamos definir uma classe Animal simples. Ela será nossa classe-base, também conhecida como superclasse ou classe-pai. Ela tem um comportamento básico: falar.
Execute o código para ver nosso animal genérico em ação!
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
object Main {
def main(args: Array[String]): Unit = {
val myAnimal = new Animal()
myAnimal.speak()
}
}Estendendo com `extends`
Agora, vamos criar um animal mais específico, um Dog. Um Dog é um Animal, portanto pode herdar da classe Animal usando a palavra-chave extends.
Também podemos substituir o método speak para dar ao Dog seu próprio som. Observe a palavra-chave override.
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
class Dog extends Animal {
override val name: String = "Dog"
override def speak(): Unit = {
println(s"$name barks!")
}
}
object Main {
def main(args: Array[String]): Unit = {
val myAnimal = new Animal()
val myDog = new Dog()
myAnimal.speak() // Generic Animal makes a sound.
myDog.speak() // Dog barks!
}
}O poder de `override`
A palavra-chave override é essencial em Scala por vários motivos:
- Clareza: informa explicitamente a outros desenvolvedores que este método ou campo está substituindo um membro da superclasse.
- Segurança: o compilador verifica se você está realmente substituindo um membro existente. Se você cometer um erro de digitação ou o método da superclasse mudar, o compilador avisará você.
- Intenção: declara claramente sua intenção de especializar ou alterar um comportamento herdado.
Sempre use override ao redefinir membros herdados!
Polimorfismo: muitas formas
Polimorfismo significa "muitas formas". Na POO, ele permite que objetos de classes diferentes sejam tratados como objetos de uma superclasse comum.
Isso significa que você pode ter uma variável do tipo Animal que armazena um objeto Dog, um objeto Cat ou qualquer outra subclasse de Animal. Quando você chama um método nessa variável, o método correto para o tipo real do objeto é executado.
- Permite criar código flexível e extensível.
- Permite uma única interface para diferentes tipos de dados.
- É obtido por meio da substituição de métodos.
Polimorfismo na prática
Vamos ver o polimorfismo em ação. Criaremos uma classe Cat semelhante a Dog. Depois, poderemos colocar diferentes tipos de animais em uma lista do supertipo comum, Animal, e chamar o método speak deles.
Observe como cada animal fala de sua própria maneira, embora todos sejam tratados como tipos Animal na lista.
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
class Dog extends Animal {
override val name: String = "Dog"
override def speak(): Unit = {
println(s"$name barks!")
}
}
class Cat extends Animal {
override val name: String = "Cat"
override def speak(): Unit = {
println(s"$name meows!")
}
}
object Main {
def main(args: Array[String]): Unit = {
val animals: List[Animal] = List(
new Animal(),
new Dog(),
new Cat()
)
animals.foreach(_.speak())
}
}Apresentando classes abstratas
Às vezes, você quer uma classe-base que defina uma interface comum, mas não forneça uma implementação completa para alguns de seus membros. É nesse caso que entram as classes abstratas.
Uma classe abstrata:
- Não pode ser instanciada diretamente (você não pode criar um objeto de uma classe abstrata).
- Pode conter métodos abstratos (métodos sem implementação) e métodos concretos (métodos com implementação).
- Serve como um modelo que suas subclasses devem completar.
Construindo modelos abstratos
Vamos definir uma abstract class Shape. Toda forma tem uma área, mas a fórmula para calculá-la varia para cada forma específica (círculo, retângulo etc.).
Por isso, declaramos area como um método abstrato. Observe que ele não tem corpo (nenhum = { ... }). As subclasses serão responsáveis por fornecer sua implementação.
abstract class Shape {
def area: Double // Abstract method, no implementation
def describe(): Unit = {
println("This is a geometric shape.")
}
}
// You cannot do: new Shape() - it's abstract!
object Main {
def main(args: Array[String]): Unit = {
println("Abstract class Shape defined.")
println("Cannot instantiate Shape directly.")
}
}Implementações concretas
Agora, vamos criar subclasses concretas, como Circle e Rectangle, que estendem nossa abstract class Shape. Essas subclasses devem fornecer uma implementação para o método abstrato area.
Elas também herdam o método concreto describe() de Shape.
abstract class Shape {
def area: Double
def describe(): Unit = {
println("This is a geometric shape.")
}
}
class Circle(radius: Double) extends Shape {
override def area: Double = math.Pi * radius * radius
}
class Rectangle(width: Double, height: Double) extends Shape {
override def area: Double = width * height
}
object Main {
def main(args: Array[String]): Unit = {
val circle = new Circle(5)
val rectangle = new Rectangle(4, 6)
println(s"Circle area: ${circle.area}")
circle.describe()
println(s"Rectangle area: ${rectangle.area}")
rectangle.describe()
}
}Verificação de herança e polimorfismo
Quais das afirmações a seguir sobre herança e polimorfismo em Scala são TRUE?
Recapitulação: herança e polimorfismo
Parabéns! Nesta lição, exploramos conceitos fundamentais da POO em Scala:
- Herança: como as subclasses reutilizam código e definem uma relação "é um" com as superclasses usando
extends. - Palavra-chave
override: essencial para redefinir explicitamente métodos e campos herdados, garantindo segurança de tipos e clareza. - Polimorfismo: a capacidade de tratar objetos de subclasses diferentes como objetos de uma superclasse comum, permitindo um código flexível e extensível.
- Classes abstratas: modelos que não podem ser instanciados diretamente, usados para definir interfaces comuns e membros abstratos que as subclasses devem implementar.
Esses conceitos são essenciais para criar aplicações Scala bem estruturadas e fáceis de manter!
Perguntas Frequentes
A aula “Herança e polimorfismo” é grátis?
Sim — o texto completo de “Herança e polimorfismo” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Scala for Backend Engineering & Functional Programming, atualize para CoddyKit PRO. O curso de Scala for Backend Engineering & Functional Programming inclui 2 aulas no total.
O que vou aprender em “Herança e polimorfismo”?
Explore princípios da orientação a objetos, como herança, classes abstratas e polimorfismo em Scala. Você pratica Scala for Backend Engineering & Functional Programming com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Scala for Backend Engineering & Functional Programming?
Nenhuma experiência prévia é necessária. Scala for Backend Engineering & Functional Programming no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 2.
Quanto tempo leva a aula “Herança e polimorfismo”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Scala for Backend Engineering & Functional Programming?
Sim. Cada aula de Scala for Backend Engineering & Functional Programming inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Classes, objetos e empacotamento
- Herança e polimorfismo