Estude novamente o exemplo de polígono a seguir, que foi trabalhado na aula de polimorfismo. Observe que na classe Poligono
o método getArea()
não faz sentido, já que se trata de uma abstração de polígono que não tem área. Entretanto, ele teve que ser declarado para permitir o polimorfismo desse método, ou seja, para que fosse possível declarar uma referência para Poligono
e, mesmo assim, se realizar a chamada para o método getArea()
nas subclasses.
In [1]:
public class Poligono {
private int altura;
private int largura;
public Poligono(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getArea() {
return 0;
}
}
Out[1]:
In [2]:
public class TrianguloRetangulo extends Poligono {
public TrianguloRetangulo(int altura, int largura) {
super(altura, largura);
}
public float getArea() {
return getAltura() * getLargura() / 2;
}
}
Out[2]:
In [3]:
public class Retangulo extends Poligono {
public Retangulo(int altura, int largura) {
super(altura, largura);
}
public float getArea() {
return getAltura() * getLargura();
}
}
Out[3]:
In [4]:
Poligono tr = new TrianguloRetangulo(6, 10);
Poligono rt = new Retangulo(6, 10);
System.out.println("Área do triangulo retângulo: " + tr.getArea());
System.out.println("Área do retângulo: " + rt.getArea());
Out[4]:
Essa estratégia de declarar métodos na superclasse que só serão definidos nas subclasses é comum. Nesses casos, a superclasse é tida como uma abstração, que declara interfaces de métodos potenciais, cuja implementação faz sentido nas subclasses.
Para esses casos o Java dispõe do recurso de Classe Abstrata.
Uma classe abstrata é declarada usando-se a cláusula abstract
antes do class
. No caso do Poligono
seria:
public abstract class Poligono
Uma classe abstrata ganha a possibilidade de declarar Métodos Abstratos, que são métodos apneas com a assinatura mas sem implementação. Esses métodos serão obrigatoriamente implementados pelos herdeiros, a menos que os herdeiros também os declare como abstratos, repassando a responsabilidade para a geração seguinte (nesse caso as respectivas classes herdeiras também serão abstratas).
O método getArea()
pode se tornar abstrato da seguinte maneira:
public abstract float getArea();
Apenas as classes abstratas podem ter métodos abstratos.
Nenhuma classe abstrata pode ser instanciada, ou seja, todos os métodos abstratos terão que ser obrigatoriamente implementados por alguém para que se possa instanciar a respectiva classe.
Veja abaixo como o Poligono
foi reimplementado:
In [5]:
public abstract class Poligono {
private int altura;
private int largura;
public Poligono(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public abstract float getArea();
}
Out[5]:
In [6]:
public class TrianguloRetangulo extends Poligono {
public TrianguloRetangulo(int altura, int largura) {
super(altura, largura);
}
public float getArea() {
return getAltura() * getLargura() / 2;
}
}
Out[6]:
In [7]:
public class Retangulo extends Poligono {
public Retangulo(int altura, int largura) {
super(altura, largura);
}
public float getArea() {
return getAltura() * getLargura();
}
}
Out[7]:
In [8]:
Poligono tr = new TrianguloRetangulo(6, 10);
Poligono rt = new Retangulo(6, 10);
System.out.println("Área do triangulo retângulo: " + tr.getArea());
System.out.println("Área do retângulo: " + rt.getArea());
Out[8]:
É possível se pensar em funcionalidades no nível abstrato que se baseiam na previsão do que será implementado nas subclasses.
A seguir é apresentada a classe ListStr
que representa uma lista de forma abstrata as seguintes duas operações:
first()
- se desloca para a primeira posição da lista e retorna o primeiro elemento (retorna nulo se não houver primeiro);next()
- se desloca para a próxima posição da lista e retorna o próximo elemento (retorna nulo se não houver próximo).Note que foi implementado um método list()
que parte do pré-suposto de que existe uma implementação de first()
e next()
. Isso faz com que você possa implementar a lista de várias maneiras e o método list()
se adapte automaticamente às implementações dos herdeiros.
Implemente uma classe herdeita de ListStr
(não abstrata) que armazene uma lista de dados e implemente os métodos first()
e next()
. Escreva uma sequência de instruções que use a sua lista.
In [9]:
public abstract class ListStr {
public abstract String first();
public abstract String next();
public void list() {
String element = first();
while (element != null) {
System.out.println(element);
element = next();
}
}
}
Out[9]:
In [ ]: