Sei sulla pagina 1di 7

Interfaces em Java uma introduo Miguel Jonathan reviso em 6/5/2010 Conceito de interfaces em Java Uma interface em Java uma

uma espcie de classe, com as seguintes propriedades: a) No pode ser instancivel (no podemos criar objetos com new); b) S pode possuir assinaturas de mtodos de instncia, pblicos e abstratos (sem corpo). No pode possuir mtodos concretos (com corpo), nem mtodos estticos. Os prefixos abstract e public podem ser usados, mas so em geral omitidos; c) No pode conter variveis de instncia ou de classe (static); d) Pode conter declaraes de constantes (com prefixo final e inicializadas para um valor) nesse caso essa varivel funcionar como uma constante de classe. O prefixo static possa ser usado, mas em geral omitido; e) Pode ser criada como subinterface de outra interface j existente, usando extends, como as classes. Para criar interfaces usamos uma sintaxe parecida com a das classes, substituindo a palavra class por interface, por exemplo:
public interface InterfaceExemplo{ public final String PALAVRA = "UFRJ"; public void metodo1(int x); public String metodo2 (String s); } public interface InterfaceExemplo2 extends InterfaceExemplo { public void metodo3(); }

Nos exemplos acima, so criadas duas interfaces. A segunda uma subinterface da primeira, ou uma extenso dela. A interface InterfaceExemplo2 contm todos os trs mtodos, e mais a constante PALAVRA. Ou seja, ela "herda" as definies da sua superinterface Exemplo (bem como de todas as superinterfaces acima na hierarquia que existirem). Ao contrrio das classes, no existe uma interface "raiz" de todas as interfaces, como ocorre com a classe Object. A interface InterfaceExemplo, vista acima, no herda de nenhuma outra. Note que a mesma conveno para nome de classe se aplica aos nomes das interfaces: iniciar com letra maiscula, seguida de letras minsculas. A constante PALAVRA do exemplo acima segue a conveno de nome de constantes em Java, que ter todas as letras maisculas. O arquivo fonte de uma interface, da mesma forma que no caso de classes, tambm tem o nome da interface com a terminao .java. E o compilador gera da mesma forma um arquivo .class de mesmo nome. Usando interfaces Uma Interface funciona de forma anloga a uma classe abstrata. Ou seja, ela no pode ser instanciada, mas pode ser como que "herdada" por uma classe.

A forma sinttica para uma classe herdar de uma interface utiliza a palavra chave implements, como no exemplo fictcio abaixo:
public class ClasseTeste implements InterfaceExemplo { public void metodo1(int x) { System.out.println(x); } public String metodo2(String s) { return s + " da " + PALAVRA; } // outros mtodos e atributos desta classe }

O sentido de uma classe "herdar" de uma interface similar ao de herdar mtodos abstratos de uma superclasse abstrata. A classe fica obrigada a implementar concretamente todos os mtodos declarados na interface, e nas suas super-interfaces, ou a classe no compilar. Note que a classe pode usar diretamente a constante definida na interface. Classes podem implementar mais de uma interface Uma diferena essencial entre classes e interfaces que uma classe pode implementar diversas interfaces, embora possa ser subclasse de apenas uma superclasse. Nesse caso, aps a palavra chave implements, escrevemos a lista das interfaces que a classe implementa, separadas por vrgulas. Por exemplo, sejam as interfaces InterfaceExemplo, InterfaceExemplo2 e InterfaceY, e uma classe ClasseExemplo2 que implementa as duas ltimas interfaces:
public interface InterfaceExemplo{ public final String PALAVRA= "UFRJ"; public void metodo1(int x); public String metodo2 (String s); } ============================================================= public interface InterfaceExemplo2 extends InterfaceExemplo { public void metodo3(); } ============================================================ public interface InterfaceY { public int f1(); public int f2(); } ============================================================ public class ClasseExemplo2 implements InterfaceExemplo2, InterfaceY { public void metodo1(int x) { // texto do mtodo } public String metodo2(String s) { // texto do mtodo } public void metodo3() { // texto do mtodo

} public int f1() { // texto do mtodo } public int f2() { // texto do mtodo } // outros mtodos, atributos, etc. desta classe }

Note que a classe fica obrigada a implementar concretamente todos os mtodos declarados em todas as interfaces que implementa (isso incluindo todos os mtodos declarados em todas as superinterfaces de todas elas). Interfaces podem ser tipos de referncias Da mesma forma que as classes, uma referncia pode ser declarada como tendo o tipo de uma interface. Essa propriedade permite, inclusive, um dos mais importantes usos de interfaces, como veremos mais adiante. Por exemplo, supondo as interfaces dos exemplos acima, poderamos declarar, em qualquer mtodo, variveis como:
InterfaceExemplo ex; InterfaceY y1;

Uma varivel do tipo de uma interface pode referenciar qualquer objeto de qualquer classe que implemente essa interface, ou qualquer subinterface dela. Mas h uma restrio importante: a partir de uma referncia de um tipo, s possvel acessar os mtodos definidos no nvel desse tipo ou acima. Acompanhe o teste abaixo. Algumas linhas contm erros comentados:
public class TesteRef{ public static void main(String[] args){ InterfaceExemplo ex1; InterfaceY y1, y2; ex1 = new ClasseExemplo2(); // OK, ClasseExemplo2 implementa sub-interface InterfaceExemplo y1 = new ClasseExemplo2(); // OK, ClasseExemplo2 implementa InterfaceY diretamente // y1 = ex1; // Erro: y1 e ex1 tm direitos de acesso diferentes ao mesmo objeto. y2 = (Y) ex1; // OK, com o casting, o compilador aceita a atribuio ex1.metodo1(100); // OK, void metodo1(int) foi definido na interface InterfaceExemplo // ex1.exemplo3()); // ERRO: mtodo void exemplo3() no foi definido para o tipo InterfaceExemplo // System.out.println(ex1.f1()); // ERRO: metodo f1() no definido para o tipo InterfaceExemplo System.out.println(y1.f1()); // OK, mtodo int f1() foi definido para o tipo InterfaceY } }

Interfaces parametrizadas da API do Java SE No pacote java.util encontramos duas interfaces fundamentais para se entender e utilizar as classes que lidam com colees de objetos em Java. Trata-se das interfaces java.lang.Comparable<T> e java.lang.Comparator<T>.

Na interface Comparable<T> est definido um nico mtodo com a assinatura:


public int compareTo (T o);

Note o parmetro genrico T. Se uma classe implementa a interface Comparable<T>, ento deve implementar esse mtodo com obrigatoriamente um parmetro tambm do do tipo T. Em geral, essa classe ser a classe T, e o mtodo permite comparar duas instncias dessa classe. Esse mtodo deve ter a seguinte funcionalidade, supondo a operao:
t1.compareTo(t2), onde t1 e t2 so do tipo T:

a) se o objeto t1 deve ser considerado menor (deve ficar antes) que t2, o mtodo deve retornar um inteiro negativo; b) se o objeto t1 deve ser considerado maior (deve ficar depois) que t2, o mtodo deve retornar um inteiro positivo; c) se o objeto t1 deve ser considerado igual a (deve ficar na mesma posio que) t2, o mtodo deve retornar zero. O exemplo abaixo ajuda a compreender o uso dessa interface para ordenar um vetor de objetos de uma classe qualquer. Seja uma classe Data, para representar datas do calendrio, com campos dia, mes e ano. Se queremos que duas datas sejam "comparveis", no sentido acima, a classe deve implementar a interface Comparable<Data>, e implementatar um mtodo public int compareTo (Data d){....} que tenha a funcionalidade convencionada nesta interface. Esse mtodo pode ser escrito da forma abaixo:
public int compareTo(Data d) { if (ano < d.ano) return -1; if (ano > d.ano)return 1; if (mes < d.mes) return -1; if (mes > d.mes) return 1; return dia -d.dia; }

O projeto Comparaveis.zip mostra essa classe e um exemplo de utilizao para ordenar um vetor de datas.

A coleo java.util.TreeSet<E>, e o uso das interfaces Comparable e Comparator: Um TreeSet uma classe que implementa a interface java.util.Set. Ela pertence ao grupo de classes conhecido como Java Collections Framework. Uma instncia de TreeSet<E> pode armazenar referncias do tipo E, ou de qualquer subtipo de E. Um TreeSet, como um HashSet, no pode ter referncias duplicadas. Mas nesse caso, o significado de "referncias duplicadas" bem mais sutil. No caso do HashSet, se x1 e x2 so duas referncias contidas no conjunto, ento x1.equals(x2) e x2.equals(x1) devem retornar o valor false. Os TreeSets, por sua vez, tm a propriedade de manter seus elementos em uma ordem dada por um critrio de ordenao definido no momento da sua construo. Esse critrio depende da forma do construtor utilizado:

a) Se o construtor for apenas new TreeSet<E>(), sem parmetro, ento o critrio de ordenao ser o definido pelo mtodo:
int compareTo(E o)

que necessariamente dever existir na classe E. Nesse caso, para que isso possa ser garantido, a classe E deve implementar a interface java.util.Comparable<E>, que obriga a ter esse mtodo. Como deve funcionar o mtodo compareTo: Sejam x1 e x2 instncias de E. Ento, x1.compareTo(x2) deve retornar um inteiro negativo se o objeto referenciado por x1 deva ficar antes de x2 na ordenao desejada, retornar um inteiro positivo, caso x1 deva ficar depois de x2, e retornar o valor inteiro zero, caso x1 e x2 tenham a mesma posio relativa na ordenao desejada.

b) Se o construtor for da forma new TreeSet(c), onde c for do tipo java.util.Comparator<T>, (onde T a classe E, ou alguma superclasse de E, ver obs adiante), ento o objeto referenciado por c dever ser de uma classe que implemente a interface java.util.Comparator<T>. Essa interface obriga que seja definido um mtodo com a assinatura:
int compare(T x1, T x2)

Esse mtodo deve ter funcionalidade similar do mtodo compareTo() visto acima: Sejam x1 e x2 duas referncias do tipo T. Ento, compare(x1, x2) deve retornar um inteiro negativo se o objeto referenciado por x1 deva ficar antes de x2 na ordenao desejada, retornar um inteiro positivo, caso x1 deva ficar depois de x2, e retornar o valor inteiro zero, caso x1 e x2 tenham a mesma posio relativa na ordenao desejada. Dizemos que o objeto passado como parmetro para o construtor do TreeSet "um comparator", ou seja, uma instncia de uma classe que implementa a interface Comparator<T>. Na prtica, essa classe feita para conter apenas o mtodo compare(), e o mtodo compare() implementa o critrio de ordenao desejado. Observao muito importante para uso de TreeSets - compatibilidade de equals() com compare() ou compareTo(): Como sabemos, um conjunto no pode conter referncias "duplicadas". Mas o que significa exatamente isso? No caso de TreeSets, quando se vai adicionar um novo elemento ao conjunto, o mtodo comparador acionado para verificar a posio deste elemento em relao aos que j esto no conjunto. Caso o resultado seja zero, indicando que o novo elemento deve ficar na "mesma" posio que algum outro que j esteja no conjunto, esse novo elemento NO ser adicionado ao conjunto, sendo considerado uma repetio. Isso ocorrer MESMO que o teste de equals() retorne o valor false. Por exemplo, suponha um conjunto de Aluno, e que nessa classe o mtodo boolean o mesmo valor de DRE. Se o critrio de ordenao usado pelo comparador for a ordem alfabtica dos nomes, e se o mtodo compare(), ou compareTo(), retornar zero para dois alunos homnimos (mesmo que com DRE's diferentes), ento somente um desses alunos poder entrar no conjunto.
equals(Object obj) considere que dois alunos so "iguais" caso possuam

Nesse caso dizemos que o mtodo equals() e o mtodo comparador utilizado no so "compatveis". Para que sejam compatveis, o mtodo comparador somente deve retornar zero para os mesmos casos em que o mtodo equals() retornar o valor true. Como conseguir isso? relativamente fcil: basta fazer com que, nos casos em que o critrio de ordenao do comparador indicar a mesma posio relativa, o valor a ser retornado pelo mtodo compare/compareTo seja dado pelo critrio definido no mtodo equals() da classe dos elementos do conjunto. Voltando ao exemplo anterior, caso o critrio compare dois alunos com exatamente o mesmo nome, o mtodo no deve retornar zero, mas sim o resultado da comparao dos valores de DRE de cada um. Assim, somente retornaria zero caso os dois DRE's fossem idnticos, indicando realmente ser o "mesmo" aluno que estaria se tentando incluir no conjunto. Exemplo completo de uma classe comparadora de Aluno, usando o critrio de comparar os nomes em ordem alfabtica ascendente, mostrando tambm o mtodo equals() usado na classe Aluno:
class Aluno { ...... // mtodo equals retorna true quando DRE's so iguais: public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof Aluno)) return false; Aluno aluno = (Aluno)obj; return this.getDre().compareTo(aluno.getDre()); } } class ComparadorNome implements java.util.Comparator<Aluno> public int compare(Aluno a1, Aluno a2) { int res = a1.getNome().compareTo(a2.getNome()); if (res == 0) return a1.getDre().compareTo(a2.getDre()); return res; } }

Note que o mtodo compare() acima jamais retornar zero com dois alunos de mesmo DRE, mesmo que tenham exatamente o mesmo nome. Outra observao importante: para poder ordenar um TreeSet<E> deve-se usar um Comparator<T>, onde T deve ser do tipo E ou de algum supertipo de E (e no um subtipo): Veja esse exemplo: ordenar um TreeSet<Pessoa>. Vamos supor que o TreeSet contenha referncia de Aluno e de Professor, subclasses de Pessoa. Evidentemente, o critrio de comparao usado no poder usar nenhuma caracterstica exclusiva de Aluno ou de Professor, mas somente caractersticas comuns, que se encontram na classe Pessoa ou acima dela. Poderemos usar um Comparator<Pessoa>, mas no um Comparator<AlunoGrad>. Para indicar isso, o tipo do comparator a ser usado para construir um TreeSet<Pessoa> escrito da forma: Comparator<? super Pessoa>. Ou seja, podemos comparar os elementos desse conjunto por nome, idade, etc, mas no por nota. Um problema que surge aqui que teremos que o mtodo comparador ter que ter compatibilidade com o mtodo equals() existente na classe Pessoa ou acima dela. ltima observao: cuidado com a definio correta do mtodo equals(): Para efeito de incluso em sets, o mtodo equals usado o que tem a assinatura:

boolean equals(Object obj);

Esse o mtodo que precisa ser redefinido na classe dos elementos que queremos inserir em um TreeSet. No caso do exemplo acima, note que NO definimos o mtodo:
boolean equals(Aluno a);

O operador instanceof: No mtodo equals() usado no exemplo acima usamos o operador instanceof. O operador instanceof compara um objeto com um tipo especfico. usado para testar se um objeto uma instncia de uma classe, uma instncia de uma subclasse, ou uma instncia de uma classe que implementa uma determinada interface. Por exemplo, se Aluno subclasse de Pessoa, e se Pessoa implementa Comparable, e se a referncia alu aponta para um objeto da classe Aluno, ento:
alu instanceof Pessoa d true alu instanceof Aluno d true alu instanceof Comparable d true

Potrebbero piacerti anche