As classes incorporam duas funções interligadas:
Já vimos anteriormente alguns problemas de usar somente a herança como mecanismo de reúso. O mesmo acontece com a interface. Muitas vezes queremos que objetos compartilhem a mesma interface, sem que usem a herança para isso.
Por essa razão o Java define o mecanismo chamado interface
. Ele permite a declaração de um interface que será garantida por um conjunto de classes, sem a necessidade que elas estejam ligadas por herança.
Considere as duas classes a seguir que representam formas geométricas. Ambas oferecem métodos para cálculo do perímetro e área, entretanto, não compartilham código.
Suponha que se deseja padronizar o acesso às interfaces de ambos objetos resolvendo a chamada de métodos de modo polimórfico. É possível se fazer isso sem herança, como será apresentado no próximo bloco.
In [1]:
public class Retangulo {
private int altura;
private int largura;
public Retangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getPerimetro() {
return 2 * (altura + largura);
}
public float getArea() {
return altura * largura;
}
}
Out[1]:
In [2]:
public class Circulo {
public static float PI = 3.1416f;
private int raio;
public Circulo(int raio) {
this.raio = raio;
}
public int getRaio() {
return raio;
}
public float getPerimetro() {
return 2 * Circulo.PI * raio;
}
public float getArea() {
return Circulo.PI * raio * raio;
}
}
Out[2]:
In [3]:
Retangulo rt = new Retangulo(6, 10);
System.out.println("Perímetro do retângulo: " + rt.getPerimetro());
System.out.println("Área do retângulo: " + rt.getArea());
Circulo cc = new Circulo(8);
System.out.println("Perímetro do círculo: " + cc.getPerimetro());
System.out.println("Área do círculo: " + cc.getArea());
Out[3]:
interface
Uma interface
em Java declara um conjunto de métodos que deverão ser implementados por todas as classes que implementa a interface. A seguinte declaração da interface Geometria
:
public interface Geometria {
public float getPerimetro();
public float getArea();
}
Indica que todos as classes que a implementarem precisarão implementar getPerimetro()
e getArea()
com as assinaturas indicadas.
Qualquer classe pode indicar que implementará a interface Geometria
com a cláusula implements
. Uma vantagem das interfaces sobre a herança (quando a intenção é padronizar a interface) é que uma classe pode implementar várias interfaces.
A seguinte declaração:
Geometria g;
Define uma variável g
que é capaz de manter uma referência para qualquer objeto de classe que implementa a interface Geometria
. Por essa razão são permitidas as instanciações:
Geometria g = new Retangulo(6, 10);
g = new Circulo(8);
Pode-se chamar qualquer método declarado da interface Geometria
e a execução é polimórfica, ou seja, depende da instância.
In [4]:
public interface Geometria {
public float getPerimetro();
public float getArea();
}
Out[4]:
In [5]:
public class Retangulo implements Geometria {
private int altura;
private int largura;
public Retangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getPerimetro() {
return 2 * (altura + largura);
}
public float getArea() {
return altura * largura;
}
}
Out[5]:
In [6]:
public class Circulo implements Geometria {
public static float PI = 3.1416f;
private int raio;
public Circulo(int raio) {
this.raio = raio;
}
public int getRaio() {
return raio;
}
public float getPerimetro() {
return 2 * Circulo.PI * raio;
}
public float getArea() {
return Circulo.PI * raio * raio;
}
}
Out[6]:
In [7]:
Geometria g = new Retangulo(6, 10);
System.out.println("Perímetro do retângulo: " + g.getPerimetro());
System.out.println("Área do retângulo: " + g.getArea());
g = new Circulo(8);
System.out.println("Perímetro do círculo: " + g.getPerimetro());
System.out.println("Área do círculo: " + g.getArea());
Out[7]:
As classes abstratas e interfaces têm uma sobreposição de funções. Alguns são levados a acreditar que uma interface é uma classe com todos os métodos abstratos.
Para entender as diferenças, retome a classe abstrata ListStr
cuja herdeira você implementou mo notebook de classes abstratas. Se você transformar ListStr
na interface IListStr
com o intuito de não usar mais classes abstratas, escreva abaixo como ficaria o código da interface e o código modificado das classes. Escreva uma sequência de instruções que usem a interface e as respectivas classes.
In [ ]:
Por um lado, você notará que não é possível se implementar nenhum método na interface, o que impede de criar abordagem de métodos que usam outros métodos potenciais abstratos, como é o caso do list()
. Isso é uma vantagem das classes abstratas que você terá que simular de outro modo.
Por outro lado, uma classe pode ter inúmeras interfaces mas só pode ser herdeira de uma classe abstrata, o que limita o poder dessas classes de agir como padronizador de interfaces.
In [8]:
public class EmprestimoSimples {
float s;
int n;
float j;
int corrente;
float p;
EmprestimoSimples(float s, int n, float j) {
this.s = s;
this.n = n;
this.j = j;
corrente = 0;
this.p = s;
}
float proximaParcela() {
corrente++;
return (corrente <= n) ? p + (p * (j/100)) : 0;
}
}
Out[8]:
In [9]:
public class EmprestimoComposto {
float s;
int n;
float j;
int corrente;
float p;
EmprestimoComposto(float s, int n, float j) {
this.s = s;
this.n = n;
this.j = j;
corrente = 1;
this.p = s;
}
float proximaParcela() {
float retorno = p;
corrente++;
if (corrente <= n)
p = p + (p * (j/100));
else
p = 0;
return retorno;
}
}
Out[9]:
In [10]:
EmprestimoSimples empS = new EmprestimoSimples(200, 5, 1);
EmprestimoComposto empC = new EmprestimoComposto(200, 5, 1);
int i = 1;
float ps = empS.proximaParcela();
float pc = empC.proximaParcela();
while (ps > 0 || pc > 0) {
if (ps > 0)
System.out.println("Emprestimo simples: parcela " + i + " eh " + ps);
if (pc > 0)
System.out.println("Emprestimo composto: parcela " + i + " eh " + pc);
ps = empS.proximaParcela();
pc = empC.proximaParcela();
i++;
}
Out[10]:
Interface
como ParâmetroConsidere o novo cenário a seguir em que é definida uma interface
para as classes Retangulo
e TrianguloRetangulo
utilizadas no notebook sobre classes abstratas. Neste caso, não há mecanismo de herança envolvida.
O método sameProportions
recebe um objeto que implementa a interface Retangular
, ou seja, pode se comparar com qualquer objeto que implementa essa interface:
public boolean sameProportions(Retangular toCompare)
A classe Retangulo
implementa duas interfaces:
public class Retangulo implements Geometria, Retangular
In [11]:
public interface Retangular {
public int getAltura();
public int getLargura();
public boolean sameProportions(Retangular toCompare);
}
Out[11]:
In [12]:
public class TrianguloRetangulo implements Retangular {
private int altura;
private int largura;
public TrianguloRetangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getArea() {
return getAltura() * getLargura() / 2;
}
public boolean sameProportions(Retangular toCompare) {
return (largura / altura == toCompare.getLargura() / toCompare.getAltura());
}
}
Out[12]:
In [13]:
public class Retangulo implements Geometria, Retangular {
private int altura;
private int largura;
public Retangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getPerimetro() {
return 2 * (altura + largura);
}
public float getArea() {
return altura * largura;
}
public boolean sameProportions(Retangular toCompare) {
return (largura / altura == toCompare.getLargura() / toCompare.getAltura());
}
}
Out[13]:
In [14]:
Retangular tr = new TrianguloRetangulo(60, 100);
Retangular rt = new Retangulo(6, 10);
System.out.println("Medidas do triangulo retângulo - altura: " +
tr.getAltura() + "; largura: " + tr.getLargura());
System.out.println("Medidas do retângulo - altura: " +
rt.getAltura() + "; largura: " + rt.getLargura());
if (tr.sameProportions(rt))
System.out.println("Ambos têm as mesmas proporções");
else
System.out.println("Ambos têm proporções diferentes");
Out[14]:
In [15]:
public interface Geometria {
public float getPerimetro();
public float getArea();
}
Out[15]:
In [16]:
public interface Retangular extends Geometria {
public int getAltura();
public int getLargura();
public boolean sameProportions(Retangular toCompare);
}
Out[16]:
In [17]:
public class Retangulo implements Retangular {
private int altura;
private int largura;
public Retangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getPerimetro() {
return 2 * (altura + largura);
}
public float getArea() {
return altura * largura;
}
public boolean sameProportions(Retangular toCompare) {
return (largura / altura == toCompare.getLargura() / toCompare.getAltura());
}
}
Out[17]:
In [18]:
public class TrianguloRetangulo implements Retangular {
private int altura;
private int largura;
public TrianguloRetangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getPerimetro() {
return (float) (altura + largura + Math.sqrt(altura * altura + largura * largura));
}
public float getArea() {
return getAltura() * getLargura() / 2;
}
public boolean sameProportions(Retangular toCompare) {
return (largura / altura == toCompare.getLargura() / toCompare.getAltura());
}
}
Out[18]:
In [19]:
Retangular rt = new Retangulo(6, 10);
Retangular tr = new TrianguloRetangulo(60, 100);
System.out.println("Medidas do retângulo - altura: " +
rt.getAltura() + "; largura: " + rt.getLargura());
System.out.println("Medidas do triangulo retângulo - altura: " +
tr.getAltura() + "; largura: " + tr.getLargura());
System.out.println("Perímetro do retângulo: " + rt.getPerimetro());
System.out.println("Área do retângulo: " + rt.getArea());
System.out.println("Perímetro do triângulo retângulo: " + tr.getPerimetro());
System.out.println("Área do triângulo retângulo: " + tr.getArea());
if (tr.sameProportions(rt))
System.out.println("Ambos têm as mesmas proporções");
else
System.out.println("Ambos têm proporções diferentes");
Out[19]:
In [20]:
public interface Geometria {
public float getPerimetro();
public float getArea();
}
Out[20]:
In [21]:
public interface Retangular {
public int getAltura();
public int getLargura();
public boolean sameProportions(Retangular toCompare);
}
Out[21]:
In [22]:
public interface GeometriaRetangular extends Geometria, Retangular {
}
Out[22]:
In [23]:
public class Circulo implements Geometria {
public static float PI = 3.1416f;
private int raio;
public Circulo(int raio) {
this.raio = raio;
}
public int getRaio() {
return raio;
}
public float getPerimetro() {
return 2 * Circulo.PI * raio;
}
public float getArea() {
return Circulo.PI * raio * raio;
}
}
Out[23]:
In [24]:
public class Retangulo implements GeometriaRetangular {
private int altura;
private int largura;
public Retangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getPerimetro() {
return 2 * (altura + largura);
}
public float getArea() {
return altura * largura;
}
public boolean sameProportions(Retangular toCompare) {
return (largura / altura == toCompare.getLargura() / toCompare.getAltura());
}
}
Out[24]:
In [25]:
public class TrianguloRetangulo implements Retangular {
private int altura;
private int largura;
public TrianguloRetangulo(int altura, int largura) {
this.altura = altura;
this.largura = largura;
}
public int getAltura() {
return altura;
}
public int getLargura() {
return largura;
}
public float getArea() {
return getAltura() * getLargura() / 2;
}
public boolean sameProportions(Retangular toCompare) {
return (largura / altura == toCompare.getLargura() / toCompare.getAltura());
}
}
Out[25]:
In [26]:
GeometriaRetangular rt = new Retangulo(6, 10);
System.out.println("Medidas do retângulo - altura: " +
rt.getAltura() + "; largura: " + rt.getLargura());
System.out.println("Perímetro do retângulo: " + rt.getPerimetro());
System.out.println("Área do retângulo: " + rt.getArea());
Geometria ci = new Circulo(8);
System.out.println("Perímetro do círculo: " + ci.getPerimetro());
System.out.println("Área do círculo: " + ci.getArea());
Retangular tr = new TrianguloRetangulo(60, 100);
System.out.println("Medidas do triangulo retângulo - altura: " +
tr.getAltura() + "; largura: " + tr.getLargura());
if (tr.sameProportions(rt))
System.out.println("Retângulo e triângulo retângulo têm as mesmas proporções");
else
System.out.println("Retângulo e triângulo retângulo têm proporções diferentes");
Out[26]:
ConjuntoEmprestimos
Baseado no notebook sobre polimorfismo, construa uma classe denominada ConjuntoEmprestimos
que é responsável por controlar um conjunto de empréstimos que podem ser simples ou compostos. Essa classe deve definir pelo menos os seguintes métodos:
construtor
- recebe como parâmetro o número máximo de empréstimos;adicionaEmprestimo
- recebe como parâmetro um empréstimo (simples ou composto) e o armazena (se não ultrapassar o número máximo);proximasParcelas
- mostra as próximas parcelas de todos os empréstimos cadastrados (para fins de simplificação, considere que o número da próxima parcela é igual para todos); o método retorna um status de verdadeiro se houve pelo menos um empréstimo com próxima parcela.Utilize uma interface para generalizar o tratamento de empréstimo. É possível se criar um vetor de interfaces.
In [ ]: