Programação por Objectos Java Parte 7: Interfaces MEEC@IST Java – 1/31 Interfaces – revisão (1) • Uma interface é um conjunto de protótipos de métodos (sem implementações) que especifica um serviço bem definido: – As interfaces não podem conter atributos, mas podem conter constantes. – A implementação duma interface é realizada pela classe concreta. Na implementação ou concretização: • Determina-se os atributos necessários à correcta implementação da interface. • Descreve-se o código dos métodos das interface. MEEC@IST Java – 2/31 Interfaces – revisão (2) – Uma interface pode herdar as definições de outra interface. • Interfaces podem usar polimorfismo. • Se uma classe concretizar mais de uma interface, e várias interfaces contiverem métodos com a mesma assinatura, basta definir uma única implementação. – Uma interface não pode ser instanciada. MEEC@IST Java – 3/31 Interfaces (1) • Tanto as classes como as interfaces definem tipos (a unidade fundamental da programação OO). • Em Java, uma classe só pode estender uma outra classe, mas pode implementar uma ou mais interfaces. • Para uma dada classe, as classes estendidas e as interfaces implementadas são denominadas supertipos. A classe em si é denominada o subtipo. • Uma referência para um objecto do subtipo pode ser usada sempre que uma referência para um objecto dos seus supertipos (classes ou interfaces) é necessária. MEEC@IST Java – 4/31 Interfaces (2) • O Java disponibiliza um conjunto de interfaces, de onde se destaca: – Comparable: objectos deste tipo têm uma ordem associada que os permite comparar. – Iterable: objectos deste tipo disponibilizam um iterador, e portanto podem ser usadas no ciclo for-each. • Collection: objectos deste tipo conseguem guardar outros objectos. – Set, List, Queue, … MEEC@IST Java – 5/31 Interfaces (3) Sintaxe Qualif* interface Ident [ extends IdentI [, IdentI ]*] { [ QualifC* Tipo IdentC = expressão; ] * [ QualifM* Tipo IdentM ( [TipoP IdentP [, TipoP IdentP ]*); ]* } • Qualif: qualificador (visibilidade, entre outros) • Ident: identificador da interface • extends IdentI: especialização de interface MEEC@IST Java – 6/31 Interfaces (4) • Qualificadores de interface: – public: interface publicamente acessível. – abstract: a interface não pode ser instanciada. • Por omissão do qualificador public, uma interface é apenas acessível no pacote onde está definida. MEEC@IST Java – 7/31 Interfaces (5) • Todas as interfaces são implicitamente abstract. Por convenção, o qualificador abstract é omitido. • Todos os membros são implicitamente public. Por convenção, o qualificador public é omitido. • Todas as constantes são implicitamente public static final. Por convenção, os qualificadores são omitidos. • Todos os métodos são implicitamente public abstract. Por convenção, os qualificadores são omitidos. • Nenhum outro qualificador é permitido às contantes e métodos duma interface. MEEC@IST Java – 8/31 Interfaces (6) public interface Pilha { //métodos boolean vazia(); Object topo(); boolean adicionar(Object o); void remover(); } MEEC@IST Java – 9/31 Herança de interfaces (1) • Uma interface pode estender mais que uma interface. • As interfaces que são estendidas são denominadas superinterfaces, enquanto que a nova interface é denominada subinterface. • Uma subinterface herda todas as constantes declaradas nas suas superinterfaces. • Se uma subinterface declara uma constante com o mesmo nome que uma constante herdada (independentemente do tipo), a constante da subinterface esconde a constante herdada. • Na subinterface a constante herdada é acedida apenas pelo seu nome qualificado (superinterface.constante). MEEC@IST Java – 10/31 Herança de interfaces (2) interface X { int val = 1; String strx = “X”; } interface Y extends X { int val = 2; int sum = val + X.val; String stry = “Y extends” + strx; } MEEC@IST Java – 11/31 Herança de interfaces (3) • Se uma interface herda duas ou mais constantes com o mesmo nome, qualquer referência simples a essa constante é ambígua e resulta num erro de compilação. interface A { String str = “A”; } interface B extends A { String str = “B”; } interface D extends B, C { String d = str; } interface C extends A { String str = “C”; } interface D extends B, C { String d = A.str+B.str+C.str; } Erro de compilação: qual str? MEEC@IST Java – 12/31 Herança de interfaces (4) • Uma subinterface herda todos os métodos declarados nas suas superinterfaces. • Se uma subinterface declara um método com a mesma assinatura, a menos de um retorno covariante, que um ou mais métodos herdados, o método da subinterface é uma redefinição dos métodos herdados. • Se uma subinterface herda mais do que um método com a mesma assinatura, a menos de um retorno covariante, a subinterface contém apenas um método – o método que retorna o subtipo comum. MEEC@IST Java – 13/31 Herança de interfaces (5) • Se um método da subinterface difere apenas no tipo de retorno de um método herdado, ou se dois métodos herdados diferem apenas no tipo de retorno, e estes retornos não são covariantes, há um erro de compilação. • Se um método tem o mesmo nome, mas diferentes parâmetros que um método herdado, o método é uma sobreposição do método herdado. MEEC@IST Java – 14/31 Herança de interfaces (6) interface X { void xpto(); Number foo1(); Number foo2(); } interface Y { Object foo1(); Object foo2(); } interface Z extends X, Y { void xpto(String s); Integer foo1(); } • Métodos da interface Z: – – – – MEEC@IST public public public public void xpto() void xpto(String) Integer foo1() Number foo2() Java – 15/31 Implementação de interfaces (1) • Uma classe identifica as interfaces que implementa, listando-as a seguir à palavra chave implements. Sintaxe (revisão) Qualif* class Ident [ extends IdentC] [ implements IdentI [,IdentI]* ] { [ Decl_atributos | Métodos ]* } MEEC@IST Java – 16/31 Implementação de interfaces (2) • As interfaces que uma classe implementa são denominadas as superinterfaces da classe. • A classe deve disponibilizar uma implementação para todos os métodos definidos nas suas superinterfaces, senão a classe tem de ser declarada abstract. MEEC@IST Java – 17/31 Implementação de interfaces (3) • Quando um classe implementa uma interface, a classe pode aceder às constantes definidas na interface como se tivessem sido declaradas na classe. • Uma classe que implementa mais do que uma interface, ou que estende uma classe e implementa uma ou mais interfaces, sofre dos mesmo problemas de constantes escondidas e ambiguidade que uma interface que estende mais de uma interface (ver slides 10, 11 e 12). MEEC@IST Java – 18/31 Implementação de interfaces (4) interface X { int val = 1; String strx = “X”; } interface Y extends X { int val = 2; int sum = val + X.val; String stry = “Y extends ” + strx; } class Z implements Y { int val = 3; } Z z = new Z(); System.out.println( “z.val=” + z.val + “ ((Y)z).val=” + ((Y)z).val + /* ou Y.val */ “ ((X)z).val=” + ((X)z).val) /* ou X.val */; System.out.println(“z.strx=” + z.strx + “ z.stry=” + z.stry; No terminal é impresso MEEC@IST z.val=3 ((Y)z).val=2 ((X)z).val=1 strx=X stry=Y extends X Java – 19/31 Implementação de interfaces (5) interface A { String str = “A”; } interface B extends A { String str = “B”; } class D implements B, C { String d = str; } interface C extends A { String str = “C”; } class D implements B, C { String d = A.str+B.str+C.str; } Erro de compilação: qual str? MEEC@IST Java – 20/31 Implementação de interfaces (6) • Se uma classe implementa várias interfaces com mais do que um método com a mesma assinatura a classe contém apenas um tal método. • Se uma classe implementa várias interfaces com mais do que um método com a mesma assinatura, a menos de um retorno covariante, a implementação deve definir o método que retorna o subtipo comum (caso contrário resulta num erro de compilação). • Se uma classe implementa várias interfaces com mais do que um método que difere apenas no tipo de retorno, e estes retornos não são covariantes, há um erro de compilação. MEEC@IST Java – 21/31 Implementação de interfaces (7) interface X { void xpto(); Number foo1(); Number foo2(); } interface Z extends X, Y { void xpto(String s); Integer foo1(); } interface Y { Object foo1(); Object foo2(); } class ClasseZ implements Z { public void xpto() {...} public void xpto(String s) {...} public Integer foo1() {...} public Number foo2() {...} } É importante identificar os métodos a implementar de uma interface: se a ClasseZ não disponibilizar a implementação para todos os métodos definidos nas suas superinterfaces tem de ser declarada abstract (ver slide 17). MEEC@IST Java – 22/31 Implementação de interfaces (8) • A implementação da interface Pilha pode ser feita de diferentes maneiras: – Baseada numa tabela: PilhaComTabela – Baseada numa lista ligada: PilhaComLista • A interface Pilha corresponde ao tipo de dados abstracto, enquanto que ambas as classes PilhaComTabela e PilhaComLista correspondem ao tipo de dados implementado de duas formas diferentes. MEEC@IST public interface Pilha { //métodos boolean vazia(); Object topo(); boolean adicionar(Object obj); void remover(); } Java – 23/31 Implementação de interfaces (9) public class PilhaComTabela implements Pilha { private final int MAX; private Object pilha[]; private int posLivre; // primeira posição livre public PilhaComTabela(int max) { MAX = max; pilha = new Object[MAX]; posLivre = 0; } public boolean vazia() { return posLivre==0; } public Object topo() { return posLivre>0 ? pilha[posLivre-1] : null; } MEEC@IST Java – 24/31 Implementação de interfaces (10) //continuação do slide anterior... public boolean adicionar(Object obj){ if (posLivre<MAX-1){ pilha[posLivre++] = obj; return true; } return false; } public void remover() { if (posLivre>0) pilha[--posLivre] = null; } public int numMaxElementos() { return MAX; } } MEEC@IST Java – 25/31 Implementação de interfaces (11) public class PilhaComLista implements Pilha { private ElementoPilha base; private int numElementos; public PilhaComLista(){ base = null; numElementos = 0; } public boolean vazia() { return numElementos==0; } public Object topo() { return base!=null ? base.elemento : null; } MEEC@IST Java – 26/31 Implementação de interfaces (12) //continuação do slide anterior... public boolean adicionar(Object obj){ base = new ElementoPilha(obj,base); numElementos++; return true; } public void remover() { if (base!=null) { base = base.proximo; numElementos--; } } public int numElementos() { return numElementos; } } MEEC@IST Java – 27/31 Implementação de interfaces (13) public class ElementoPilha { Object elemento; ElementoPilha proximo; public ElementoPilha(Object elem, ElementoPilha prox){ elemento = elem; proximo = prox; } } MEEC@IST Java – 28/31 Implementação de interfaces (14) • Definindo as interfaces um tipo, é possível declarar variáveis com o seu tipo: Pilha p = new PilhaComTabela(100); • Contudo, referências para um tipo de interface, só podem ser usadas para aceder a membros da própria interface: p.adicionar(new Integer(100)); p.adicionar(new Character(‘a’)); p.remover(); int max = p.numMaxElementos(); //INVÁLIDO!!! • Para contornar este problema pode usar-se um cast: int max = ((PilhaComTabela)p).numMaxElementos(); MEEC@IST Java – 29/31 Implementação de interfaces (15) • É possível chamar qualquer método de Object com uma referência para um tipo de interface: String s = p.toString(); MEEC@IST Java – 30/31 Implementação de interfaces (16) • O programador pode instanciar a pilha que mais lhe interessa: Pilha p1 = new PilhaComLista(); Pilha p2 = new PilhaComLista(); p1.adicionar(new Integer(5)); p2.adicionar(new Character(‘a’)); • Se houver interesse em usar PilhaComTabela, em vez de PilhaComLista, a única alteração reside na instanciação dos objectos, e não na declaração das referências para o tipo Pilha: Pilha p1 = new PilhaComTabela(20); Pilha p2 = new PilhaComTabela(100); p1.adicionar(new Integer(5)); p2.adicionar(new Character(‘a’)); MEEC@IST Java – 31/31