3. [TD]: Classes
Palavras-chave: classe, interface, herança, exceção, polimorfismo
Leituras recomendadas:
- parágrafos 2.1, 2.2, 2.4 e 2.7 do capítulo 2 de [ref1]: Classes e interfaces
- parágrafos 3.3 (classe String), 3.5 (classe ArrayList), 3.6 (classe Arrays)
Na parte 1 do exercício ELECTIONS, nenhuma classe foi utilizada. Construímos uma solução da mesma forma que a teríamos construído na linguagem C. Agora, introduzimos o conceito de classe Java.
3.1. Support
![]() | ![]() |
A pasta [support / chap-03] contém o projeto Eclipse deste capítulo.
A partir de agora, trabalharemos com o JDK 1.8, pois alguns dos projetos a seguir exigem essa versão. Para saber qual versão do JDK está sendo usada, proceda da seguinte maneira:
![]() |
![]() |
- em [4], o JRE (Java Runtime Environment) utilizado. Este JRE é, na verdade, um JDK (Java Development Kit), neste caso, o [jdk1.8.0_60]. Se não for um JDK ou se você tiver uma versão inferior à 1.8, proceda da seguinte forma: [5-21];
![]() |
- para [8], o JRE usado atualmente por padrão pelo Eclipse;
- em [11], os diversos JDK e JRE atualmente reconhecidos pelo Eclipse;
![]() |
- em [15], escolha um JDK em vez de um JRE. Este documento utiliza projetos Maven que precisam de um JDK;
![]() |
![]() |
- no [21], há um JDK com versão >=1.8;
- no [22-23], acesse as facetas (diferentes visualizações de um mesmo projeto Eclipse) do projeto;
![]() |
- no [24], verifique se você está usando uma versão do Java >=1.8;
3.2. A classe [ListeElectorale]
Na linguagem C, provavelmente teríamos usado uma estrutura para representar uma lista de participantes da eleição. Ela poderia ter a seguinte forma:
O conceito de “estrutura” não existe na linguagem Java. É preciso substituí-lo pelo de “classe”. Decidimos, portanto, criar uma classe para armazenar as informações sobre uma lista de candidatos. Ela teria a seguinte estrutura:
package istia.st.elections;
public class ListeElectorale {
/**
* identité de la liste
*/
private int id;
/**
* nom de la liste
*/
private String nom;
/**
* nombre de voix de la liste
*/
private int voix;
/**
* nombre de sièges de la liste
*/
private int sieges;
/**
* indique si la liste est éliminée ou non
*/
private boolean elimine;
/**
* constructeur par défaut
*/
public ListeElectorale() {
}
/**
*
* @param nom String : le nom de la liste
* @param voix int : son nombre de voix
* @param sieges int : son nombre de sieges
* @param elimine boolean : son état éliminé ou non
*/
public ListeElectorale(int id,String nom, int voix, int sieges, boolean elimine) {
...
}
/**
*
* @return int : l'identifiant de la liste
*/
public int getId() {
...
}
/**
* initialise l'identifiant de liste
* @param id int : identifiant de la liste
* @throws ElectionsException si id<1
*/
public void setId(int id) {
...
}
/**
*
* @return String : le nom de la liste
*/
public String getNom() {
...
}
/**
* initialise le nom de la liste
* @param nom String : nom de la liste
* @throws ElectionsException si le nom est vide ou blanc
*/
public void setNom(String nom) {
...
}
/**
*
* @return int : le nombre de voix de la liste
*/
public int getVoix() {
...
}
/**
* initialise le nombre de voix de la liste
* @param voix int : le nombre de voix de la liste
*/
public void setVoix(int voix) {
...
}
/**
*
* @return int : le nombre de sièges de la liste
*/
public int getSieges() {
...
}
/**
* fixe le nombre de sièges de la liste
* @param sieges int : le nombre de sièges de la liste
*/
public void setSieges(int sieges) {
...
}
/**
*
* @return boolean : valeur du champ elimine
*/
public boolean isElimine() {
...
}
/**
*
* @param sieges int
*/
public void setElimine(boolean elimine) {
...
}
/**
*
* @return String : identité de la liste électorale
*/
public String toString() {
...
}
}
- linha 8: número que identifica uma lista de forma exclusiva. Não é indispensável neste momento, mas está previsto para uso futuro.
- linha 13: o nome da lista.
- linha 17: o número de votos da lista
- linha 21: o número de cadeiras da lista
- linha 25: valor booleano indicando se a lista foi eliminada (porcentagem de votos obtidos abaixo do limite eleitoral) ou não.
Cada campo privado denominado [xyz] pode ser inicializado por um método denominado [setXyz]. O método [getXyz] permite, por sua vez, obter o valor do campo privado [xyz]. No caso específico em que [xyz] seja um campo do tipo booleano, o método [getXyz] pode ser substituído pelo método [isXyz]. A nomenclatura específica desses métodos segue uma norma de codificação denominada norma JavaBean. Assim, definimos os seguintes métodos públicos:
- getId (linha 48), setId (linha 57)
- getNom (linha 65), setNom (linha 74)
- getVoix (linha 82), setVoix (linha 90)
- getSieges (linha 98), setSieges (linha 106)
- isElimine (linha 114), setElimine (linha 122)
- linhas 30-31: definem um construtor sem parâmetros. Ele permite criar um objeto [ListeElectorale] sem inicializá-lo. Esse objeto pode então ser inicializado por meio dos métodos set.
- linhas 40-42: definem um construtor que permite criar um objeto [ListeElectorale] ao mesmo tempo em que inicializa seus cinco campos privados.
- linhas 130-132: definem o método [toString], que retorna uma sequência de caracteres com os valores dos cinco campos do objeto.
Um programa de teste da classe ListeElectorale poderia ser o seguinte:
package istia.st.elections.tests;
import istia.st.elections.ListeElectorale;
public class MainTest1ListeElectorale {
public static void main(String[] args) {
// criação de uma lista eleitoral
ListeElectorale listeElectorale1 = new ListeElectorale(1, "A", 32000,
0, false);
// exibição da identidade da lista
System.out.println("listeElectorale1=" + listeElectorale1);
// alteração do número de cadeiras
listeElectorale1.setSieges(2);
// exibição da identidade da lista 1
System.out.println("listeElectorale1=" + listeElectorale1);
// uma nova lista eleitoral
ListeElectorale listeElectorale2 = listeElectorale1;
// exibição da identidade da lista 2
System.out.println("listeElectorale2=" + listeElectorale2);
// alteração do número de cadeiras
listeElectorale2.setSieges(3);
// exibição da identidade das duas listas
System.out.println("listeElectorale2=" + listeElectorale2);
System.out.println("listeElectorale1=" + listeElectorale1);
}
}
O ambiente Eclipse para esse teste poderia ser o seguinte:
![]() |
- [1]: o projeto se chama [elections-02A]
- [2]: o aplicativo será colocado em um pacote, neste caso, [istia.st.elections]
- [3]: [ListeElectorale.java] é o código-fonte da classe [ListeElectorale]
- [4]: as classes de teste serão colocadas em um pacote, neste caso, [istia.st.elections.tests]
- [5]: a classe de teste [MainTest1ListeElectorale]
A exibição na tela obtida após a execução do programa acima é a seguinte:

Tarefa a ser realizada: com base no exposto acima, complete o código da classe ListeElectorale.
3.3. Criação de uma classe de exceção [ElectionsException]
Entre as diversas classes de exceção da linguagem Java, há uma chamada [RuntimeException]. Essa classe deriva da classe [Exception], que é a raiz de todas as classes de exceção. A particularidade das instâncias de [RuntimeException] ou de instâncias derivadas é que não é necessário declará-las ou gerenciá-las. Elas são chamadas de exceções não controladas.
Vejamos um primeiro exemplo. A classe [BufferedReader] é uma classe cujas instâncias permitem ler linhas de texto em um fluxo de dados. Ela possui um método [readLine] cuja assinatura é a seguinte:
Vemos que o método pode lançar uma exceção do tipo [IOException]. A árvore de classes dessa classe é a seguinte:
A classe [IOException] deriva da classe [Exception] (linha 3). O compilador nos obriga a gerenciar e declarar as exceções do tipo [java.lang.Exception] ou derivadas (exceto para o ramo [RuntimeException], que apresentaremos mais adiante). Assim, para ler uma linha de texto digitada no teclado, seremos obrigados a escrever algo como:
Vejamos outro exemplo. Para converter uma string em um inteiro, podemos usar o método estático [Integer.parseInt], cuja assinatura é a seguinte:
O argumento [s] é a sequência de caracteres a ser convertida em inteiro. Observa-se que o método pode lançar uma exceção do tipo [NumberFormatException]. A árvore de classes desta classe é a seguinte:
A classe [NumberFormatException] deriva da classe [RuntimeException] (linha 4). O compilador não nos obriga a gerenciar e declarar exceções do tipo [java.lang.RuntimeException] ou derivadas. Assim, podemos escrever algo como:
Não somos obrigados a incluir uma cláusula [try - catch] para lidar com a eventual exceção gerada por [Integer.parseInt] (linha 9).
Existem vantagens e desvantagens em criar e utilizar classes de exceção derivadas de [RuntimeException]:
- quanto às vantagens: o código fica mais leve
- quanto às desvantagens: pode-se acabar voltando aos métodos do C, em que cada função retorna um código de erro que poucas pessoas utilizam, justamente para ter um código mais leve. Quando ocorre um erro não tratado desse tipo, o programa trava, geralmente de maneira pouco elegante.
Decidimos criar uma classe especial que agrupe todas as exceções que possam ocorrer em nosso aplicativo ELECTIONS. Ela se chamará [ElectionsException] e será derivada da classe [RuntimeException]. Seu código é o seguinte:
package istia.st.elections;
public class ElectionsException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ElectionsException() {
super();
}
public ElectionsException(String message) {
super(message);
}
public ElectionsException(Throwable cause) {
super(cause);
}
public ElectionsException(String message, Throwable cause) {
super(message, cause);
}
}
- linha 1: colocamos a classe no pacote [istia.st.elections];
- linha 3: a classe deriva de [RuntimeException]. Portanto, ela não é controlada;
- linha 4: um identificador de serialização que podemos ignorar por enquanto;
- utilizaremos em nossa aplicação dois tipos de construtor:
- o clássico das linhas 15 a 17, conforme mostrado abaixo:
Nesse caso, o método que chama um método que lança tal exceção pode tratá-la da seguinte forma:
// teste de exceção
try {
listeElectorale2.setSieges(-3);
} catch (ElectionsException ex) {
System.err.println("L'exception suivante s'est produite : ["
+ ex.toString() + "]");
}
- (continuação)
- ou o das linhas 14 a 20, destinado a reportar uma exceção já ocorrida, encapsulando-a em uma exceção do tipo [ElectionsException]:
try {
...;
} catch (SQLException ex) {
// encapsulamos a exceção
throw new ElectionsException("erreur de fermeture de la connexion à la BD",ex);
}
Esse segundo método tem a vantagem de preservar as informações que a primeira exceção possa conter. Nesse caso, o método que chama um método que lança tal exceção pode tratá-la da seguinte forma:
try {
...;
} catch (ElectionsException ex) {
System.out.println(ex.getMessage() + ", Cause : "+ ex.getCause().getMessage());
System.exit(1);
}
Tarefa a ser realizada: modifique o código da classe ListeElectorale de forma que os métodos set lancem uma exceção do tipo [ElectionsException] caso a inicialização solicitada esteja incorreta, como, por exemplo, inicializar o nome com uma string vazia.
O projeto Eclipse de teste dessa nova versão poderia ser o seguinte:
![]() |
- [1]: o projeto se chama [elections-02B]
- [2]: o aplicativo está localizado em um pacote, neste caso, [istia.st.elections]
- [3]: as classes [ListeElectorale] e [ElectionsException]
- [4]: as classes de teste estão localizadas em um pacote, neste caso, [istia.st.elections.tests]
- [5]: a classe de teste [MainTest1ListeElectorale]
A classe de teste [MainTest1ListeElectorale], já analisada, é ligeiramente modificada para testar os casos de exceção:
package istia.st.elections.tests;
import istia.st.elections.ElectionsException;
import istia.st.elections.ListeElectorale;
public class MainTest1ListeElectorale {
public static void main(String[] args) {
// criação de uma lista eleitoral
ListeElectorale listeElectorale1 = new ListeElectorale(1, "A", 32000,
0, false);
// exibição da identidade da lista
System.out.println("listeElectorale1=" + listeElectorale1);
// alteração do número de cadeiras
listeElectorale1.setSieges(2);
// exibição da identidade da lista 1
System.out.println("listeElectorale1=" + listeElectorale1);
// uma nova lista eleitoral
ListeElectorale listeElectorale2 = listeElectorale1;
// exibição da identidade da lista 2
System.out.println("listeElectorale2=" + listeElectorale2);
// alteração do número de cadeiras
listeElectorale2.setSieges(3);
// exibição da identidade das duas listas
System.out.println("listeElectorale2=" + listeElectorale2);
System.out.println("listeElectorale1=" + listeElectorale1);
// teste de exceção
try {
listeElectorale2.setSieges(-3);
} catch (ElectionsException ex) {
System.err.println("L'exception suivante s'est produite : ["
+ ex.toString() + "]");
}
}
}
- linha 28: tenta-se inicializar o número de assentos com um valor proibido
- linha 30: se houver uma exceção, ela é exibida
A execução do teste produz os seguintes resultados:

Observa-se que a classe [ListeElectorale] gerou uma exceção ao tentar inicializar o número de assentos com um valor inválido (linha 28 do código).
3.4. Uma classe de teste unitário
O tipo de teste anterior baseia-se em uma verificação visual. Verifica-se se o que aparece na tela corresponde ao esperado. Esse é um método desaconselhado no ambiente profissional. Os testes devem sempre ser automatizados ao máximo e ter como objetivo não exigir nenhuma intervenção humana. O ser humano está, de fato, sujeito à fadiga e sua capacidade de verificar testes diminui ao longo do dia.
Um aplicativo evolui com o tempo. A cada evolução, é preciso verificar se o aplicativo não sofre “regressão”, c.a.d, e se continua a passar nos testes de funcionamento que foram realizados durante sua criação inicial. Esses testes são chamados de testes de “não regressão”. Um aplicativo de certa complexidade pode exigir centenas de testes. De fato, testa-se cada método de cada classe do aplicativo. Isso é chamado de testes unitários. Esses testes podem mobilizar muitos desenvolvedores se não tiverem sido automatizados.
Foram desenvolvidas ferramentas para automatizar os testes. Uma delas se chama [JUnit]. Trata-se de uma biblioteca de classes destinada a gerenciar os testes. Vamos utilizar essa ferramenta para testar a classe [ListeElectorale].
Um programa de teste JUnit (versões 4.x) tem o seguinte formato:
package istia.st.elections.tests;
import org.junit.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JUnitEssai {
@Before
public void avant() throws Exception {
System.out.println("tearUp");
}
@After
public void après() throws Exception {
System.out.println("tearDown");
}
@Test
public void t1() {
System.out.println("test1");
Assert.assertEquals(1, 1);
}
@Test
public void t2() {
System.out.println("test2");
Assert.assertEquals(1, 2);
}
}
- linha 1: a classe foi colocada no pacote [istia.st.elections.tests];
- linha 11: o método anotado pela anotação [@Before] é executado antes de cada teste unitário;
- linha 16: o método anotado com a anotação [@After] é executado após cada teste unitário;
- linha 21: um método anotado com a anotação [@Test] é um método testado pelo teste unitário. Os métodos anotados com [@Test] serão executados um após o outro, salvo indicação em contrário do testador, que pode selecionar ele mesmo os métodos a serem testados. Antes de cada execução de um método [@Test], o método [@Before] é executado. Após cada execução de um método [@Test], o método [@After] é executado;
- linhas 22-25: definem um método de teste [t1];
- linha 18: um dos métodos [Assert.assert*] que permite verificar asserções. Encontram-se os seguintes métodos [assert]:
- assertEquals(expressão1, expressão2): verifica se os valores das duas expressões são iguais. São aceitos diversos tipos de expressão (int, String, float, double, boolean, char, short). Se as duas expressões não forem iguais, é lançada uma exceção do tipo [AssertionFailedError ],
- assertEquals(real1, real2, delta): verifica se dois números reais são iguais com uma tolerância de delta; c.a.d abs(real1 - real2) <= delta. Pode-se escrever, por exemplo, assertEquals(real1, real2, 1E-6) para verificar se dois valores são iguais com uma precisão de 10⁻⁶,
- assertEquals(mensagem, expressão1, expressão2) e assertEquals(mensagem, real1, real2, delta) são variantes que permitem especificar a mensagem de erro a ser associada à exceção do tipo [AssertionFailedError] lançada quando o método [assertEquals] falha,
- assertNotNull(Object) e assertNotNull(message, Object): verifica se Object não é igual a null,
- assertNull(Object) e assertNull(mensagem, Object): verificam se Object é igual a null,
- assertSame(Object1, Object2) e assertSame(message, Object1, Object2): verifica se as referências Object1 e Object2 apontam para o mesmo objeto,
- assertNotSame(Object1, Object2) e assertNotSame(message, Object1, Object2): verifica se as referências Object1 e Object2 não apontam para o mesmo objeto;
- linha 24: essa asserção deve ser bem-sucedida;
- linha 30: esta asserção deve falhar;
No ambiente Eclipse, a criação de uma classe de teste JUnit pode ser feita da seguinte maneira:
![]() |
- [1]: clique com o botão direito do mouse no pacote ao qual se deseja adicionar a classe de teste e selecione a opção [JUnit / New / JUnit Test Case]
![]() |
- [1]: escolha de uma versão JUnit;
- [2]: escolha da pasta na qual a classe de teste deve ser criada;
- [3]: seleção do pacote no qual a classe de teste deve ser criada;
- [4]: nome da classe de teste;
- [5]: seleção dos métodos a serem incluídos na classe que será gerada;
- [6]: a classe JUnitEssai foi gerada
O assistente anterior gera uma classe praticamente vazia:
package istia.st.elections.tests;
import org.junit.Assert;
import org.junit.After;
import org.junit.Before;
public class JUnitEssai {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
}
Vamos completar e modificar o código anterior da seguinte maneira:
package istia.st.elections.tests;
import org.junit.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JUnitEssai2 {
@Before
public void avant() throws Exception {
System.out.println("tearUp");
}
@After
public void après() throws Exception {
System.out.println("tearDown");
}
@Test
public void t1() {
System.out.println("test1");
Assert.assertEquals(1, 1);
}
@Test
public void t2() {
System.out.println("test2");
Assert.assertEquals(1, 2);
}
}
No Eclipse, clicar com o botão direito do mouse na classe de teste e selecionar a opção [Run as / JUnit test] permite executá-la:

Os resultados obtidos na execução deste teste são os seguintes:

Acima, o método [test2] falhou. Sempre que um teste falha, uma mensagem de erro é associada a ele. Para o [test2], é a mensagem exibida acima. A mensagem indica o número da linha em que ocorreu o erro (linha 30). Na linha 30, a chamada que falhou foi:
Assert.assertEquals(1, 2);
O primeiro parâmetro é chamado de valor esperado, e o segundo, de valor real. A mensagem de erro de [test2] acima indica que o valor esperado era 2, mas que o valor real foi 3.
Por fim, as mensagens exibidas no console pelos diversos métodos de teste foram as seguintes:

Essas mensagens mostram que os métodos [@Before] e [@After] foram efetivamente chamados, respectivamente, antes e depois de cada método de teste.
As classes de teste não são necessariamente escritas pelos próprios desenvolvedores. Elas podem ser criadas pelas pessoas que redigiram as especificações do aplicativo. Algumas metodologias de desenvolvimento, conhecidas como TDD (Desenvolvimento Orientado a Testes), recomendam a criação das classes de teste antes mesmo da criação das classes a serem testadas. Isso permite, às vezes, esclarecer especificações que, de outra forma, poderiam ser interpretadas de várias maneiras.
Vamos criar um teste JUnit 4, chamado [JUnitTest1ListeElectorale], para a classe [ListeElectorale]. No Eclipse, procederemos conforme descrito anteriormente:
![]() | ![]() |
Completamos o código gerado pelo assistente da seguinte maneira:
package istia.st.elections.tests;
import org.junit.Assert;
import istia.st.elections.ElectionsException;
import istia.st.elections.ListeElectorale;
import org.junit.Test;
public class JUnitTest1ListeElectorale {
@Test
public void t1() {
// criação da lista eleitoral
ListeElectorale liste = new ListeElectorale(1, "a", 32000, 0, false);
// verificações
Assert.assertEquals("a", liste.getNom());
Assert.assertEquals(32000, liste.getVoix());
Assert.assertEquals(false, liste.isElimine());
Assert.assertEquals(0, liste.getSieges());
// verificação da validade do ID
boolean erreur = false;
try {
liste.setId(-4);
} catch (ElectionsException e) {
erreur = true;
}
Assert.assertEquals(true, erreur);
// verificação da validade do nome
erreur = false;
try {
liste.setNom("");
} catch (ElectionsException e) {
erreur = true;
}
Assert.assertEquals(true, erreur);
// verificação da validade dos votos
erreur = false;
try {
liste.setVoix(-4);
} catch (ElectionsException e) {
erreur = true;
}
Assert.assertEquals(true, erreur);
// verificação da validade dos assentos
erreur = false;
try {
liste.setSieges(-4);
} catch (ElectionsException e) {
erreur = true;
}
Assert.assertEquals(true, erreur);
}
}
A execução do teste produz o seguinte resultado:

Os testes foram bem-sucedidos. A partir de agora, consideraremos que temos uma classe [ListeElectorale] operacional.
3.5. MainElections: versão 2
Leituras recomendadas:
- parágrafos 2.1, 2.2, 2.4 e 2.7 do capítulo 2 de [1]: Classes e interfaces
- parágrafos 3.3 (classe String), 3.5 (classe ArrayList) e 3.6 (classe Arrays)
Deseja-se reescrever o aplicativo [Elections], adicionando as seguintes novas restrições:
- utilizaremos a classe [ListeElectorale] para representar uma lista de candidatos
- o aplicativo solicitará ao teclado as seguintes informações:
- o número de vagas a serem preenchidas
- os nomes e as vozes das listas. Não se sabe, a priori, quantas listas existem. A última lista será identificada por um nome igual à sequência “*”.
- Como não se sabe, a priori, o número de listas, estas serão, em primeiro lugar, armazenadas em um objeto do tipo [ArrayList]. Em seguida, quando todas as listas tiverem sido inseridas, elas serão transferidas para uma matriz de listas.
- Os resultados serão exibidos em ordem decrescente do número de cadeiras obtidas.
Para ordenar uma matriz T, dispõe-se de diferentes métodos estáticos da classe [Arrays]:
- Arrays.sort(T): ordena a matriz T de acordo com uma ordem natural, caso exista (crescente para números e datas, alfabética para cadeias de caracteres, etc.)
- Arrays.sort(T,comparador): para ordenar tabelas T que não possuem uma ordem natural. Esse é o caso, aqui, da tabela de listas que deve ser ordenada de acordo com um campo específico da lista: o número de assentos obtidos.
No método Arrays.sort(T,comparador), o parâmetro comparador é um objeto que implementa a seguinte interface Comparator:

- o método `compare` permite comparar dois elementos da matriz T
- o método equals permite determinar se dois objetos são iguais
Os dois métodos comparam os tipos Object obj1 e obj2. Determinar se obj1<obj2, obj1=obj2 ou obj1>obj2 é o caso depende da relação de ordem que se deseja estabelecer entre os dois objetos. Cabe ao desenvolvedor que implementa essa interface indicar como se sabe que:
- obj1 é menor que obj2
- obj1 é maior que obj2
- obj1 é igual a obj2
A classe Object, da qual todas as classes Java derivam, já dispõe de um método [equals]. Para ordenar um array T de objetos do tipo O, o método [equals] da classe O não é necessário. Portanto, pode-se manter a implementação padrão fornecida pela classe Object. Nesse caso, apenas o método [compare] deve ser implementado. Esse método é chamado repetidamente pelo método [Arrays.sort]. Este, a cada chamada, passará como parâmetros obj1 e obj2 do método compare, dois elementos da matriz T a ser ordenada. No nosso caso, esses elementos serão do tipo [ListeElectorale]. Observe aqui o polimorfismo em ação. O método [compare] está definido para receber parâmetros do tipo [Object]. Isso significa que ela pode receber parâmetros do tipo [Object] ou derivados (polimorfismo). Como [Object] é a classe pai de todas as classes Java, os parâmetros efetivos podem ter o tipo [ListeElectorale].
Para uma ordenação crescente, o método [compare] deve retornar:
- -1 se obj1 for menor que obj2
- +1 se obj1 for maior que obj2
- 0 se obj1 for igual a obj2
Para uma ordenação em ordem decrescente, os valores +1 e -1 são invertidos. Os termos “é menor que”, “é maior que” e “é igual a” expressam uma relação de ordem. Para objetos do tipo [ListeElectorale], teremos a relação lista1 “é menor que” lista2 se lista1 tiver menos votos que lista2.
No mesmo arquivo-fonte da classe [MainElections], é possível adicionar uma segunda classe:
- linha 2: a classe não está declarada como pública. Em um arquivo-fonte Java, pode haver várias classes, mas apenas uma pode ter o atributo public, que é aquela que leva o nome do arquivo-fonte.
No método compare anterior, os parâmetros são do tipo Object,, o que obriga as linhas 7 e 8 a realizar uma conversão de tipo dos parâmetros do método, do tipo Object para o tipo ListeElectorale. A assinatura do método compare é imposta pela interface Comparator, que foi criada para comparar objetos quaisquer. Desde a versão 1.5 do JDK, existe uma interface genérica Comparator: Comparator<T>, em que T é um tipo Java qualquer. O método compare da interface Comparator<T> compara objetos do tipo T e não do tipo Object, o que evita as conversões de tipo anteriores. A classe de comparação de objetos do tipo ListeElectorale poderia ser semelhante a esta:
// classe de comparação de listas eleitorais
class CompareListesElectorales implements Comparator<ListeElectorale> {
// comparação entre duas listas eleitorais com base no número de cadeiras
public int compare(ListeElectorale listeElectorale1,
ListeElectorale listeElectorale2) {
...
}
}
- linha 2: a classe implementa a interface Comparator<ListeElectorale>
- linhas 5-6: os parâmetros do método compare são do tipo ListeElectorale. A conversão de tipos agora é desnecessária.
O JDK 1.5 introduziu o conceito de classe/interface genérica para diversas classes/interfaces do JDK 1.4 que, inicialmente, manipulavam apenas objetos do tipo Object. É o caso das listas, dos dicionários, etc.
Mencionamos um pouco acima que, como não se sabia o número de listas, não era possível armazená-las em um array. Elas podem ser armazenadas em um objeto ArrayList que implementa o conceito de “lista de objetos”. Essa classe armazena objetos do tipo Object. A partir da versão 1.5 do JDK, existem listas de objetos tipados. Assim, utilizar-se-á um objeto ArrayList<ListeElectorale> para armazenar as listas antes de transferi-las para um array. Se este último for denominado tListes, sua ordenação será obtida pela instrução:
// classificação das listas
Arrays.sort(tListes, new CompareListesElectorales());
onde CompareListesElectorales é a classe que implementa a interface Comparator<ListeElectorale>.
Tarefa a ser realizada: reescreva a aplicação [Elections] levando em conta essas novas especificações.
O projeto Eclipse poderia ser o seguinte:
![]() |
Um exemplo de execução de [1] é o seguinte:
















