Classes e Métodos Abstratos
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 32 de 87.
Às vezes, você deseja definir uma classe que sirva como um modelo, mas que nunca deva ser instanciada diretamente. Por exemplo, uma classe Shape genérica faz sentido como uma classe pai, mas como seria uma "forma" sem uma forma específica? É aqui que as classes abstratas entram.
Uma classe abstrata é declarada com a palavra-chave abstract e não pode ser instanciada. Ela pode conter tanto métodos regulares com implementações quanto métodos abstratos que não possuem corpo:
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Método abstrato - sem implementação
public abstract double getArea();
// Método regular - possui implementação
public String getColor() {
return color;
}
}Métodos abstratos declaram o que uma subclasse deve fazer, mas não como. Qualquer classe não abstrata que estenda uma classe abstrata deve fornecer implementações para todos os métodos abstratos:
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}Você ainda pode usar classes abstratas como tipos de referência, permitindo o polimorfismo:
Shape shape = new Circle("red", 5.0);
System.out.println(shape.getArea()); // Chama a implementação do CircleClasses abstratas são ideais quando subclasses compartilham código comum, mas cada uma deve implementar certos comportamentos de forma diferente. Elas impõem um contrato enquanto permitem a reutilização de código.
Desafio
FácilVamos construir um sistema de eletrodomésticos que demonstra o poder das classes abstratas. Você criará uma classe base Appliance que define o que cada eletrodoméstico deve fazer, permitindo que tipos específicos de eletrodomésticos decidam exatamente como fazê-lo.
Você organizará seu código em quatro arquivos:
Appliance.java: Crie uma classe abstrata que sirva como modelo para todos os eletrodomésticos. Todo eletrodoméstico possui um campobrand(String) e um campowattage(int). Inclua um construtor que inicialize ambos os campos, métodos getter para cada um e um método regulargetInfo()que retorna:[brand] - [wattage]W. Defina um método abstratooperate()que as subclasses devem implementar - isso representa como cada eletrodoméstico realiza sua função principal.WashingMachine.java: Crie uma classe concreta que estende Appliance. Máquinas de lavar têm um campo adicionalcapacity(int) representando o tamanho da carga em kg. Usesuperpara lidar com a inicialização do pai. Implemente o métodooperate()para imprimir:[brand] washing machine is washing [capacity]kg of clothesMicrowave.java: Crie outra classe concreta que estende Appliance. Micro-ondas têm um campopower(int) representando a porcentagem do nível de potência. Implementeoperate()para imprimir:[brand] microwave is heating at [power]% powerMain.java: Reúna tudo usando polimorfismo. Você receberá cinco entradas: um nome de marca, potência, capacidade da máquina de lavar, outro nome de marca e nível de potência do micro-ondas. Crie uma WashingMachine e um Microwave, então armazene-os em um array de referências deAppliance. Percorra o array e, para cada eletrodoméstico, imprima suas informações usandogetInfo()seguido pela chamada deoperate().
Você receberá cinco entradas nesta ordem: primeira marca (String), primeira potência (int), capacidade em kg (int), segunda marca (String) e nível de potência (int).
Sua saída deve mostrar quatro linhas - para cada eletrodoméstico, você verá sua linha de informações seguida por seu comportamento de operação. Observe como a classe abstrata permite tratar diferentes eletrodomésticos de forma uniforme, enquanto cada um opera de sua maneira única!
Folha de consulta
Uma classe abstrata é declarada com a palavra-chave abstract e não pode ser instanciada diretamente. Ela serve como um modelo para subclasses:
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Método abstrato - sem implementação
public abstract double getArea();
// Método regular - possui implementação
public String getColor() {
return color;
}
}Métodos abstratos não possuem corpo e devem ser implementados por subclasses não abstratas:
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}Classes abstratas podem ser usadas como tipos de referência para polimorfismo:
Shape shape = new Circle("red", 5.0);
System.out.println(shape.getArea()); // Chama a implementação de CircleClasses abstratas são ideais quando as subclasses compartilham código comum, mas devem implementar certos comportamentos de forma diferente.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Ler as entradas
String brand1 = scanner.nextLine();
int wattage1 = scanner.nextInt();
int capacity = scanner.nextInt();
scanner.nextLine(); // consumir a quebra de linha
String brand2 = scanner.nextLine();
int power = scanner.nextInt();
// TODO: Criar um objeto WashingMachine com brand1, wattage1 e capacity
// TODO: Criar um objeto Microwave com brand2, wattage1 (ou a potência apropriada) e power
// TODO: Criar um array de referências Appliance e armazenar ambos os objetos
// TODO: Percorrer o array e para cada eletrodoméstico:
// - Imprimir suas informações usando getInfo()
// - Chamar operate()
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator