Você está na página 1de 349

JAVA - Programação Orientada a Objetos e UML com Java

1 Introdução à criação de classes 9


1.1 Classes & Objetos 10
1.1.1 Classes 10
1.1.2 Declaração de classes 11
1.1.3 Convenções para nomes de classes 12
1.1.4 Objetos 12
1.1.5 Abstração 13
1.1.6 Coesão 14

r
1.2 Atributos 16

.b
1.2.1 Declaração de atributos 16
1.2.2 Convenções para nomes de atributos 17
1.2.3 Acessando atributos a partir de outras classes 17

m
1.2.4 Inicialização de atributos 19
1.2.5 Laboratório : utilização de atributos 21

co
1.3 Métodos 22
1.3.1 Declaração de métodos 22
1.3.2 Convenções para nomes de métodos: 22
1.3.3
1.3.4
1.3.5
Retorno de métodos
Passagem de parâmetros
Acessando métodos a partir de outras classes
g. 23
24
25
in
1.3.6 Exemplos 26
1.3.7 Erros comuns 28
nn

1.3.8 Listas de parâmetros de tamanho variável (varargs) 31


1.3.9 Laboratório: chamada a métodos 34
1.3.10 Passagem de parâmetros de tipos primitivos 35
ai

1.3.11 Passagem de parâmetros de tipos reference (Objetos e arrays) 36


1.4 Certificação Oracle Certified Java Programmer (OCJP) 38
.tr

2 Introdução a UML 41
2.1 UML e metodologias de desenvolvimento de software 42
2.2 Principais diagramas da UML 43
w

2.2.1 Diagrama de casos de uso 43


2.2.2 Diagrama de classes 43
w

2.2.3 Diagrama de estados 44


2.2.4 Diagrama de seqüência 45
w

2.2.5 Diagrama de comunicação 46


2.2.6 Diagrama de componentes 47
2.2.7 Diagrama de instalação / deployment 47
2.2.8 Diagrama de atividades 48
2.3 Introdução ao diagrama de classes 49
2.3.1 Representando atributos 49
2.3.2 Representando métodos 49

Trainning Education Services - Todos os direitos reservados 1


3 Encapsulamento 53
3.1 Getters e Setters 54
3.1.1 Métodos get 54
3.1.2 Métodos set 54
3.1.3 Métodos is 54
3.2 Modificadores de acesso 59
3.2.1 Modificador public 59
3.2.2 Modificador private 60

r
3.2.3 Quando utilizar private ou public? 61

.b
3.2.4 Exemplos 62
3.3 Objeto this 64
3.4 Encapsulamento de atributos compostos 66

m
3.5 Acoplamento (Coupling) 74
3.5.1 Acoplamento Forte 74

co
3.5.2 Acoplamento Fraco 74
3.6 Laboratório: encapsulamento 75
4 Sobrecarga de métodos 79
4.1
4.2
Exemplos
Sobrecarga com tipos ambíguos
g. 81
83
in
4.3 Varargs e sobrecarga 85
4.4 Laboratório: sobrecarga de métodos 87
4.5 Certificação Oracle Certified Java Programmer (OCJP) 88
nn

5 Construtores 91
5.1 Declarando construtores 94
5.1.1 Erros comuns na declaração de construtores 97
ai

5.2 Sobrecarga de construtores 99


5.2.1 Utilização do objeto implícito this 100
.tr

5.3 Blocos de inicialização de objetos 102


5.4 Garbage Collector e remoção de objetos 104
5.4.1 Removendo um objeto da memória 104
w

5.4.2 Método finalize 105


5.5 Laboratório: construtores 108
w

5.6 Certificação Oracle Certified Java Programmer (OCJP) 109


6 Modificador static 113
w

6.1 Atributos estáticos 115


6.1.1 Quando utilizar atributos estáticos? 115
6.1.2 Quando não utilizar atributos estáticos? 119
6.2 Métodos estáticos 120
6.2.1 Restrições no uso de métodos estáticos 124
6.3 Bloco de inicialização estático 127
6.4 Representação do modificador static na UML 130

Trainning Education Services - Todos os direitos reservados 2


6.5 Laboratório: modificador static 131
6.6 Certificação Oracle Certified Java Programmer (OCJP) 132
7 Associação 135
7.1 Representação de associações na UML 135
7.2 Cardinalidade / Multiplicidade 136
7.3 Navegabilidade 138
7.4 Restrições 140
7.5 Associação reflexiva 140

r
7.6 Agregação 141

.b
7.7 Composição 142
7.8 Dependência 143
7.9 Classe Associativa 144

m
7.10 Estudo de caso: Modelagem de uma empresa 145
7.10.1 Laboratório: associação simples 147

co
7.10.2 Laboratório Opcional: atributos compostos 149
7.10.3 Laboratório Opcional de Modelagem 151
8 Herança 155
8.1
8.2
Representação de herança na UML
Exemplos
g. 156
157
in
8.3 Herança e modificador private 162
8.4 Modificador protected 163
8.5 Referência implícita super 165
nn

8.6 Construtores x Herança 167


8.6.1 Seqüência completa de inicialização dos objetos em Java 171
8.7 Sobrescrita de métodos 174
ai

8.7.1 Sobrescrita do método toString() 177


8.7.2 Laboratório: herança 180
.tr

8.8 Modificador final 181


8.8.1 Modificador final na declaração de classes 181
8.8.2 Modificador final na declaração de métodos 182
w

8.8.3 Modificador final na declaração de atributos 183


8.9 Certificação Oracle Certified Java Programmer (OCJP) 186
w

9 Enumerações 195
9.1 Introdução ao uso de enumerações 197
w

9.2 Imprimindo os elementos da enumeração 200


9.3 Adicionando atributos e métodos à enumeração 201
9.4 Representando enumerações na UML 203
9.5 Certificação Oracle Certified Java Programmer (OCJP) 204
10 Classes abstratas e interfaces 207
10.1 Modificador abstract 207
10.1.1 Classes abstratas 207

Trainning Education Services - Todos os direitos reservados 3


10.1.2 Métodos Abstratos 210
10.1.3 Representando o modificador abstract em UML 214
10.1.4 Erros comuns 215
10.1.5 Laboratório: classes abstratas 218
10.2 Interfaces 220
10.2.1 Interfaces em Java 221
10.2.2 Definindo uma Interface 222
10.2.3 Implementando uma Interface 224

r
10.2.4 Estendendo uma Interface 229

.b
10.2.5 Representando interfaces na UML 231
10.2.6 Interface vs. Abstract 233
10.2.7 Erros comuns 234

m
10.2.8 Laboratório: interfaces 239
10.3 Certificação Oracle Certified Java Programmer (OCJP) 241

co
11 Polimorfismo 245
11.1 Cast de objetos 245
11.1.1 Cast up (Widening) 248
11.1.2
11.1.3
11.2
Cast down (Narrowing)
Operador instanceof
Polimorfismo
g. 249
250
251
in
11.2.1 Parâmetros polimórficos 254
11.2.2 Coleções Heterogêneas 255
nn

11.3 Tipos de retorno covariantes e polimorfismo 256


11.4 Acoplamento e polimorfismo 258
11.4.1 Laboratório: polimorfismo 260
ai

11.5 Certificação Oracle Certified Java Programmer (OCJP) 261


12 Pacotes 265
.tr

12.1 Declarando o pacote das classes 267


12.1.1 Compilando classes que estão em pacotes 268
12.1.2 Executando classes que estão em pacotes 268
w

12.1.3 Erros comuns 269


12.2 Utilizando classes de outros pacotes 270
w

12.2.1 Modificador padrão / package 273


12.2.2 Importando duas classes com o mesmo nome em pacotes diferentes 275
w

12.2.3 Trabalhando com classes que estão em pacotes diferentes 278


12.2.4 Erros comuns 280
12.3 Importação estática (static import) 284
12.3.1 Como utilizar importação estática? 285
12.3.2 Quando devemos utilizar importação estática? 285
12.4 Representação de pacotes na UML 286
12.5 Dicas para utilização de pacotes 288
12.6 Componentes: JAR (Java ARchive) 290

Trainning Education Services - Todos os direitos reservados 4


12.6.1 Criação de um JAR simples 291
12.6.2 Extração das classes de um JAR 293
12.6.3 Criação de um JAR executável 294
12.6.4 Execução de um JAR 295
12.6.5 Disponibilizando um JAR para muitas aplicações 296
12.7 Diagrama de componentes 299
12.8 Laboratório: pacotes 301
12.9 Certificação Oracle Certified Java Programmer (OCJP) 302

r
13 Tratamento de erros 305

.b
13.1 Exceções 306
13.1.1 Hierarquia das classes de erro 306
13.1.2 A classe Error 307

m
13.1.3 A classe Exception 308
13.1.4 RuntimeExceptions 309

co
13.1.5 Laboratório: runtime exceptions 311
13.2 Tratamento de exceções 312
13.2.1 A instrução throw 313
13.2.2
13.2.3
13.2.4
A instrução throws
A estrutura try / catch
A instrução finally
g. 315
319
323
in
13.2.5 Capturando múltiplas exceções 326
13.2.6 Laboratório: capturando exceções 332
nn

13.2.7 Criando suas próprias exceções 333


13.2.8 Piores Práticas 336
13.2.9 Erros comuns 337
ai

13.3 Sobrescrita de métodos e lançamento de exceções 339


13.4 Laboratório: exceções customizadas 342
.tr

13.5 Liberação automática de recursos 343


13.6 Assertivas 346
13.6.1 Compilação com assertivas 348
w

13.6.2 Execução com assertivas 348


13.6.3 Execução do código de exemplo 348
w

13.7 Certificação Oracle Certified Java Programmer (OCJP) 350


14 Diagramas de Seqüência 355
w

14.1 Elementos de um Diagrama de Seqüência 356


14.1.1 Objetos 356
14.1.2 Mensagens 357
14.1.3 Fragmentos 361
14.2 Estudo de caso 364
14.2.1 Laboratório Opcional 368
15 Apêndice 373

Trainning Education Services - Todos os direitos reservados 5


15.1 Solução das questões preparatórias para certificação 373
15.2 Solução dos laboratórios opcionais de UML 380
15.2.1 Modelagem de Classes e Relacionamentos 380
15.2.2 Diagramas de Seqüência 381
16 Apêndice II - Javadoc 387
16.1 Doclets 388
16.2 Tags padrão do Javadoc 388
16.3 Executando o utilitário Javadoc 395

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 6


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Introdução à criação de classes


.tr

Classes & Objetos


Atributos
w

Métodos
w
w

Trainning Education Services - Todos os direitos reservados 7


1 Introdução à criação de classes
Ao utilizar a análise procedural para desenvolver sistemas de software existe um foco muito grande nos
procedimentos ou sub-rotinas e um foco menor nos dados que serão manipulados. Na análise orientada a objetos
este foco muda para os dados ou entidades e o que cada entidade pode fazer. Isso facilita a modelagem do
sistema, por utilizar uma abordagem mais próxima ao mundo real.

No paradigma de programação procedural, trabalha-se com tipos de dados primitivos e estruturados. Os tipos

r
primitivos correspondem a valores numéricos, caracteres e valores lógicos (verdadeiro ou falso). Denominam-se

.b
tipos estruturados, os tipos definidos pelo usuário, que agrupam diversos outros tipos em uma estrutura mais
complexa, mas que permite uma manipulação mais fácil e consistente em um programa.

m
Para criar variáveis que representem datas utilizando apenas variáveis primitivas, existem algumas alternativas:

co
• declarar uma variável numérica para cada data, representando o tempo em segundos desde uma data
base (ex: 01/01/1970);

long dataInicioProjeto = 1213645169;


g.
para cada data, declarar um conjunto de variáveis numéricas representando cada uma das partes de uma
in
data (mês, dia, ano, etc.).
nn

byte diaInicioProjeto1 = 16;


byte mesInicioProjeto1 = 6;
short anoInicioProjeto1 = 2008;
ai

byte diaInicioProjeto2 = 23;


byte mesInicioProjeto2 = 10;
short anoInicioProjeto2 = 2008;
.tr

Ambas as soluções criam dificuldades para seu gerenciamento em um programa. No primeiro caso, é preciso
w

fazer conversões toda vez que se quiser manipular apenas uma das partes da data, como por exemplo, retornar o
ano correspondente. No segundo caso, na presença de várias datas, nada garante que por algum erro na
w

programação não se misturem partes de datas diferentes, como por exemplo, o dia de uma data com o mês de
outra.
w

Trainning Education Services - Todos os direitos reservados 9


Com tipos estruturados, é possível criar um tipo Data, que agrupe as características desejadas, e permita sua
manipulação em conjunto. Porém, neste modelo, devem ser criadas separadamente as sub-rotinas que farão o
processamento das datas. Este processamento pode envolver, por exemplo, retornar uma data por extenso. No
paradigma de programação procedural, há então, a separação entre os dados/características dos tipos e seu
processamento/comportamento.

Com a programação orientada a objetos, podem ser criados tipos customizados, que agrupem características e
comportamento em um único elemento. Estes tipos são chamados de classes.

r
.b
1.1 Classes & Objetos
1.1.1 Classes

m
Uma classe é definida pelo usuário pelas especificações (características e comportamentos) que a identificam. É
possível dizer que uma classe é um molde que será usado para construir objetos que representam elementos da

co
vida real.

Classe = Características + Comportamentos


g.
Esse molde é gerado por meio da observação e agrupamento de elementos que possuem as mesmas
características e comportamentos sob uma mesma denominação. Exemplificando: em uma loja online (ambiente)
in
encontra-se um elemento chamado Produto (classe), que possui um conjunto de características tal como a
Identificação e o Preço (atributos).
nn

Produto

Identificação Preço
ai
.tr

Cada Produto poderia ser materializado com as seguintes informações:

Produto
w

Identificação Preço
w

Livro de Java R$ 150,00


w

Trainning Education Services - Todos os direitos reservados 10


Produto
Identificação Preço
Camiseta R$ 15,00

Atributos nem sempre são úteis individualmente, e por isso é importante definir algumas ações que possam ser
executadas dentro do ambiente modelado, usando os atributos existentes na classe. Essas ações definem o
comportamento desejado para a classe.

r
.b
Denominam-se Métodos, as operações implementadas para definir as ações previstas para essa classe. No
exemplo da loja, podem ser atribuídos aos Produtos algumas funcionalidades tais como aumentar e diminuir o

m
preço e alterar a identificação. Note que as ações estão geralmente associadas aos atributos da classe (Preço,
Identificação).

co
Produto
Identificação Preço

Aumentar preço
Diminuir preço
g.
in
Alterar identificação
nn

1.1.2 Declaração de classes


Classes são declaradas utilizando-se a palavra reservada class, seguida do nome da classe e de seu corpo. O
corpo da classe é um bloco de código delimitado por “abre e fecha chaves”, e dentro do corpo é feita a declaração
ai

de seus atributos e métodos, denominados membros da classe.


.tr

Sintaxe para declaração de classes


* class nomeDaClasse {}
w

*Alguns modificadores ou palavras reservadas podem ser aplicados alterando características e a forma de acesso
a classe (o assunto será abordado posteriormente).
w

1. class Data {
2. //declaração de atributos e métodos
w

3. }

Código 1.1 - Exemplo de declaração para classe Data

Trainning Education Services - Todos os direitos reservados 11


1.1.3 Convenções para nomes de classes

• Iniciar os nomes de classes com letras maiúsculas


• Separar nomes de classes compostos por duas ou mais palavras com um
caractere maiúsculo

1.1.4 Objetos

r
Nos exemplos anteriores (Livro de Java, R$ 150,00; Camiseta, R$ 15,00) estão representados casos particulares

.b
da classe Produto. Eles são denominados instâncias das classes, ou objetos, e têm vida independente entre si,
apesar de compartilharem o mesmo “molde” (Classe).

m
Para criar objetos utiliza-se o operador new, e o espaço necessário de memória para o objeto é então alocado.
Esse espaço de memória, quando não está mais sendo utilizado, é liberado por um elemento da Java Virtual

co
Machine (JVM), denominado Garbage Collector.

Sintaxe
<NomeDaClasse> <nomeVariavel> = new <NomeDaClasse>() g.
in
Para criar uma instância da classe Pessoa utilize o comando:
Pessoa p = new Pessoa();
nn

Para criar uma instância da classe Data utilize o comando:


Data d = new Data();
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 12


1.1.5 Abstração
Uma classe pode representar qualquer coisa em qualquer ambiente, e a modelagem deve focar os objetivos
principais do negócio. Isso evita que o sistema torne-se muito grande e conseqüentemente de difícil manutenção e
compreensão. A análise focada é denominada abstração. Basicamente, para um determinado elemento (entidade)
do mundo real selecionam-se as características e comportamentos de interesse para o sistema.

No mundo real utiliza-se um produto que possui informações de garantia, matéria-prima, etc. Porém, conforme o
tipo de aplicativo, é necessário analisar se tais informações devem ser colocadas na definição do objeto.

r
.b
No mundo real troca-se produtos entre pessoas, entretanto, num cenário de e-business, não é preciso
implementar este comportamento ao se definir o Produto.

m
Exemplo: abstração de Data

co
Qual é a estrutura básica de uma Data?
• Dia;
• mês;
• ano.

Qual o comportamento ou operações relativos a esta entidade?


g.
in
• Transformar o número do mês em um texto com o nome do mês (Ex: 1: Janeiro);
• transformar o número do dia em nome do dia (Ex: 24: Segunda, 25: Terça);
nn

• saber se o ano é bissexto.

Exemplo: abstração de Produto


ai

Quais são as características básicas (estrutura) de um produto?


• Identificação;
.tr

• preço;
• nome.
w

Qual o comportamento desta entidade no mundo real?


• Aumentar o preço;
w

• aplicar desconto;
• alterar o nome.
w

Trainning Education Services - Todos os direitos reservados 13


1.1.6 Coesão

Coesão em orientação a objetos é o grau de direcionamento de uma classe para uma única e bem definida
responsabilidade, e traz os seguintes benefícios:
• maior facilidade na manutenção do código;
• melhor reaproveitamento das classes criadas.

Imagine os seguintes requisitos para construção de um aplicativo:

r
• arquivos de textos são gerados por um servidor de dados com informações cadastrais de clientes,

.b
com um registro por linha;
• através de uma interface gráfica o usuário seleciona um arquivo fornecido para processamento;

m
• o aplicativo deve ler os registros do arquivo selecionado e apresentá-los na interface gráfica
classificando-os por município e por nome de cliente.

co
É possível atender aos requisitos e construir este aplicativo com uma única classe Java. Mas será esta a melhor
abordagem a médio e longo prazo? Considere as seguintes solicitações de melhoria, após algum período de
utilização do aplicativo:


g.
o usuário poderá escolher através da interface gráfica outros critérios de classificação;
o servidor de dados passa a fornecer o código de município ao invés do nome de município nos
in
registros dos arquivos de clientes gerados. Um arquivo à parte é disponibilizado pelo mesmo servidor
com a relação de códigos e nomes de municípios;
nn

• os resultados apresentados na interface gráfica poderão ser encaminhados para um relatório


impresso;
• Um novo aplicativo é solicitado, e deve utilizar os mesmos arquivos de texto gerados pelo servidor de
ai

dados, e enviar por e-mail, automaticamente e semanalmente, relatórios para cada gerente de filial
com os clientes de sua região classificados por município e por nome.
.tr

Na melhor e mais rara das hipóteses essas solicitações de melhoria serão feitas de uma só vez, porém na prática
essas solicitações são sempre feitas individualmente e em datas diferentes! Qual o esforço de manutenção cada
w

vez que uma nova solicitação é apresentada? E quanto ao novo aplicativo, será que é o caso de uma construção
“a partir do zero”?
w
w

Trainning Education Services - Todos os direitos reservados 14


Valendo-se da coesão é possível minimizar o impacto das solicitações adicionais.
Veja a versão original do aplicativo planejada de forma coesa:
• uma classe de interface gráfica responsável apenas pela seleção dos
arquivos e pela exibição dos registros já classificados: Tela.java
• uma classe responsável pela leitura dos registros contidos no arquivo texto
selecionado: Leitor.java
• uma classe responsável pela classificação dos registros: Classificador.java

r
Graças à coesão, cada solicitação de melhoria demandará apenas um esforço de manutenção pontual, ou a

.b
criação de novas classes (coesas) se necessário:

m
Tabela 1.1 - Modelagem do sistema com alta coesão

Impacto Tela.java Leitor.java Classificador.java Novas Classes


Melhoria

co
Outros critérios de Lista com Parametrização do
classificação opções de critério de classificação
classificação
g.
in
Código do município Leitura do arquivo
em vez do nome de municípios e
nn

transformação de
código em nome
ai

Encaminhamento Botão para Impressao.java


para impressora impressão
.tr

Novo aplicativo de Reaproveitamento Reaproveitamento, com Temporizador.java


w

envio de relatórios total filtro de região EnviaEmail.java


por e-mail
w
w

Coesão é um conceito independente da linguagem de modelagem e da metodologia de desenvolvimento.

Trainning Education Services - Todos os direitos reservados 15


1.2 Atributos
As definições das características de um objeto são feitas através de atributos da classe : atributos armazenam os
dados do objeto.

1.2.1 Declaração de atributos


Atributos são declarados dentro do corpo da classe, ou seja, dentro do bloco delimitado pela abertura e
fechamento das chaves ({ e }). Não se declaram atributos dentro de métodos, pois variáveis declaradas dentro de

r
métodos são chamadas variáveis locais e têm escopo menor do que um atributo.

.b
Para declarar um atributo em uma classe indica-se o tipo de dado que será armazenado nele.

m
Atributos podem ser de dois tipos:
• tipos primitivos (Ex: long,int,boolean, etc.);
• tipos reference (Ex: Arrays, String, Integer, Date, Cliente, Pessoa, etc.).

co
Sintaxe para declaração
*<tipo do atributo> identificador; g.
Observação: Quando o atributo é um array a declaração é feita da mesma forma que a declaração de uma
in
variável local do tipo array.
Exemplos: int[] array ou int array[]
nn

*.Alguns modificadores ou palavras reservadas podem ser aplicados a atributos alterando suas características e
forma de acesso.
ai

1. class Pessoa {
2. long rg;
.tr

3. String nome;
4. String sobrenome;
5. String dataNascimento;
6. String[] telefones;
w

7. }

Código 1.2 - Pessoa.java com declaração de atributos


w
w

Trainning Education Services - Todos os direitos reservados 16


1. class Data {
2. int dia;
3. int mes;
4. int ano;
5. }

Código 1.3 - Data.java com declaração de atributos

1.2.2 Convenções para nomes de atributos


Para declarar atributos são utilizadas convenções e com isso visualiza-se melhor e mais

r
facilmente o que são classes e o que são atributos. Imagine um desenvolvedor

.b
perguntando para outro quais os nomes dos atributos da classe Cliente, e o outro
respondendo: nome, telefone e endereço.
Quando as convenções são corretamente empregadas sabe-se como escrever os atributos

m
e não é preciso consultar toda a documentação para saber como eles foram declarados:
com maiúsculas, minúsculas, underscore, etc.

co
Identificadores de atributos devem ser declarados com letras minúsculas.

Exemplo: nome, telefone, i, item, email g.


in
Quando o nome do atributo for composto por duas ou mais palavras, a separação deve ser feita com um caractere
maiúsculo e não underscore.
nn

Exemplo: telefoneComercial, enderecoDeEntrega, contratoPessoaJuridica, curriculoVitae,


itemDeVenda
ai

1.2.3 Acessando atributos a partir de outras classes


A partir de uma instância de classe, é possível acessar seus atributos com dois objetivos: ler ou alterar o seu valor.
.tr

Para tal, utiliza-se ponto e mais o nome do atributo.


w

Sintaxe
w

nomeVariavel.nomeAtributo
w

Trainning Education Services - Todos os direitos reservados 17


No exemplo a seguir, criou-se uma classe chamada TestePessoa, que no método main acessa os atributos da
classe Pessoa definida anteriormente com dois objetivos: escrita e leitura.

1. class TestePessoa {
2. public static void main(String[] args) {
3. // Cria-se uma instância da classe Pessoa
4. Pessoa p = new Pessoa();
5. // Acessando os atributos da classe Pessoa para definir seus valores

r
6. p.nome = "Rodrigo";
7. p.sobrenome = "Monteiro";

.b
8. p.dataNascimento = "25/12/1975";
9. p.rg = 11111;
10. String[] osTelefones = { "1234-5678", "8765-4321"};
11. p.telefones = osTelefones;

m
12. // Acessando os atributos para leitura
13. System.out.println("Nome : " + p.nome + " " + p.sobrenome );
14. System.out.println("Data Nasc : " + p.dataNascimento );

co
15. System.out.println("RG : " + p.rg );
16. System.out.println("Telefones:" );
17. for (int i=0; i < p.telefones.length ; i++){
18. System.out.println(p.telefones[i]);
19. }
20.
21.}
} g.
in
Código 1.4 - TestePessoa.java
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 18


1.2.4 Inicialização de atributos
Atributos são inicializados com valores padrão, ao contrário de variáveis locais, que devem ser inicializadas
explicitamente.
Se os atributos de uma classe não forem inicializados, eles terão o valor padrão definido de acordo com seu tipo,
de acordo com a tabela a seguir:

Tabela 1.2 - valores de inicialização padrão para atributos

r
Tipo Valor de Inicialização

.b
byte 0
short 0
int 0

m
float 0.0f
long 0L
double 0.0d

co
char ‘\u0000’
boolean false
refer.objeto null
g.
in
Atenção! Atributos do tipo array são inicializados com null, e portanto qualquer acesso a
elementos resultará em um erro em tempo de execução chamado NullPointerException,
nn

lembrando que não é possível acessar atributos ou métodos de objetos que estão com o valor
null, ou acessar elementos de arrays que estão nulos.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 19


1. class ExemploInicializacaoAtributos {
2.
3. public static void main(String[] args) {
4. // Cria-se uma instância da classe Pessoa
5. Pessoa p = new Pessoa();
6. // Acessando os atributos para leitura
7. System.out.println("Nome : " + p.nome + " " + p.sobrenome );
8. System.out.println("Data Nasc : " + p.dataNascimento );
9. System.out.println("RG : " + p.rg );
10. System.out.println("Telefones : " + p.telefones );

r
11. }

.b
12.}

Código 1.5 - ExemploInicializacaoAtributos.java

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 20


1.2.5 Laboratório : utilização de atributos

Objetivo:
Exercitar e fixar a criação de classes e utilização de atributos.

Tabela de atividades:
Atividade OK

r
1. Faça o download do arquivo aj2lab01_01.zip na URL indicada pelo instrutor(a).

.b
2. Descompacte o arquivo em seu diretório de trabalho.

3. Adicione os seguintes atributos na classe Agencia.

m
• número do tipo String
• banco do tipo int

co
4. Siga as instruções encontradas na classe TestaAgencia.

5. Adicione os seguintes atributos na classe Cliente.


• nome do tipo String
• cpf do tipo String

6. Siga as instruções encontradas na classe TestaCliente


g.
in
7. Adicione os seguintes atributos na classe Conta.
• saldo do tipo double
nn

• número do tipo String


• titular do tipo String
• agência do tipo int
ai

• banco do tipo int

8. Siga as instruções encontradas na classe TestaConta.


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 21


1.3 Métodos
As operações que podem ser executadas com ou sobre um objeto são definidas por meio de métodos, ou seja, os
métodos definem o comportamento da classe. Os métodos podem receber valores de entrada, necessários para
seu processamento, e gerar um valor de saída, resultado deste processamento. Esses valores de entrada e saída,
chamam-se respectivamente parâmetros e retorno do método.

1.3.1 Declaração de métodos

r
Métodos são declarados dentro do corpo da classe, ou seja, dentro do bloco de código da definição da classe, que

.b
é delimitado pela abertura e fechamento de chaves ({ e }).

m
Um método é dividido em três partes:
• retorno do método;
• nome do método;

co
• parâmetros do método.

Sintaxe para declaração de métodos


* <tipo do retorno> nomeDoMetodo (<parametrosDeMetodos>){}
g.
in
Sintaxe para declaração de <parametrosDeMetodos>:
(<tipo> identificador, ..., <tipo> identificador)
nn

*Alguns modificadores ou palavras reservadas podem ser aplicados a métodos alterando suas características e
ai

formas de acesso.
.tr

1.3.2 Convenções para nomes de métodos:

• iniciar os nomes dos métodos com letras minúsculas;


w

• separar nomes de métodos compostos por duas ou mais palavras com um


caractere maíusculo.
w
w

Trainning Education Services - Todos os direitos reservados 22


1.3.3 Retorno de métodos
Os métodos em Java podem retornar um valor para o código que os chamou. Este valor é usualmente o resultado
do processamento solicitado ao método. As regras para o uso deste valor são:

• para retornar o valor para quem chamou o método utiliza-se a instrução return;
• o tipo do valor retornado deve ser compatível com o tipo indicado na assinatura do método;
• o valor de retorno de um método pode ser uma literal (um valor explícito);

r
o retorno de um método pode ser obtido através da chamada a um método ou expressão;

.b
variáveis que recebem valores retornados nos métodos devem obrigatoriamente ser de tipo
compatível com o declarado na assinatura do método;
• os valores retornados por métodos não precisam ser armazenados em variáveis e podem ser,

m
opcionalmente, ignorados;
• quando um método não retorna valor nenhum, indica-se em sua declaração que seu tipo de retorno é

co
void;
• métodos com retorno void podem utilizar a instrução return sem parâmetros.

1. class ExemploMetodos {
2.
g.
in
3. //void indica que o método não retorna nada
4. void imprime() {
5. System.out.println("Este metodo nao retorna nada!");
nn

6. }
7. //o método DEVE retornar um int ou tipo primitivo compatível, caso
8. //contrário haverá um erro de compilação!!
9. int calculaFrete() {
10. return 19;
ai

11. }
12. //o método DEVE retornar um objeto da classe String, ou seja, um tipo
13. //reference
.tr

14. String getNome() {


15. return "Este metodo retorna uma String!";
16. }
17.}
w

Código 1.6 - ExemploMetodos.java


w
w

Trainning Education Services - Todos os direitos reservados 23


1.3.4 Passagem de parâmetros
Os parâmetros de um método devem ser declarados separadamente, usando-se (,) vírgula entre os parênteses
na declaração do método.
Denomina-se assinatura do método, o conjunto composto pelo nome do método mais a lista dos tipos de
parâmetros recebidos. Em chamadas a métodos, é obrigatório passar os parâmetros utilizando-se tipos
compatíveis aos definidos em sua assinatura, caso contrário, o compilador acusará um erro.

Exemplo de assinatura de método:

r
int soma(int x, int y) {

.b
return x + y;
}

m
assinatura: soma (int, int)

Em Java, parâmetros são sempre passados por valor, ou seja, uma cópia do valor da variável é transmitida ao

co
método. Algumas linguagens permitem a passagem de parâmetros por referência, isto é, com a própria variável
sendo transmitida ao método.

1. class Calculadora {
2.
g.
3. // a passagem de dois valores do tipo int (ou tipo compatível) é obrigatória
in
4. int soma(int x, int y) {
5. return x + y;
6. }
nn

7.
8. //a passagem de dois valores do tipo double(ou tipo compatível)é obrigatória
9. double multiplicacao(double d1, double d2) {
10. double resultado = d1 * d2;
11. return resultado;
ai

12. }
13.
14. // a passagem de dois valores do tipo int (ou tipo compatível) é obrigatória
.tr

15. boolean maior(int num1, int num2) {


16. if (num1 > num2)
17. return true;
18. else
w

19. return false;


20. }
21.
w

22. // a passagem de um parâmetro do tipo String é obrigatória


23. void print(String texto) {
24. System.out.println("Texto: " + texto);
w

25. }
26.}

Código 1.7 - Exemplo de passagem de parâmetros: Calculadora.java

Trainning Education Services - Todos os direitos reservados 24


1.3.5 Acessando métodos a partir de outras classes
Para acessar os métodos de uma classe a partir de outra, é necessário criar um objeto. A partir dessa instância, é
possível acessá-los, usando-se a seguinte sintaxe:

nomeVariavel.nomeDoMetodo(<parâmetros>);

Convém observar que a passagem de parâmetros é opcional e depende da assinatura do método.

r
Observe a seguir, a criação de uma classe chamada TesteCalculadora, cujo método main acessa os métodos

.b
da classe Calculadora definida anteriormente.

m
1. class TesteCalculadora {
2.
3. public static void main(String[] args) {

co
4. Calculadora c = new Calculadora();
5. c.print("Vamos testar a calculadora");
6. int resultado1 = c.soma(10, 10);
7. System.out.println(" 10 + 10 " + resultado1);
8.
9.
10.
11.
double resultado2 = c.multiplicacao(10, 10);
System.out.println(" 10 * 10 " + resultado2);
boolean resultado3 = c.maior(20, 1000);
System.out.println(" 20 > 1000 " + resultado3);
g.
in
12. }
13.}
nn

Código 1.8 - TesteCalculadora.java


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 25


1.3.6 Exemplos
Veja mais alguns exemplos para ilustrar a criação e manipulação de classes com atributos e métodos:

1. class Produto {
2. double preco;
3. String descricao;
4. String marca;
5.
6. void inicializaValores(double umPreco, String umaDescricao, String umaMarca)
7. {
8. preco = umPreco;

r
9. descricao = umaDescricao;

.b
10. marca = umaMarca;
11. }
12. void imprime() {
13. System.out.println("------------------------");

m
14. System.out.println("Produto : " + descricao);
15. System.out.println("Marca : " + marca);
16. System.out.println("Preco : " + preco);
17. System.out.println("------------------------");

co
18. }
19.}

Código 1.9 - Produto.java

1. class TesteProduto {
2.
3.
public static void main(String[] args) {
Produto p = new Produto();
g.
in
4. p.inicializaValores(9.0, "Produto X", "Marca Y");
5. p.imprime();
6. // aumento de 10% no preço do produto
nn

7. p.preco *= 1.1;
8. p.descricao = " Nova descricao";
9. p.marca = "Sem-marca";
10. p.imprime();
11. }
ai

12.}

Código 1.10 - TesteProduto.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 26


1. class Data {
2. int dia;
3. int mes;
4. int ano;
5.
6. boolean isAnoBissexto() {
7. if (((ano % 4 == 0) && !(ano % 100 == 0)) || (ano % 400 == 0))
8. return true;
9. else
10. return false;
11. }
12. void imprime() {

r
13. System.out.println(dia + "/" + mes + "/" + ano);

.b
14. }
15. }

Código 1.11 - Data.java

m
1. class TesteData {
2. public static void main(String[] args) {

co
3. Data d = new Data();
4. d.dia = 12;
5. d.mes = 1;
6. d.ano = 2004;
7. d.imprime();
8.
9.
10.
11.
String bi = d.isAnoBissexto() ? " " : " nao ";
g.
System.out.println("O ano " + d.ano + " " + bi + "e bissexto ");
in
12. Data d2 = new Data();
13. d2.imprime();
14.
nn

15. d2.dia = -20;


16. d2.mes = 23;
17. d2.ano = 9;
18. d2.imprime();
19.
ai

20. String bi2 = d2.isAnoBissexto() ? " " : " nao ";


21. System.out.println("O ano " + d2.ano + " " + bi2 + "e bissexto ");
22. }
23.}
.tr

Código 1.12 - TesteData.java


w
w
w

Trainning Education Services - Todos os direitos reservados 27


1.3.7 Erros comuns
O valor retornado pelo método deve ser compatível com o tipo indicado na assinatura do
método.
A tentativa de compilar a classe Calculadora definida abaixo recebeu um erro de compilação,
porque no cabeçalho / assinatura do método soma foi declarado que o método deveria retornar
um int, mas ele retornou um float, que não pode ser armazenado dentro de um int.

r
1. class CalculadoraRetornoIncorreto {

.b
2. int soma(int i, int j) {
3. float f = i + j;
4. return f;
5. }

m
6. }

Código 1.13 - CalculadoraRetornoIncorreto.java

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 28


Instrução inatingível
A classe abaixo tem uma instrução return dentro do primeiro if, outra dentro do primeiro else e
uma outra fora do if-else, que nunca será alcançada. Veja o erro de compilação gerado:

r
1. class ReturnInatingivel {
2. boolean teste() {

.b
3. int i = 0;
4. if (i > 0) {
5. return true;
6. } else {

m
7. return false;
8. }
9. return false;

co
10. }
11.}

Código 1.14 - ReturnInatingivel.java

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 29


Faltando instrução return em determinada condição
A classe abaixo tem uma instrução return dentro do if. No entanto, caso a condição do if
não seja satisfeita qual valor será retornado? Nenhum, pois a classe não irá compilar.

1. class SemReturn {

r
2. boolean teste() {

.b
3. int i = 0;
4. if (i > 0) { return true; }
5. }
6.}

m
Código 1.15 - SemReturn.java

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 30


1.3.8 Listas de parâmetros de tamanho variável (varargs)
Em diversas situações é preciso passar para um método um número variável de parâmetros (geralmente de um
mesmo tipo), e para isto é necessário que o método receba como tipo do parâmetro um array. Tradicionalmente,
antes da chamada do método, são inseridos todos os objetos que se quer passar nesse array, para finalmente
passá-lo como parâmetro.

Veja um exemplo:

r
1. class ImpressoraSemVarargs {
2. void listaNomes(String[] nomes) {

.b
3. System.out.println("Lista de nomes recebidos: ");
4. for (int i = 0; i < nomes.length; i++) {
5. System.out.println("\t " + nomes[i]);

m
6. }
7. }
8.
9. void listaNotas(double[] notas) {

co
10. System.out.println("Lista de notas recebidas: ");
11. for (int i = 0; i < notas.length; i++) {
12. System.out.println("\t " + notas[i]);
13. }
14. }
15.} g.
Código 1.16 - ImpressoraSemVarargs.java
in
1. class TesteImpressoraSemVarargs {
nn

2. public static void main(String[] args) {


3. ImpressoraSemVarargs imp = new ImpressoraSemVarargs();
4. //inicializando cada elemento do array individualmente
5. String[] candidatos = new String[3];
6. candidatos[0] = "Marcos da Silva";
ai

7. candidatos[1] = "Roberto da Costa";


8. candidatos[2] = "Ana Maria Soares";
9. imp.listaNomes(candidatos);
10. //inicializando o array todo de uma vez
.tr

11. imp.listaNotas(new double[] { 7.5, 8.75, 5.5});


12. }
13.}
w

Código 1.17 - TesteImpressoraSemVarargs.java


w
w

Trainning Education Services - Todos os direitos reservados 31


r
.b
m
A partir do Java 5, foi inserida uma opção de declaração de lista de parâmetros de tamanho variável na assinatura
dos métodos. Essa opção também é chamada de varargs.

co
Indica-se na assinatura do método ou do construtor que ele recebe um número de parâmetros variável com três
pontos, entre o tipo da variável e o nome da variável, como se observa no trecho de código abaixo.

public static void meuMetodo(TipoObjeto ... objetos){


g.
in
}
nn

O TipoObjeto pode ser um tipo primitivo, Object ou um tipo mais específico como Cliente, String, Date ou
outro qualquer e deve ser sempre o último parâmetro da lista.
ai

Os parâmetros devem ser passados na chamada do método separados por vírgula, e o próprio Java se encarrega
de transformar os objetos em um array.
.tr

Dentro do método o parâmetro objetos pode ser utilizado como um array, afinal de contas ele poderá conter um ou
mais objetos da classe indicada no TipoObjeto. Desta forma utiliza-se a propriedade length do array para
w

conhecer o número de elementos contidos no array, e é possível acessar seus elementos através do índice do
array, como se vê no exemplo a seguir:
w
w

Trainning Education Services - Todos os direitos reservados 32


1. class ImpressoraComVarargs {
2. void listaNomes(String... nomes) {
3. System.out.println("Lista de nomes recebidos: ");
4. for (int i = 0; i < nomes.length; i++) {
5. System.out.println("\t " + nomes[i]);
6. }
7. }
8.
9. void listaNotas(String msg, double... notas) {
10. System.out.println(msg);

r
11. for (int i = 0; i < notas.length; i++) {
12. System.out.println("\t " + notas[i]);

.b
13. }
14. }
15.}

m
Código 1.18 - ImpressoraComVarargs.java

co
1. class TesteImpressoraComVarargs {
2. public static void main(String[] args) {
3. ImpressoraComVarargs imp = new ImpressoraComVarargs();
4. imp.listaNomes("Marcos da Silva", "Roberto da Costa",
5.
6.
7.
8. }
"Ana Maria Soares"); g.
// método que recebe uma String e varargs do tipo double
imp.listaNotas("Lista de notas recebidas:", 7.5, 8.75, 5.5);
in
9. }

Código 1.19 - TesteImpressoraComVarargs


nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 33


1.3.10 Passagem de parâmetros de tipos primitivos
Quando uma variável do tipo primitivo é passada como parâmetro a um método, uma cópia do seu valor é
passada ao método.

1. class CalculadoraMaluca {
2. int multiplicaValores(int numero1, int numero2) {
3. int resultado = numero1 * numero2;
4. numero1 = 0;
5. numero2 = 0;

r
6. return resultado;
7. }

.b
8. }

Código 1.20 - CalculadoraMaluca.java

m
1. class TestePassagemPrimitivos {
2. public static void main(String[] args) {

co
3. int num1 = 4;
4. int num2 = 2;
5. CalculadoraMaluca calculadora = new CalculadoraMaluca();
6. System.out.println("O valor de num1 antes do metodo multiplica:" + num1);
7. System.out.println("O valor de num2 antes do metodo multiplica:" + num2);
8.
9.
10.
11.
g.
//o método multiplica atribui zero aos dois parâmetros recebidos
calculadora.multiplicaValores(num1, num2);
in
12. System.out.println("O valor de num1 apos o metodo:" + num1);
13. System.out.println("O valor de num2 apos o metodo:" + num2);
14. }
nn

15.}

Código 1.21 - TestePassagemPrimitivos.java


ai

As variáveis numero1 e numero2 armazenam uma cópia dos valores de num1 e num2, ou seja, depois da
execução do método multiplicaValores o valor das variáveis num1 e num2 continuam intactos, conforme se
.tr

observa na saída gerada ao executar a classe TestePassagemPrimitivos:


w
w
w

Trainning Education Services - Todos os direitos reservados 35


1.3.11 Passagem de parâmetros de tipos reference (Objetos e arrays)
Toda variável do tipo reference armazena uma referência para o objeto e não o próprio objeto.

Ao passar uma variável do tipo reference, uma cópia da referência para o objeto é gerada, portanto serão duas
variáveis armazenando referências para o mesmo objeto e as modificações feitas dentro do método serão
percebidas fora do método. Este comportamento não ocorre com variáveis primitivas, conforme observado no item
anterior.

r
.b
m
co
g.
Figura 1.1 - passagem de variáveis tipo reference
in
1. class TestePassagemObjetos {
nn

2. public static void main(String[] args) {


3. Data data1 = new Data();
4. System.out.println("Valores iniciais para data1:");
5. System.out.println("Dia: " + data1.dia);
6. System.out.println("Mes: " + data1.mes);
ai

7. System.out.println("Ano: " + data1.ano);


8. TestePassagemObjetos testador = new TestePassagemObjetos();
9. testador.alteraData(data1);
.tr

10. System.out.println("Valores atuais para data1:");


11. System.out.println("Dia: " + data1.dia);
12. System.out.println("Mes: " + data1.mes);
13. System.out.println("Ano: " + data1.ano);
w

14. }
15. void alteraData(Data data2) {
16. data2.dia = 10;
w

17. data2.mes = 12;


18. data2.ano = 2008;
19. }
w

20.}

Código 1.22 - TestePassagemObjetos.java

Trainning Education Services - Todos os direitos reservados 36


1.4 Certificação Oracle Certified Java Programmer (OCJP)
1. What will happen when you attempt to compile and run the following code

1. class Foo {
2.
3. int i1 = 25;
4. int i2;
5. char c = 1;
6. boolean b;

r
7.
8. public static void main(String... args) {

.b
9. Foo foo = new Foo();
10. foo.method();
11. }

m
12.
13. void method() {
14. boolean b;
15. System.out.println(i2);

co
16. System.out.println(b);
17. }
18.}

A) Compilation succeeds and at runtime there is an output of 0 and false


B) Compilation succeeds and at runtime there is an output of 0 and true
g.
in
C) Compile time error b is not initialized
D) Compile time error c must be assigned a char value
nn

E) Runtime error java.lang.NoSuchMethodError: main, caused by wrong declaration of main method


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 38


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Introdução a UML
.tr

UML e metodologias de desenvolvimento de software


Principais diagramas da UML
w

Introdução ao diagrama de classes


w
w

Trainning Education Services - Todos os direitos reservados 39


2 Introdução a UML
A UML é uma linguagem de modelagem de software
A UML (Unified Modeling Language) é uma linguagem que é formada por um número de
elementos gráficos combinados para formar diagramas. Por ser uma linguagem, a UML tem
regras para a combinação desses elementos.

r
O propósito dos diagramas é apresentar múltiplas visões de um sistema. O conjunto dessas múltiplas visões é

.b
chamado de modelo. É importante deixar claro que um modelo UML diz o que um sistema deve fazer, mas não
como implementá-lo.

m
A UML unifica os métodos de Grady Booch, James Rumbaugh e Ivar Jacobson.

co
Nos anos 80 e no começo dos anos 90 esses três pesquisadores trabalhavam em diferentes empresas, cada um
desenvolvendo sua própria metodologia para análise e projeto de softwares orientados a objetos. Na metade dos
anos 90 eles resolveram unir suas metodologias e criar uma nova , aproveitando o que havia de bom em cada
uma delas.

A UML é padronizada pela OMG (Object Management Group)


g.
in
Em 1997 um consórcio formado por grandes empresas do mercado, tais como, Oracle, HP, Texas Instruments,
Rational, produziu a versão 1.0 da UML e o submeteu à aprovação do OMG. Mais tarde,outra versão, a 1.1, foi
nn

submetida ao OMG, que então adotou a UML como linguagem de modelagem de software padrão, e passou a
manter e produzir suas novas versões. Atualmente a UML está em sua versão 2.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 41


2.1 UML e metodologias de desenvolvimento de software

Uma metodologia define as etapas que devem ser seguidas para desenvolvimento de um sistema. Algumas
metodologias, como o RUP (Rational Unified Process), utilizam a UML como base para a modelagem. Quando
isso ocorre, a metodologia é responsável por indicar em qual fase do desenvolvimento cada diagrama deve ser
utilizado. Desta forma, a UML não define quando cada diagrama deve ser utilizado, e sim qual visão do sistema

r
ele oferece.

.b
Muitas vezes é inviável desenhar todos os diagramas para o projeto e, por isso, selecionam-se os diagramas mais
interessantes para cada caso. É importante conhecer o objetivo e o público alvo de cada diagrama, de forma a

m
criar diagramas úteis. Um mesmo tipo de diagrama pode ser criado com diferentes níveis de detalhe, dependendo
de quem deve lê-lo, isto é diagramas mais detalhados para um público mais técnico, e outros com menos detalhes

co
para um público de nível gerencial.

No próximo tópico serão comentados diagramas utilizados com freqüencia independentemente de sua
metodologia. g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 42


2.2 Principais diagramas da UML

2.2.1 Diagrama de casos de uso


Representa-se neste diagrama os casos de uso de um sistema, ou seja, suas funcionalidades , e por isso esse
diagrama geralmente é utilizado no início de um projeto, na fase de análise de requisitos.

r
.b
m
co
g.
in
nn
ai
.tr

Diagrama 2.1 - exemplo de diagrama de casos de uso


w

2.2.2 Diagrama de classes


w

O diagrama de classes é utilizado para representar a estrutura do sistema, ou seja, as classes do sistema.
Normalmente este diagrama é utilizado durante todo o projeto. No início, na fase de análise de requisitos ele é
utilizado para fazer a modelagem conceitual do sistema e representar as entidades mais evidentes e o seu
w

relacionamento , sem ainda a preocupação com detalhes de implementação.

Trainning Education Services - Todos os direitos reservados 43


Na fase de implementação, refina-se o diagrama de classes conceitual concebido na análise de requisitos e cria-
se então o chamado diagrama de classes de implementação. Este diagrama é atualizado sempre que houver
atualizações no sistema.

Algumas variações do diagrama de classes são: o diagrama de pacotes e o diagrama de objetos. O primeiro
agrupa classes semelhantes em estruturas denominadas pacotes e o segundo representa instâncias de classes
(objetos) em um determinado instante no tempo.

r
.b
m
co
g.
in
nn
ai
.tr

Diagrama 2.2 - exemplos de diagramas de classe em diversos graus de detalhes


w

2.2.3 Diagrama de estados


w

Para se representar a mudança de estado de determinada entidade de um sistema utiliza-se o diagrama de


estados, que é uma evolução dos diagramas usados na programação procedural para representar as chamadas
w

"máquinas de estados finitos".

Trainning Education Services - Todos os direitos reservados 44


Imagine a entidade pagamento em qualquer sistema que efetue uma venda: é possível imaginar estados para um
pagamento, pagamento recebido, pagamento compensado, pagamento não compensado (Cheque
devolvido),entre outros. Para entidades que possuem estados bem definidos é aconselhável desenhar o diagrama
de estados.

r
.b
m
co
g.
in
nn

Diagrama 2.3 - exemplo de diagrama de estados

2.2.4 Diagrama de seqüência


ai

O diagrama de seqüência representa a parte dinâmica de um sistema. Demonstra quais os passos a seguir, em
uma linha do tempo, para que determinada tarefa seja executada. Em um diagrama mais detalhado, estes passos
.tr

podem ser chamadas a métodos de classes. Utiliza-se este diagrama para mostrar a arquitetura de um sistema,
design patterns implementados e interações entre classes.
w
w
w

Trainning Education Services - Todos os direitos reservados 45


r
.b
m
co
Diagrama 2.4 - exemplo de diagrama de seqüência

2.2.5 Diagrama de comunicação g.


O diagrama de comunicação é uma visão semelhante aquela apresentada pelo diagrama de seqüência, contudo
in
sem a preocupação do espaço temporal. Permite uma visão mais organizada das classes e suas colaborações,
sem a necessidade de se compreender esse relacionamento ao longo do tempo. Na versão anterior da UML (1.x)
era chamado de diagrama de colaboração.
nn
ai
.tr
w
w
w

Diagrama 2.5 - exemplo de diagrama de comunicação

Trainning Education Services - Todos os direitos reservados 46


2.2.6 Diagrama de componentes
O diagrama de componentes é utilizado para mostrar os componentes do sistema. Nele é possível detalhar as
classes que formam os componentes e o seu relacionamento .

r
.b
m
co
Diagrama 2.6 - exemplo de diagrama de componentes

2.2.7 Diagrama de instalação / deployment g.


O diagrama de instalação ou deployment é empregado para detalhar a estrutura utilizada para implantar o sistema
in
dentro de um contêiner. Este diagrama é útil para que os administradores dos servidores JavaEE saibam o que
fazer com as classes e componentes produzidos pela equipe de desenvolvimento.
nn
ai
.tr
w
w
w

Diagrama 2.7 - exemplo de diagrama de instalação

Trainning Education Services - Todos os direitos reservados 47


2.2.8 Diagrama de atividades
O diagrama de atividades é muito parecido com o fluxograma comumente utilizado na programação procedural. É
uma evolução deste diagrama, e é bastante utilizado na fase de análise de requisitos pois é útil para modelar
processos complexos como regras de negócio. Pode também ser utilizado para representação de algoritmos,
navegação entre telas, fluxo de casos de uso e processos concorrentes.

r
.b
m
co
g.
in
nn
ai
.tr

Diagrama 2.8 - exemplo de diagrama de atividades


w
w
w

Trainning Education Services - Todos os direitos reservados 48


2.3 Introdução ao diagrama de classes
Um diagrama de classes descreve os tipos de objetos no sistema e o relacionamento entre eles,
mostrando os métodos e atributos de cada classe.

Uma classe pode ser representada por uma caixa contendo apenas o nome
da classe, ou por uma caixa com atributos e métodos.

r
Diagrama 2.9 - Representação simples de classe

.b
2.3.1 Representando atributos
A representação de atributos de uma classe em UML é feita de forma diferente da que foi definida em Java, pois

m
declara-se primeiramente o nome do atributo e depois o tipo, separando-os pelo símbolo “:” (dois pontos).

co
Diagrama 2.10 - Representação de atributos
g.
in
2.3.2 Representando métodos
A representação de métodos de uma classe em UML é feita de forma diferente da que foi definida em Java, pois
nn

declara-se primeiramente o nome do método, e depois o tipo do valor de retorno do método.

A declaração dos parâmetros do método deve ser feita da


ai

mesma forma que aquela definida para os atributos:


primeiramente declara-se o nome e depois o tipo, separados
pelo símbolo " : " (dois pontos).
.tr
w
w
w

Diagrama 2.11 - Representação de métodos

Trainning Education Services - Todos os direitos reservados 49


Exercício: Modelagem de classes

Desenhe no papel três definições de objetos do mundo real, com estruturas e


comportamento específicos.

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 50


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Encapsulamento
.tr

Getters e Setters
Modificadores de acesso
w

Objeto this
Encapsulamento de atributos compostos
Acoplamento
w
w

Trainning Education Services - Todos os direitos reservados 51


3 Encapsulamento
Conforme os exemplos anteriores das classes Produto, Data, TesteProduto e TesteData, verificou-se
que é possível criar um objeto da classe Data e colocar um ano negativo, um dia inválido e um mês igual a 123,
ou ainda um produto com preço negativo, sem nenhum controle ou regra.

Para uma implementação mais robusta 1 desses atributos, o acesso deve ser mais controlado, ou seja, realizado
mediante métodos que permitam criar regras para atribuição e leitura. Esta prática é chamada encapsulamento de

r
atributos.

.b
Veja algumas vantagens que podem ser obtidas utilizando-se o encapsulamento:

m
• validar valores a serem escritos em cada atributo;
• definir quais e quando os atributos podem ser alterados;

co
• fazer um log das modificações dos atributos;
• oferecer acesso aos atributos através de métodos. Modificações futuras nos
atributos serão facilitadas, pois muitas vezes não será necessário modificar a
g.
assinatura do método que o encapsula.
in
O encapsulamento de atributos pode utilizar métodos padronizados. Contudo, quando existirem métodos
relacionados à lógica de negócio, ou ainda, que facilitem a manipulação de atributos, pode-se utilizar nomes que
não sigam esta convenção.
nn

Os métodos-padrão para encapsulamento são chamados Getters e Setters.


ai
.tr
w
w
w

1
robustez neste caso é um termo técnico que define o grau com o qual o sistema continua a se comportar
normalmente quando submetido a entradas inválidas, defeitos de software e hardware, etc.

Trainning Education Services - Todos os direitos reservados 53


3.1 Getters e Setters

3.1.1 Métodos get


São métodos que permitem a leitura de atributos da classe. É uma boa prática criá-los para cada atributo que será
encapsulado.

Convenções

r
<modificadores> <tipoAtributo> get + <nomeAtributo> ( )

.b
Exemplos
String getNome()

m
long getRg()

3.1.2 Métodos set

co
São métodos que modificam o valor dos atributos. O uso destes métodos, em vez da escrita direta no atributo, é
indicado para protegê-los da escrita ou modificação indevida. É possível estabelecer certas normas e controles
dentro dos métodos Setters.

Convenções
g.
<modificadores> void set + <nomeAtributo> (<tipoAtributo> <nomeParametro>)
in
Exemplos
void setNome(String nome)
nn

void setRg(long rg)

3.1.3 Métodos is
ai

São métodos utilizados para leitura de atributos booleanos.

Convenções
.tr

boolean is + <nomeAtributo> ()

Exemplos
w

boolean isConnected()
boolean isOk()
w

Veja, a seguir, como encapsular três atributos da classe Produto. Para os atributos marca e descricao serão
utilizadas as formas padronizadas de encapsulamento (getters e setters) , mas para o preço serão usados
w

métodos de encapsulmento que agregam funcionalidade à classe. Exemplo: aumento de preço realizado através
do método aumentarPreco.

Trainning Education Services - Todos os direitos reservados 54


1. class Produto {
2. String descricao, marca;
3. double preco;
4.
5. void valoresIniciais(double umPreco, String umaDescricao, String umaMarca) {
6. alterarPreco(umPreco);
7. setDescricao(umaDescricao);
8. setMarca(umaMarca);
9. }
10. String getDescricao() {
11. return descricao;

r
12. }

.b
13. void setDescricao(String novaDescricao) {
14. descricao = novaDescricao;
15. }

m
16. String getMarca() {
17. return marca;
18. }

co
19. void setMarca(String novaMarca) {
20. marca = novaMarca;
21. }
22. double getPreco() {
23. return preco;
24. }
25. void alterarPreco(double novoPreco) {
26. if (novoPreco > 0) {
g.
in
27. preco = novoPreco;
28. }
29. }
nn

30. void aumentarPreco(double porcentagem) {


31. if (porcentagem > 0) {
32. System.out.println("aumentando o preco em " + porcentagem + " %");
33. porcentagem = 1 + (porcentagem / 100);
34. preco *= porcentagem;
ai

35. System.out.println("Novo preco = " + preco);


36. } else {
37. System.out.println("aumento deve ser maior do que zero");
38. }
.tr

39. }
40. void imprime() {
41. System.out.println("------------------------");
42. System.out.println("Produto : " + descricao);
w

43. System.out.println("Marca : " + marca);


44. System.out.println("Preco : " + preco);
45. System.out.println("------------------------");
w

46. }
47.}
w

Código 3.1 - Produto.java

Trainning Education Services - Todos os direitos reservados 55


1. class TesteProduto {
2. public static void main(String[] args) {
3. Produto p = new Produto();
4. p.valoresIniciais(9.0, "Produto X", "Marca Y");
5. p.imprime();
6. p.aumentarPreco(10);
7. p.setDescricao("Casual Class");
8. p.setMarca("trainning");
9. p.imprime();
10. }
11.}

r
.b
Código 3.2 - TesteProduto.java

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 56


1. class Data {
2. int dia;
3. int mes;
4. int ano;
5.
6. int getAno() {
7. return ano;
8. }
9. void setAno(int anoNovo) {
10. ano = anoNovo;

r
11. }

.b
12. int getDia() {
13. return dia;
14. }
15. void setDia(int diaNovo) {

m
16. dia = diaNovo;
17. }
18. int getMes() {
19. return mes;

co
20. }
21. void setMes(int mesNovo) {
22. mes = mesNovo;
23. }
24.
25.
26.
27.
boolean isAnoBissexto() { g.
if (((ano % 4 == 0) && !(ano % 100 == 0)) || (ano % 400 == 0))
return true;
in
28. else
29. return false;
30. }
31. void imprime() {
nn

32. System.out.println(dia + "/" + mes + "/" + ano);


33. }
34.}
ai

Código 3.3 - Data.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 57


1. class TesteData {
2.
3. public static void main(String[] args) {
4. Data d = new Data();
5. d.setDia(12);
6. d.setMes(01);
7. d.setAno(2004);
8. d.imprime();
9. String s = d.isAnoBissexto() ? " " : " nao ";

r
10. System.out.println("O ano " + s + "e bissexto ");

.b
11. }
12.}

Código 3.4 - TesteData.java

m
co
g.
in
Conforme demonstrado, em vez de se modificar os atributos diretamente, é possível fazê-lo através dos métodos
nn

de acesso aos atributos. No entanto, ainda não é possível evitar que desenvolvedores acessem os atributos
diretamente; para isso, é necessário utilizar modificadores de acesso.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 58


3.2 Modificadores de acesso
No exemplo anterior foram implementados os getters e os setters, mas não é possível garantir que todos os
atributos sejam acessados SOMENTE via métodos, isto é, mesmo se oferecendo métodos de acesso aos
atributos, ainda é possível alterá-los diretamente.

O conceito de modificadores de acesso visa controlar a acessibilidade dos elementos que compõem a classe.
Conseqüentemente, é possível definir por meio de modificadores, que apenas os métodos podem ser chamados,

r
restringindo o acesso direto aos atributos.

.b
3.2.1 Modificador public
O modificador public altera o elemento ao qual é aplicado, permitindo que seja acessado diretamente por qualquer

m
classe. Pode ser aplicado a classes, atributos e métodos.

co
Sintaxe
public <tipo> <identificador>
public <tipoRetorno> <identificadorMetodo> (<parametros>)
public class <nomeClasse>

1. public class Pessoa {


2. public int id;
g.
in
3. public String nome;
4. public void imprime() {
5. System.out.println(id + " : " + nome);
nn

6. }
7.}

Código 3.5 - Pessoa.java


ai

Representação UML do modificador public


A representação do modificador public na UML é feita adicionando o símbolo “+” na frente de
.tr

atributos e métodos, como no exemplo da classe Pessoa:


w
w
w

Diagrama 3.1 - representação UML do modificador public

Trainning Education Services - Todos os direitos reservados 59


3.2.2 Modificador private
Quando o modificador private é utilizado em atributos ou métodos, os elementos só podem ser acessados de
dentro da própria classe, ou seja, não são visíveis fora da classe.

Sintaxe
private <tipo> <identificador>
private <tipoRetorno> <identificadorMetodo> (<parametros>)

r
.b
m
co
g.
in
nn

Figura 3.1 - exemplo de uso de modificadores private


ai

Representação UML do modificador private


A representação do modificador private na UML é feita adicionando o símbolo “-“ na frente do
.tr

atributo ou método.Veja o exemplo da classe Pessoa:


w
w
w

Diagrama 3.2 - representação UML do modificador private

Trainning Education Services - Todos os direitos reservados 60


Se não for utilizado nenhum modificador, o que acontece ?

Ocorre uma restrição de acesso denominada package ou default. Esta restrição de acesso
será abordada em mais detalhes no capítulo dedicado a pacotes. Por enquanto, basta
saber que ela é mais restritiva que public e menos que private.

r
3.2.3 Quando utilizar private ou public?

.b
• Utiliza-se o modificador de acesso public em atributos, quando for necessário que seus valores
possam ser manipulados diretamente por objetos de outras classes.

m
• Utiliza-se o modificador de acesso private para criar variáveis que possam ser acessadas somente
por métodos da própria classe, ou então acessados, via setters e getters, por outras classes.

co
Recomendação

g.
Recomenda-se que os atributos sejam protegidos, portanto eles devem ser private e
acessados via setters. Isso facilita posteriores modificações no código, assim como garante
in
a integridade do código. Haverá algum overhead no encapsulamento mas ele será MÍNIMO.
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 61


3.2.4 Exemplos
A seguir, são apresentadas as classes Produto e Data modificadas para utilizar encapsulamento de atributos.
Observa-se nas saídas geradas pela compilação dos códigos de teste, que ocorrem erros de compilação na
tentativa de acesso aos atributos privados. A única maneira de obter acesso aos atributos é através dos métodos
getters e setters criados.

1. class Produto {
2. private double preco;

r
3. private String descricao;

.b
4. private String marca;
5. // ... demais métodos permanecem idênticos ao exemplo anterior de Produto
6.}

m
Código 3.6 - Produto.java modificada com encapsulamento de atributos

co
1. class TesteProduto {
2. public static void main(String[] args) {
3. Produto p = new Produto();
4. p.valoresIniciais(9.0, "Produto X", "Marca Y");
5. p.imprime();
6.
7.
8.
// aumento de 10% no preço do produto
p.preco *= 1.1;
g.
in
9. p.descricao = "Nova descricao";
10. p.marca = "Sem-marca";
11. }
12. }
nn

Código 3.7 - TesteProduto.java com tentativa de acesso a atributos privados


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 62


1. class Data {
2.
3. private int dia;
4. private int mes;
5. private int ano;
6. // ... demais métodos permanecem idênticos ao exemplo anterior de Data
7. }

Código 3.8 - Data.java com encapsulamento de atributos

r
.b
1. class TesteData {
2.

m
3. public static void main(String[] args) {
4. Data d = new Data();
5. d.dia = -20;
6. d.mes = 23;

co
7. d.ano = 9;
8. d.imprime();
9. String s = d.isAnoBissexto() ? " " : " nao ";
10. System.out.println("O ano " + s + "e bissexto ");
11. }
12.} g.
Código 3.9 - TesteData.java com tentativa de acesso a atributos privados
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 63


3.3 Objeto this
Foi visto anteriormente, que o acesso a atributos e métodos de um objeto é feito através de uma variável que
referencia o objeto.

Sintaxe
nomeVariavel.nomeAtributo
nomeVariavel.nomeDoMetodo(<parâmetros>)

r
.b
Qualquer instância de classe possui, por default, um objeto implícito denominado this, utilizado para o acesso
aos atributos e métodos da própria instância. Diz-se que o objeto é implícito porque não é declarado

m
explicitamente no código da classe, e sim acrescentado automaticamente.

Sintaxe
this.nomeAtributo

co
this.nomeDoMetodo(<parâmetros>)

O uso do objeto this não é obrigatório. O compilador utiliza implicitamente o objeto this para acessar um
g.
atributo ou um método da própria instância. Por exemplo: é definida uma classe Produto com um atributo de nome
marca; para que instâncias de Produto acessem o valor do atributo marca, utiliza-se explicitamente o objeto this
in
escrevendo-se this.marca, ou simplesmente marca.
nn

Uma situação especial ocorre quando há ambigüidade no nome de variáveis, ou seja, o mesmo nome pode
referenciar uma variável local ou um atributo. Neste caso, a JVM dá preferência a variável local e deve ser
utilizado explicitamente o objeto this caso se deseje referenciar o atributo, como demonstrado a seguir:
ai

1. public class Produto {


2. private String marca;
3.
.tr

4. public String getMarca() {


5. return marca;
6. }
7. public void setMarca(String marca) {
w

8. this.marca = marca;
9. }
10. /*
11. * utilizando this, indica-se que o atributo marca da
w

12. * classe Produto (this.marca)


13. * irá receber o parâmetro marca, que possui o mesmo nome do atributo
14. */
w

15.}

Código 3.10 - Produto.java utilizando o objeto implícito this.

Trainning Education Services - Todos os direitos reservados 64


1. public class ProdutoComBug {
2. private String marca;
3.
4. public String getMarca() {
5. return marca;
6. }
7. public void setMarca(String marca) {
8. marca = marca;
9. }
10.}
Código 3.11 - ProdutoComBug.java

r
.b
1. public class TesteProduto {
2. public static void main(String[] args) {

m
3. Produto p1 = new Produto();
4. ProdutoComBug p2 = new ProdutoComBug();
5. p1.setMarca("Brastemp");
6. p2.setMarca("Eletrolux");

co
7. System.out.println("Produto 1 = " + p1.getMarca());
8. System.out.println("Produto 2 = " + p2.getMarca());
9. }
10.}

g.
Código 3.12 - TesteProduto.java
in
nn
ai

Observa-se que na classe ProdutoComBug não é feita a atribuição do parâmetro passado para o atributo. Isto
acontece porque foi feita uma atribuição da variável local para ela mesma, e não para o atributo.
.tr
w
w
w

Figura 3.2 - referência this

Trainning Education Services - Todos os direitos reservados 65


3.4 Encapsulamento de atributos compostos
Existem duas formas de encapsular atributos representados por arrays.

1. Criar getters e setters que retornam e recebem respectivamente arrays, como no


atributo pessoas[] na classe MauDepartamento:

r
1. public class MauDepartamento {

.b
2.
3. private String nome;
4. private Pessoa[] pessoas;

m
5.
6. public void setNome(String nome) {
7. this.nome = nome;
8. }

co
9. public String getNome() {
10. return nome;
11. }
12. public void setPessoas(Pessoa[] pessoas) {
13. this.pessoas = pessoas;
14. }
15. public Pessoa[] getPessoas() {
16.
17. }
return pessoas;
g.
in
18. public void imprime() {
19. System.out.println("----------------------------------");
20. System.out.println("Departamento: " + this.getNome());
nn

21. // É preciso garantir que o array de pessoas tenha sido inicializado


22. // e, por isso deve ser diferente de null.
23. if (pessoas != null) {
24. for (int i = 0; i < pessoas.length; i++) {
25. System.out.println(pessoas[i].getNome());
ai

26. }
27. } else
28. System.out.println("Nao ha pessoas neste departamento");
29. System.out.println("----------------------------------");
.tr

30. }
31.}

Código 3.13 - MauDepartamento.java


w
w
w

Trainning Education Services - Todos os direitos reservados 66


1. public class Pessoa {
2.
3. private String nome;
4. private String rg;
5.
6. public String getNome() {
7. return nome;
8. }
9.
10. public void setNome(String nome) {
11. this.nome = nome;
12. }

r
13.

.b
14. public String getRg() {
15. return rg;
16. }
17.

m
18. public void setRg(String rg) {
19. this.rg = rg;
20. }
21.}

co
Código 3.14 - Pessoa.java

g.
Essa implementação apresenta problemas e, portanto, não deve ser utilizada. Veja a seguir:

Como fazer se for necessário adicionar apenas uma pessoa ao departamento?


in
Realizar as seguintes operações:
1) obter a referência para o array de pessoas
nn

2) criar um novo array com capacidade para uma pessoa a mais;


3) transferir as pessoas do array de pessoas para o novo array de pessoas com maior capacidade;
4) associar o novo array de pessoas ao departamento.
ai

Como consultar se uma pessoa pertence ou não ao departamento ?


.tr

Realizar as seguintes operações:


1) obter a referência para o array de pessoas;
2) navegar pelo array de pessoas até encontrar a pessoa desejada;
w

3) armazenar em uma variável booleana se a pessoa foi encontrada ou não.


w
w

Trainning Education Services - Todos os direitos reservados 67


Como remover uma pessoa do departamento?
Realizar as seguintes operações:
1) obter a referência para o array de pessoas;
2) navegar pelo array de pessoas até encontrar a pessoa desejada;
3) transferir todos os elementos para um array com capacidade menor, se a pessoa for encontrada;
4) associar o novo array de pessoas ao departamento.

Nota: Também é possível marcar posições como null e, ao adicionar elementos antes de fazer o

r
redimensionamento, procurar as posições não preenchidas. Para isso, porém, é necessário fazer o controle

.b
dessas posições.

m
E para repetir estas operações mais de uma vez?
É preciso repetir todo o código tantas vezes quanto o número de repetições da operação,e isso é um absurdo!

co
Lembre-se que o encapsulamento não serve apenas para “proteger” ou “controlar” um atributo, mas também para
evitar que um mesmo trecho de código seja repetido muitas vezes, minimizando o esforço de manutenção.

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 68


2. Criação de métodos para adição, remoção e busca de elementos.
Nesse exemplo,imagine os métodos:

• void addPessoa(Pessoa p)
• Pessoa getPessoa(String rg)
• void removePessoa(Pessoa p)

Há também a opção de retornar um booleano (indicando a real remoção da Pessoa) ou o objeto removido.

r
.b
1. public class Departamento {
2.
3. private String nome;
4. private Pessoa[] pessoas;

m
5. private int numeroPosicoesLivres = 0;
6.
7. public void setNome(String nome) {

co
8. this.nome = nome;
9. }
10.
11. public String getNome() {
12. return nome;
13. }
14.
15. public void setPessoas (Pessoa[] pessoas) {
16. this.pessoas = pessoas;
g.
in
17. }
18.
19. public Pessoa[] getPessoas() {
nn

20. return pessoas;


21. }
22.
ai

Código 3.15 - Departamento.java (primeira parte)


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 69


23.public void addPessoa(Pessoa pessoa) {
24. System.out.println("Adicionando " + pessoa.getNome() + " ao departamento");
25. if (numeroPosicoesLivres > 0) {
26. System.out.println("Existem posicoes livres no departamento");
27. // inserção na posição disponível; não será necessário redimensionar o
28. // array
29. pessoas[pessoas.length - numeroPosicoesLivres] = pessoa;
30. numeroPosicoesLivres--;
31. }else {
32. System.out.println("Aumentando a capacidade de pessoas do depto");

r
33. Pessoa[] novoArrayPessoas = new Pessoa[pessoas.length + 1];

.b
34. for (int i = 0; i < pessoas.length; i++) {
35. novoArrayPessoas[i] = pessoas[i];
36. }
37. novoArrayPessoas[novoArrayPessoas.length - 1] = pessoa;

m
38. pessoas = novoArrayPessoas;
39. }
40. }
41.

co
42. public Pessoa getPessoa(String rg) {
43. for (int i = 0;
44. (i < pessoas.length - numeroPosicoesLivres); i++) {
45. if (pessoas[i].getRg().equals(rg)) { return pessoas[i]; }
46.
47.
48.
49. }
} g.
// Se a pessoa com o rg passado não foi encontrada retornar null
return null;
in
50.
51. public Pessoa removePessoa(Pessoa p) {
52. String rgPessoa = p.getRg();
nn

53. int i = 0;
54.
55. while (i < pessoas.length - numeroPosicoesLivres) {
56. if (pessoas[i].getRg().equals(rgPessoa)) {
57. // Indicar que a pessoa foi removida trazendo o último elemento
ai

58. // do array para a posição e colocando null na última posição.


59. Pessoa pessoaRemovida = pessoas[i];
60. pessoas[i] = pessoas[pessoas.length - 1 - numeroPosicoesLivres];
.tr

61. pessoas[pessoas.length - 1 - numeroPosicoesLivres] = null;


62. numeroPosicoesLivres++;
63. System.out.println(pessoaRemovida.getNome()
64. + " foi removido(a) do departamento");
w

65. return pessoaRemovida;


66. }
67. i++;
68. }
w

69. // Se a pessoa com o rg passado com parâmetro não foi


70. // encontrada retornar null indicando que a remoção não foi feita
71. return null;
w

72. }

Código 3.15 - Departamento.java ( continuação )

Trainning Education Services - Todos os direitos reservados 70


73. public void imprime() {
74. System.out.println("----------------------------------");
75. System.out.println("Departamento: " + nome);
76. // É preciso garantir que o array de pessoas foi inicializado e por isso
77. // é diferente de null,caso contrário poderá ocorrer uma
78. // NullPointerException
79. if (pessoas != null) {
80. int i = 0;
81. // É necessario garantir que as posições não estão vazias,

r
82. // e que não estão sendo impressas posições inválidas,

.b
83. // ou seja, maiores do que o array
84. while ((i < pessoas.length)) {
85. System.out.print("[" + i + "]");
86. if (pessoas[i] != null) {

m
87. System.out.print(pessoas[i].getNome());
88. System.out.println(" " + pessoas[i].getRg());
89. } else {
90. System.out.println("Posicao Livre");

co
91. }
92. i++;
93. }
94. } else {
95. System.out.println("Nao ha pessoas neste departamento");
96.
97.
98. }
} g.
System.out.println("----------------------------------");
in
99.
100.}
nn

Código 3.15 - Departamento.java ( continuação )


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 71


1. public class TesteDepartamento {
2. public static void main(String[] args) {
3. // Criação das pessoas para o array de pessoas do departamento
4. Pessoa p1 = new Pessoa();
5. p1.setNome("Renato");
6. p1.setRg("11111");
7. Pessoa p2 = new Pessoa();
8. p2.setNome("Fernanda");
9. p2.setRg("22222");
10. // Criação do array de pessoas para o departamento

r
11. Pessoa[] pessoasDpto = {p1, p2};
12.

.b
13. // Criação do departamento
14. Departamento d = new Departamento();
15. d.setNome("Departamento compras");

m
16. d.setPessoas(pessoasDpto);
17. System.out.println("Departamento recem criado");
18. d.imprime();
19.

co
20. Pessoa novaPessoa = new Pessoa();
21. novaPessoa.setNome("Nova Pessoa da Silva");
22. novaPessoa.setRg("33333");
23. d.addPessoa(novaPessoa);
24. d.imprime();
25.
26.
27.
28.
d.removePessoa(p1);
d.imprime();
g.
in
29. Pessoa p3 = new Pessoa();
30. p3.setNome("Raquel");
31. p3.setRg("33333");
nn

32. d.addPessoa(p3);
33. d.imprime();
34.
35. Pessoa p4 = new Pessoa();
36. p4.setNome("Gustavo");
ai

37. p4.setRg("44444");
38. d.addPessoa(p4);
39. d.imprime();
40.
.tr

41. System.out.println("Procurando a pessoa com rg = 33333");


42. Pessoa procurada1 = d.getPessoa("33333");
43. if (procurada1 != null) System.out.println(procurada1.getNome());
44.
w

45. System.out.println("Procurando a pessoa com rg = 555");


46. Pessoa procurada2 = d.getPessoa("555");
47. if (procurada2 != null)
w

48. System.out.println(procurada2.getNome());
49. else
50. System.out.println("Pessoa nao encontrada");
w

51. }
52.}

Código 3.16 - TesteDepartamento.java

Trainning Education Services - Todos os direitos reservados 72


3.5 Acoplamento (Coupling)
Acoplamento é o grau de conhecimento requerido sobre os membros internos de uma classe, para que ela possa
ser utilizada por outras classes . O encapsulamento é capaz de diminuir o acoplamento entre classes.

3.5.1 Acoplamento Forte

A classe MauDepartamento é um exemplo de acoplamento forte, pois para ser utilizada em uma aplicação o

r
membro interno array de pessoas deve ser bem conhecido para que se possa gerenciá-lo corretamente. Classes

.b
com um alto grau de acoplamento dificultam a manutenção do software. Se a forma de gerenciamento do array de
pessoas do departamento sofrer uma alteração, todas as aplicações que utilizam MauDepartamento deverão

m
ser modificadas, e em vários pontos.

3.5.2 Acoplamento Fraco

co
Métodos para gerenciar o array de pessoas (addPessoa, getPessoa, removePessoa) são encontrados na
g.
classe Departamento. Isso facilita sua utilização pois as aplicações que usarem a classe Departamento não
necessitam conhecer seus detalhes internos. Esse é um exemplo de acoplamento fraco, porque se a forma de
in
gerenciamento do array de pessoas do departamento sofrer uma alteração apenas a classe Departamento será
modificada. As aplicações dependentes não sofrem nenhum impacto, considerando-se as mesmas operações de
gerenciamento.
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 74


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Sobrecarga de métodos
.tr

Exemplos
Sobrecarga com tipos ambíguos
w

Varargs e sobrecarga
w
w

Trainning Education Services - Todos os direitos reservados 77


4 Sobrecarga de métodos
Usualmente é necessário implementar funcionalidades cujas características são bastante semelhantes entre si,
todavia com tipos e quantidade de parâmetros variáveis.

Veja o exemplo: em uma Calculadora existem somas com dois, três ou quantos argumentos forem necessários.
Além disso, há também somas de números de diversos tipos (int, long, float, byte, etc) e, portanto,

r
é necessário implementar diversos métodos que somem os diferentes parâmetros recebidos. Uma possível

.b
solução para este problema consiste em criar diversos métodos que somem os valores, utilizar como prenome
soma e gerar alguma distinção, como demonstrado a seguir:

m
int soma2(int x, int y);
int soma3(int x, int y, int z);
int somaN(int numeros[]);

co
Porém, criar vários nomes para métodos que fazem basicamente a mesma coisa não parece uma abordagem
muito interessante.

Overload = "Sobrecarga"
g.
A solução desse impasse chama-se sobrecarga de métodos e é uma funcionalidade pertinente a Orientação a
in
Objetos e que o Java implementa. Sobrecarregar um método é escrever métodos com nomes iguais, porém, com
quantidade e tipos de parâmetros de entradas diferentes.
nn

Importante

Em Java, é impossível definir métodos sobrecarregados cujo valor de retorno é o único alterado, pois isso
ai

impossibilita o compilador de identificar qual dos métodos deverá ser executado. Supondo que isso fosse
possível, para o exemplo de código a seguir, qual dos métodos
.tr

multiplica seria executado pelo método usaMultiplicacao ?


w
w
w

Trainning Education Services - Todos os direitos reservados 79


1. public class SobrecargaImpossivel {
2.
3.
4. public int multiplica(int a, int b) {
5. return a * b;
6. }
7.
8. public long multiplica(int c, int d) {
9. return c * d;
10. }
11.
12. public void usaMultiplicacao() {

r
13. multiplica(100,350);

.b
14. }
15.}

m
Código 4.1 - SobrecargaImpossivel.java

Não é possível determinar qual método deveria ser executado; se é o que retorna um long ou o que retorna um

co
int. Por isso, o compilador gera um erro de método duplicado na tentativa de compilar a classe, conforme pode
ser observado na saída gerada pela tentativa de compilação da classe:

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 80


4.1 Exemplos
A seguir veja exemplos de classes com sobrecarga de métodos implementada corretamente:

1. public class Calculadora {


2. public int soma(int a, int b) {
3. return a + b;
4. }
5. public int soma(int a, int b, int c) {
6. int resultado = this.soma(a, b) + c;
7. return resultado;

r
8. }

.b
9. public float soma(float a, float b) {
10. return a + b;
11. }

m
12. public long soma(int[] numeros) {
13. long resultado = 0;
14. for (int i = 0; i < numeros.length; i++) {
15. resultado += numeros[i];

co
16. }
17. return resultado;
18. }
19.}

g.
Código 4.2 - Calculadora.java
in
1. public class TesteCalculadora {
2. public static void main(String[] args) {
3. Calculadora calc = new Calculadora();
nn

4. System.out.println("1 + 9 = " + calc.soma(1, 9));


5. System.out.println("1 + 9.0F = " + calc.soma(1, 9.0F));
6. int num[] = { 1, 3, 6};
7. System.out.println("1 + 3 + 6 = " + calc.soma(num));
8. }
ai

9.}

Código 4.3 - TesteCalculadora.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 81


1. public class Produto {
2. private String descricao;
3. private String marca;
4. private double preco;
5. public void valoresIniciais(double umPreco, String umaMarca) {
6. this.alterarPreco(umPreco);
7. this.setMarca(umaMarca);
8. }
9. public void valoresIniciais(double umPreco,String umaDescricao,String umaMarca)
10. {
11. this.valoresIniciais(umPreco, umaMarca);

r
12. this.setDescricao(umaDescricao);

.b
13. }
14. public String getDescricao() {
15. return this.descricao;
16. }

m
17. public void setDescricao(String novaDescricao) {
18. this.descricao = novaDescricao;
19. }
20. public String getMarca() {

co
21. return this.marca;
22. }
23. public void setMarca(String novaMarca) {
24. this.marca = novaMarca;
25. }
26. public double getPreco() {
27.
28. }
return this.preco;
g.
in
29. public void alterarPreco(double novoPreco) {
30. if (novoPreco > 0) {
31. this.preco = novoPreco;
32. }
nn

33. }
34. public void aumentarPreco(double porcentagem) {
35. if (porcentagem > 0) {
36. System.out.println("aumentando o preco em " + porcentagem + " %");
37. porcentagem = 1 + (porcentagem / 100);
ai

38. preco *= porcentagem;


39. System.out.println("Novo preco = " + this.getPreco());
40. } else {
.tr

41. System.out.println("aumento deve ser maior do que zero");


42. }
43. }
44. public void imprime() {
w

45. System.out.println("------------------------");
46. System.out.println("Produto : " + this.getDescricao() + "\n");
47. System.out.println("Marca : " + this.getMarca() + "\n");
w

48. System.out.println("Preco : " + this.getPreco() + "\n");


49. System.out.println("------------------------");
50. }
51.}
w

Código 4.4 - Produto.java

Trainning Education Services - Todos os direitos reservados 82


1. public class TesteProduto {
2.
3. public static void main(String[] args) {
4. Produto p = new Produto();
5. // o método que recebe (double, String, String) será chamado
6. p.valoresIniciais(9.0, "Produto X", "Marca Y");
7. p.imprime();
8. // o método que recebe (double, String) será chamado
9. Produto p2 = new Produto();
10. p2.valoresIniciais(1000, "Fiat");
11. p2.imprime();
12. }

r
13.}

.b
Código 4.5 - TesteProduto.java

m
co
g.
in
nn
ai

4.2 Sobrecarga com tipos ambíguos


.tr

Em algumas situações, são passados parâmetros que são compatíveis com a assinatura de vários métodos.
Nestes casos, é chamado o método que possua a lista mais específica possível em relação aos tipos dos
w

parâmetros. Para determinar qual a assinatura mais específica segue-se os passos:


• Identificar os métodos que tem assinatura compatível, ou seja, que possam receber os parâmetros
passados;
w

• Utilizar o método, se existir, cuja assinatura corresponde exatamente aos tipos dos parâmetros passados;
• Se não existir, converter os tipos dos parâmetros para o tipo imediatamente superior na hierarquia, até
w

que se encontre um método com correspondência exata

Trainning Education Services - Todos os direitos reservados 83


Veja o exemplo a seguir:

1. public class CalculadoraAmbigua {


2. public int soma(byte b1, byte b2) {
3. System.out.println("Soma de byte");
4. return b1 + b2;
5. }
6. public long soma(long lg1, long lg2) {
7. System.out.println("Soma de long");
8. return lg1 + lg2;
9. }
10. public double soma (double d1, double d2) {

r
11. System.out.println("Soma de double");
12. return d1 + d2;

.b
13. }
14.}

Código 4.6 - CalculadoraAmbigua.java

m
co
1. public class TesteCalculadoraAmbigua {
2. public static void main(String[] args) {
3. CalculadoraAmbigua calc = new CalculadoraAmbigua();
4. calc.soma(24, 25); //chama-se soma(long,long)
5. byte a = 24;
6.
7.
8.
9. }
byte b = 25;
calc.soma(a,b); //chama-se soma(byte,byte)
g.
calc.soma((byte)24, (byte)25); //chama-se soma(byte,byte)
in
10. }

Código 4.7 - TesteCalculadoraAmbigua.java


nn
ai
.tr
w
w

Na linha 4 é feita uma chamada passando dois inteiros como parâmetros. Tanto o método soma(long,long)
quanto o método soma(double,double) podem receber os parâmetros, porém long está mais próximo de int
w

do que double, portanto é chamado o método soma(long,long).

Trainning Education Services - Todos os direitos reservados 84


Nas linhas 7 e 8 são feitas chamadas passando dois bytes como parâmetros. Todos os métodos podem receber
os parâmetros, porém o método soma(byte,byte) é chamado, porque recebe os tipos corretos sem a
necessidade de conversão.

Importante
Existem casos nos quais não é possivel determinar o método a ser chamado. Neste caso é
gerado um erro de compilação. Por exemplo, se existirem os métodos soma (int,float) e soma
(float,int), e for feita a chamada soma (15, 30), não existe um método mais específico.

r
.b
m
4.3 Varargs e sobrecarga

co
Quando se utiliza varargs em um método indicando que um ou mais objetos do tipo determinado podem ser
passados como parâmetro, e se declara também um método mais específico, que receba somente um objeto
daquele tipo, pode ocorrer ambigüidade. Varargs são considerados como menos específicos que todos os demais
g.
casos, só sendo utilizados como última opção. Veja o exemplo a seguir, adicionando um método soma com
varargs à classe CalculadoraAmbigua:
in
1. public class CalculadoraAmbiguaVarargs {
nn

2. public int soma(byte b1, byte b2) {


3. System.out.println("Soma de byte");
4. return b1 + b2;
5. }
6. public long soma(long lg1, long lg2) {
ai

7. System.out.println("Soma de long");
8. return lg1 + lg2;
9. }
10. public double soma (double d1, double d2) {
.tr

11. System.out.println("Soma de double");


12. return d1 + d2;
13. }
14. public int soma(int... params) {
w

15. System.out.println("Soma com varargs");


16. int soma = 0;
17. for(int i = 0; i < params.length; i++) {
w

18. soma += params[i];


19. }
20. return soma;
w

21. }
22.}

Código 4.8 - CalculadoraAmbiguaVarargs.java

Trainning Education Services - Todos os direitos reservados 85


1. public class TesteCalculadoraAmbiguaVarargs {
2. public static void main(String[] args) {
3. CalculadoraAmbiguaVarargs calc = new CalculadoraAmbiguaVarargs();
4. calc.soma(15,20); //chama-se soma(long,long)
5. calc.soma(15,20,25);//chama-se soma(int...)
6. }
7.}

Código 4.9 - TesteCalculadoraAmbiguaVarargs.java

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 86


4.5 Certificação Oracle Certified Java Programmer (OCJP)

1. What will happen when you attempt to compile and run the following code

1. public class Foo {


2.
3. public static void main(String[] args) {

r
4. Foo foo = new Foo();

.b
5. short s1 = 123;
6. short s2 = 456;
7. foo.method(s1,s2);
8. }

m
9.
10. public void method(int... params ) {
11. System.out.println("Inside method with varargs");
12. }

co
13.
14. public void method(int a, int b) {
15. System.out.println("Inside method with two int params");
16. }
17.
18.
19.
20.
public void method(int a, long b) {

}
System.out.println("Inside method with
g.
int and long params");
in
21.
22. public void method(long x, int y) {
23. System.out.println("Inside method with long and int params");
24. }
nn

25.}

A) Compilation succeeds and at runtime the message "Inside method with varargs" is written
ai

B) Compilation succeeds and at runtime the message "Inside method with two int params" is written
C) Compile time error because there is no method that accepts two short parameters: method (short, short)
D) Compile time error because there are duplicate methods
.tr

E) Compile time error because there are ambiguous methods : method(int,long) and method(long,int)
w
w
w

Trainning Education Services - Todos os direitos reservados 88


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Construtores
.tr

Declarando construtores
Sobrecarga de construtores
w

Blocos de inicialização de objetos


Garbage Collector e remoção de objetos
w
w

Trainning Education Services - Todos os direitos reservados 89


5 Construtores
Construtores são métodos especiais, declarados sem valor de retorno e são utilizados para criar instâncias de
objetos de uma classe. São invocados utilizando-se a palavra reservada new.

Todo construtor tem sempre o mesmo nome da classe.

r
Sintaxe para invocação de um construtor:

.b
<nomeClasse> <nomeVariavel> = new <nomeClasse>();

m
Toda classe tem, pelo menos, um construtor que o compilador adiciona, quando nenhum for
declarado (“construtor padrão”).

co
Neste exemplo da classe Curso não foi declarado explicitamente nenhum construtor.

1. public class Curso {


2.
g.
in
3. private String nome;
4. private String descricao;
5. private String codigo;
6. private int cargaHoraria;
nn

7.
8. public void inicializaCurso(String nome, String desc,String cod,int carga) {
9. setNome(nome);
10. setCodigo(cod);
11. setCargaHoraria(carga);
ai

12. setDescricao(desc);
13. }
14. public void imprime() {
.tr

15. System.out.println("Nome: " + this.getNome());


16. System.out.println("Descricao: " + this.getDescricao());
17. System.out.println("Codigo: " + this.getCodigo());
18. System.out.println("Carga Horaria: " + this.getCargaHoraria());
w

19. }
20. public int getCargaHoraria() {
21. return cargaHoraria;
w

22. }
23. public String getCodigo() {
24. return codigo;
25. }
w

Código 5.1: Curso.java (primeira parte)

Trainning Education Services - Todos os direitos reservados 91


26. public String getDescricao() {
27. return descricao;
28. }
29. public String getNome() {
30. return nome;
31. }
32. public void setCargaHoraria(int i) {
33. cargaHoraria = i;
34. }
35. public void setCodigo(String cod) {
36. codigo = cod;
37. }

r
38. public void setDescricao(String desc) {

.b
39. this.descricao = desc;
40. }
41. public void setNome(String nome) {
42. this.nome = nome;

m
43. }
44.}

Código 5.1: Curso.java (continuação)

co
1. public class TesteCurso {
2.
3. public static void main(String[] args) {
4.
5.
String nomeCurso = "Curso de tricot";
g.
String descricaoCurso = "Neste curso voce ira aprender tudo sobre tricot";
in
6. String codigo = "ct1";
7. int cargaHoraria = 40;
8. // Chamada ao construtor
nn

9. Curso curso1 = new Curso();


10. curso1.inicializaCurso(nomeCurso, descricaoCurso, codigo, cargaHoraria);
11. curso1.imprime();
12. }
ai

Código 5.2: TesteCurso.java

Note que não foi declarado explicitamente nenhum construtor na classe Curso, no entanto, foi possível utilizá-lo
.tr

na classe TesteCurso. Isso se deve a adição implícita do construtor default na classe Curso, e pode ser
confirmado utilizando-se o utilitário javap, que é distribuído juntamente com o JDK.
w

No mesmo diretório do arquivo Curso.class deve se executar a seguinte linha de comando:


w

javap Curso
w

Trainning Education Services - Todos os direitos reservados 92


r
.b
m
co
g.
Note a presença do construtor Curso(), logo após a declaração dos atributos da classe.
in
Para maiores informações sobre esse utilitário, consulte a documentação distribuída juntamente com o JDK:
JDK_HOME\docs\technotes\tools\windows\javap.html
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 93


5.1 Declarando construtores
Criam-se construtores na classe para que um objeto receba, no momento da instanciação, um conjunto de
valores de inicialização, em vez de instanciar um objeto de uma classe e depois atribuir valores para seus
atributos.

Sintaxe básica para declaração de construtores


<modificador*> NomeDaClasse (ZERO ou mais parametros)

r
Construtores são rotinas especiais de inicialização, que devem seguir as seguintes regras:

.b
• ter obrigatoriamente o mesmo nome da classe em que são definidos;
• não possuir nenhum valor de retorno (nem mesmo void).

m
Em muitas situações não é desejável que sejam criados objetos sem valores iniciais. Para isso, freqüentemente
declaram-se construtores com parâmetros, que criam “regras” de inicialização de uma classe.

co
A inicialização dos atributos de uma classe poderia ser feita através de um método. No entanto, não há garantias
de que o método será chamado, e tampouco de que será chamado uma única vez.
g.
Na classe Curso, por exemplo, não é recomendável haver objetos criados sem o nome, descrição, código e
in
duração do curso. Diante disso, o método inicializaCurso pode ser substituído por um construtor, conforme
demonstrado a seguir:
nn

1. public class Curso {


2. private String nome;
3. private String descricao;
4. private String codigo;
5. private int cargaHoraria;
ai

6.
7. public Curso(String nome, String descricao, String codigo, int cargaHoraria) {
8. setNome(nome);
.tr

9. setDescricao(descricao);
10. setCodigo(codigo);
11. setCargaHoraria(cargaHoraria);
12. }
w

13.// demais métodos idênticos ao exemplo anterior da classe Curso


14. ...
15.}
w

Código 5.3: Curso.java com construtor


w

Trainning Education Services - Todos os direitos reservados 94


Após recompilar a classe Curso, a tentativa de compilar a classe TesteCurso (Código 5.2) gerará erros:

• o primeiro erro acontece porque não há mais o construtor padrão; assim, sempre que se
declarar um construtor o compilador não adicionará o construtor padrão;

r
.b
m
• o segundo erro é bastante simples, visto que não há mais o método
inicializaCurso.

co
g.
Para eliminar estes erros de compilação é preciso incluir um construtor válido. Neste caso, o único construtor
válido é o construtor que recebe os parâmetros “(String, String, String, int)“ referentes ao conjunto de
in
atributos nome, descrição, código e carga horária do curso.
nn
ai

1. public class TesteCurso {


2. public static void main(String[] args) {
.tr

3.
4. String nomeCurso = "Curso de tricot";
5. String descricaoCurso = "Neste curso voce ira aprender tudo sobre tricot";
6. String codigo = "ct1";
w

7. int cargaHoraria = 40;


8. // Chamada ao construtor com parâmetros de inicialização da classe Curso
9. Curso curso1 = new Curso(nomeCurso,descricaoCurso ,codigo, cargaHoraria);
w

10. curso1.imprime();
11. }
12.}
w

Código 5.4: TesteCurso.java chamando o construtor com parâmetros

Trainning Education Services - Todos os direitos reservados 95


r
Lembre-se de que construtores são utilizados sempre em combinação com a palavra reservada new .

.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 96


5.1.1 Erros comuns na declaração de construtores
1. Declara-se um construtor com retorno void em vez de declará-lo sem nenhum retorno,
como no seguinte fragmento de código:

1. public class Curso {


2. private String nome;
3. private String descricao;
4. private String codigo;
5. private int cargaHoraria;

r
6. public void Curso(String nome,String descricao,String codigo,int cargaHoraria)

.b
7. {
8. setNome(nome);
9. setDescricao(descricao);
10. setCodigo(codigo);

m
11. setCargaHoraria(cargaHoraria);
12. }
13. // demais métodos idênticos ao exemplo anterior da classe Curso
14. ...

co
15.}
Código 5.5: Curso.java com construtor declarado incorretamente

1. public class TesteCurso {


2.
3.
public static void main(String[] args) {
String nomeCurso = "Curso de tricot";
g.
in
4. String descricaoCurso = "Neste curso voce ira aprender tudo sobre tricot";
5. String codigo = "ct1";
6. int cargaHoraria = 40;
nn

7. // Chamada ao construtor com parâmetros de inicialização da classe Curso


8. Curso curso1 = new Curso(nomeCurso,descricaoCurso ,codigo, cargaHoraria);
9. curso1.imprime();
10. }
11.}
ai

Código 5.6: TesteCurso.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 97


2. Chamada ao construtor com ordem de parâmetros invertida ou com parâmetros a mais
ou a menos. Veja a seguir o fragmento de código da classe ExemploConstrutorIncorreto:

1. public class ExemploConstrutorIncorreto {


2. public static void main(String[] args) {
3. String nomeCurso = "Curso de tricot";
4. String descricaoCurso = "Neste curso voce ira aprender tudo sobre tricot";
5. String codigo = "ct1";
6. int cargaHoraria = 40;
7. // A ordem correta é (String, String ,String, int) representando

r
8. // respectivamente nomeCurso, descricao, codigo, cargaHoraria
9. Curso curso2 = new Curso(cargaHoraria, nomeCurso, descricaoCurso,codigo);

.b
10. }
11.}
Código 5.7 - ExemploConstrutorIncorreto.java

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 98


5.2 Sobrecarga de construtores
Segundo as mesmas regras de sobrecarga de métodos pode ser definido mais do que um construtor. É importante
lembrar que, a partir do momento em que se define um construtor explicitamente, o compilador não irá mais criar o
construtor padrão, ou seja, não é mais possivel construir um objeto da classe Curso com a expressão:

Curso c = new Curso();

r
Construtores podem ser definidos de acordo com as regras de negócio de cada entidade. No exemplo da classe

.b
Curso, visto anteriormente, seria possível definir que um Curso também pode ser criado sem a descrição. Para
isso seria necessário definir dois construtores conforme se observa a seguir:

m
1. public class Curso {
2. private String nome;

co
3. private String descricao;
4. private String codigo;
5. private int cargaHoraria;
6. public Curso(String nome, String desc, String cod, int cargaHoraria) {
7. this.setNome(nome);
8.
9.
10.
this.setDescricao(desc);
this.setCodigo(cod);
this.setCargaHoraria(cargaHoraria);
g.
in
11. }
12. public Curso(String nome, String cod, int cargaHoraria) {
13. this.setNome(nome);
14. this.setCodigo(cod);
nn

15. this.setCargaHoraria(cargaHoraria);
16. }
17.
18. // demais métodos idênticos ao exemplo anterior da classe Curso
19. ...
ai

20.}
.tr

Código 5.8: Curso.java com sobrecarga de construtores


w
w
w

Trainning Education Services - Todos os direitos reservados 99


5.2.1 Utilização do objeto implícito this
No exemplo da classe Curso, visto anteriormente, é possível utilizar qualquer um dos dois construtores definidos.

1. Curso(String nome, String desc, String cod, int cargaHoraria) {


2. this.setNome(nome);
3. this.setDescricao(desc);
4. this.setCodigo(cod);
5. this.setCargaHoraria(cargaHoraria);
6. }

r
7. Curso(String nome, String cod, int cargaHoraria) {

.b
8. this.setNome(nome);
9. this.setCodigo(cod);
10. this.setCargaHoraria(cargaHoraria);
11.}

m
Código 5.9: Fragmento da classe Curso.java

co
No entanto, não existe nenhum reaproveitamento de código, e qualquer mudança necessária no construtor com
apenas três parâmetros deverá ser replicada no construtor mais completo e que contém quatro parâmetros.

g.
Na verdade, este é o mesmo problema encontrado na sobrecarga de métodos, e por isso será resolvido da
mesma forma, ou seja, através da utilização do objeto implícito this.
in
Ao chamar um método da própria classe utiliza-se a seguinte sintaxe:
this.nomeDoMetodo (<ZERO ou mais parametros>)
nn

Construtores são invocados de maneira diferente de métodos, portanto não é possível usar a mesma sintaxe. Para
chamar construtores da própria classe utiliza-se :
ai

this (<ZERO ou mais parametros>)


.tr

Importante
É importante ressaltar que a chamada a um construtor da própria classe utilizando a referência implícita this só
w

pode ser feita a partir de outro construtor e deverá sempre ser sua primeira instrução, caso contrário haverá um
erro de compilação.
w
w

Trainning Education Services - Todos os direitos reservados 100


Para maior aproveitamento do código declarado na classe Curso, as seguintes alterações podem ser feitas em
seus construtores:

1. Curso(String nome, String desc, String cod, int cargaHoraria) {


2. this(nome, cod, cargaHoraria);
3. this.setDescricao(desc);
4. }
5.
6. Curso(String nome, String cod, int cargaHoraria) {
7. this.setNome(nome);

r
8. this.setCodigo(cod);

.b
9. this.setCargaHoraria(cargaHoraria);
10.}

Código 5.10: Fragmento da classe Curso.java com reaproveitamento de código de construtor

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 101


5.3 Blocos de inicialização de objetos
Além dos construtores, existe um outro mecanismo que pode ser utilizado para inicialização de objetos. Este
mecanismo é denominado "inicializador de instância" e é um um bloco de código, delimitado por { e }, presente no
corpo da classe, mas fora de qualquer declaração de métodos.

Sintaxe
{ conjunto de instruções }

r
.b
Veja um exemplo de uso, a seguir:

1. public class ExemploInicializador {

m
2. //declaração de atributos
3. private int atributo = 15;
4. //bloco inicializador
5. {

co
6. System.out.println("Dentro do inicializador de instância");
7. System.out.println("Valor do atributo = " + atributo);
8. }
9. //construtor
10. public ExemploInicializador() {
11.
12.
13.}
}
System.out.println("Dentro do construtor"); g.
in
Código 5.11: ExemploInicializador.java
nn

1. public class TesteInicializador {


2. public static void main(String[] args) {
3. ExemploInicializador obj = new ExemploInicializador();
4. }
ai

5.}

Código 5.12: TesteInicializador.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 102


O exemplo anterior também mostra a ordem das operações que são realizadas quando se invoca um construtor
através da instrução new:
1. espaço em memória é alocado para o objeto sendo construído;
2. cada um dos atributos do objeto é criado e inicializado;
3. o código do bloco de inicialização é executado;
4. o código do construtor é executado.

r
.b
Nos próximos capítulos serão apresentados novos passos para esta seqüência de inicialização, conforme forem
apresentados os tópicos de herança e o modificador static.

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 103


5.4 Garbage Collector e remoção de objetos
Em algumas situações pode ser desejável executar instruções de finalização em um objeto antes que seja retirado
da memória, assim como há construtores com instruções de inicialização de objetos.
Tradicionalmente em várias linguagens orientadas a objeto (C++, Object Pascal, ...) este conjunto de instruções de
finalização é denominado “destrutor”. O programador invoca explicitamente o destrutor de um objeto para marcar o
final de seu ciclo de vida; o destrutor pode realizar uma rotina de limpeza e finalmente o objeto é removido da
memória. Nesse modelo, o programador é responsável por desalocar um objeto da memória mas em Java outro

r
modelo de programação é utilizado.

.b
5.4.1 Removendo um objeto da memória

m
Em Java não há destrutores, porque não é possível forçar a remoção de um objeto da memória, mas isso, na
verdade, é uma facilidade e não uma limitação.

co
A Virtual Machine Java assume a responsabilidade de remover os objetos indesejados da memória valendo-se do
mecanismo “Garbage Collector” (coletor de lixo). Basta que um objeto não seja referenciado por nenhuma variável
g.
do tipo reference e por nenhum outro objeto para que se torne um alvo da coleta de lixo da Virtual Machine.
in
Para descartar um objeto, o programador Java deve, no máximo, atribuir nulo (null) às variáveis reference que
apontam para este objeto, ou atribuir um outro objeto a essas variáveis.
nn

Um objeto não é necessariamente removido da memória pelo Garbage Collector no instante em que perde todas
as referências e se torna “descartável”. A especificação formal de uma Virtual Machine Java permite que o
Garbage Collector decida o melhor momento para a remoção dos objetos descartáveis da memória.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 104


Cada fabricante de Virtual Machine (Sun, IBM, BEA, Apache, etc.) tem a liberdade de adotar uma estratégia
diferente para o Garbage Collector.

Importante
Existem duas instruções que o programador pode utilizar para indicar à JVM que é um bom
momento para a coleta de lixo, porém a JVM não tem a obrigação de acatar estas sugestões:
• System.gc()
• Runtime.getRuntime().gc()

r
.b
Mesmo com o auxílio do Garbage Collector seu programa pode levar a JVM a emitir um erro grave

m
de falta de memória (OutOfMemoryError). Por exemplo: grandes arrays de objetos podem manter
muitos objetos inúteis indefinidamente referenciados, e portanto fora da “jurisdição” do Garbage
Collector (que só pode remover os objetos não referenciados). Quando sua aplicação precisar de

co
mais memória obrigará a JVM a negociar com o sistema operacional mas o sistema operacional,por
sua vez, pode se negar a ceder novas páginas de memória para o processo da JVM.

g.
in
Sem dúvida o Garbage Collector pode recuperar quantidades preciosas de memória para nossas aplicações Java
quando o programador libera as referências para os objetos inúteis. Porém a ação do Garbage Collector cobra um
nn

preço, diminuindo o desempenho das aplicações: loops que instanciam e rapidamente descartam objetos são
grandes inimigos do desempenho, pois mais cedo ou mais tarde vão dar trabalho para o Garbage Collector. Este é
o âmago da discussão clássica de utilização das classes String e StringBuffer.
ai

5.4.2 Método finalize


.tr

Quando o Garbage Collector decide entrar em funcionamento e encontra objetos “descartáveis” ele procura por
w

um método especial de finalização nestes objetos. Este método especial de finalização chama-se finalize.
w

Quando um objeto disponibiliza o método finalize o Garbage Collector executa-o imediatamente antes da
remoção deste objeto da memória. O programador pode então definir em sua classe um método finalize para
w

estabelecer um conjunto de instruções de finalização, para o Garbage Collector executar nos objetos
“descartáveis” desta classe.

Trainning Education Services - Todos os direitos reservados 105


No exemplo a seguir a classe ListaInteiros é composta por um array de inteiros e um atributo identificador id.
Além disso foi implementado um método finalize, que vai ser chamado quando a instância da classe for
descartada pelo Garbage Collector, e vai imprimir uma mensagem na console.

1. public class ListaInteiros {


2. private int[] inteiros;
3. private int id;
4. public ListaInteiros(int id, int tamanho) {
5. this.id = id;

r
6. inteiros = new int[tamanho];
7. }

.b
8.
9. public void finalize() {
10. System.out.println("Removendo objeto " + id + " da memoria");
11. }

m
12.}

Código 5.13 - ListaInteiros.java

co
1. public class TesteListaInteiros {
2.
3.
4.
public static void main(String[] args) {
g.
//Faz a leitura do tamanho da lista de inteiros a ser criada
//Esta valor deve ser passado como parâmetro na execução do código.
in
5. int tamanhoLista = Integer.parseInt(args[0]);
6. for(int i = 0; i < 5; i++) {
7. ListaInteiros lista = new ListaInteiros(i,tamanhoLista);
8. }
nn

9. System.out.println("Finalizando programa");
10. }
11.}

Código 5.14 - TesteListaInteiros.java


ai

A classe TesteListaInteiros cria várias instâncias de ListaInteiros dentro de um laço e armazena suas
.tr

referências na variável local lista. Como a cada iteração um novo valor é associado à variável lista, o valor
anterior não é mais utilizado e pode ser descartado pelo Garbage Collector.
w
w
w

Trainning Education Services - Todos os direitos reservados 106


r
.b
A saída mostra que durante a execução do programa ocorreram 4 coletas de lixo dos objetos ListaInteiros
criados, antes da impressão da mensagem final. Foram criados propositalmente objetos grandes, para forçar uma

m
coleta de lixo antes que fosse possivel a criação de novos objetos. Não há como determinar com exatidão o
momento em que irá ocorrer uma coleta de lixo, porém se o sistema precisar alocar mais memória do ele tem

co
disponível, tentará primeiro descartar os objetos não utilizados(coleta de lixo) antes de reclamar de falta de
memória.

g.
A saída gerada não será a mesma em todos os computadores, pois dependerá da configuração de memória
disponível para a JVM além do tamanho dos objetos criados. Com objetos pequenos, pode não ser necessária a
realização da coleta de lixo antes do término do programa. Observe o resultado gerado quando a classe
in
TesteListaInteiros é alterada para gerar listas de inteiros com 10 elemento em vez de 1.000.000.
nn
ai
.tr

Neste caso, como a lista de inteiros era pequena, não ocorreu nenhuma coleta de lixo, pois não foi necessário
w

liberar espaço em memória para novos objetos.


w

Você pode invocar diretamente o método finalize, do mesmo modo que poderia fazer com qualquer
método disponível em um objeto. Lembre-se porém que invocar o método finalize diretamente
w

sobre um objeto não o remove da memória.

Trainning Education Services - Todos os direitos reservados 107


5.6 Certificação Oracle Certified Java Programmer
(OCJP)

1. What is the output of the following code when compiled and run? Select all the
correct answers.

1. public class Foo {


2.

r
3. {
4. System.out.println("inside instance initializer");

.b
5. }
6.
7. Foo(byte b) {

m
8. System.out.println("inside constructor with byte");
9. }
10.
11. Foo(short s) {

co
12. System.out.println("inside constructor with short");
13. }
14.
15. Foo(char c) {
16. System.out.println("inside constructor with char");
17.
18.
19.
20.
}

Foo(int i) {
System.out.println("inside
g.
constructor with int");
in
21. }
22.
23. public static void main(String[] args) {
nn

24. Foo foo = new Foo(2);


25. }
26.
27.}
ai

A) Prints: inside constructor with byte


.tr

B) Prints: inside constructor with short


C) Prints: inside constructor with char
D) Prints: inside constructor with int
w

E) Prints: inside instance initializer


F) Compilation error because there is a block of instructions outside a method or constructor declaration
w
w

Trainning Education Services - Todos os direitos reservados 109


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Modificador static
.tr

Atributos estáticos
Métodos estáticos
w

Bloco de inicialização estática


Representação do modificador static na UML
w
w

Trainning Education Services - Todos os direitos reservados 111


6 Modificador static
Até o presente momento, foram apresentados atributos e métodos que "pertencem" a uma determinada instância
de classe. Isso significa que para acessar os atributos ou chamar os métodos é necessária a criação de um objeto
através da chamada ao seu construtor. Além disso, cada objeto tem a sua própria cópia dos atributos, com valores
específicos daquele objeto. Veja a seguir, a utilização da classe Curso apresentada em capítulos anteriores:

1. public class TesteCurso {

r
2. public static void main(String[] args) {

.b
3. Curso curso1 = new Curso("Academia Java","AJ",128);
4. System.out.println("O curso " + curso1.getNome()
5. + " tem a carga horaria de " + curso1.getCargaHoraria()
6. + " horas");

m
7. Curso curso2 = new Curso("Academia Web","AW", 124);
8. System.out.println("O curso " + curso2.getNome()
9. + " tem a carga horaria de " + curso2.getCargaHoraria()
10. + " horas");

co
11. }
12.}

Código 6.1 - TesteCurso.java criando duas instâncias de curso


g.
in
nn
ai

Note que cada objeto curso tem os seus próprios valores para os atributos nome e carga horária. Este é o tipo de
.tr

cenário mais comum em sistemas orientados a objetos, mas existem casos nos quais um valor global é desejado.
Esse valor global não é específico de cada objeto, mas pode ser compartilhado entre os objetos e demais
w

elementos de um aplicativo.
w

A classe TesteCurso ilustra um valor global deste tipo. Observe o uso da instrução System.out.println . Até
agora, esta instrução foi utilizada em diversos exemplos sem maiores detalhes, pois foi necessária a introdução de
w

diversos conceitos para o seu correto entendimento. Agora é o momento propício para uma análise mais profunda.

Trainning Education Services - Todos os direitos reservados 113


Em Java é possível escrever valores para um determinado destino utilizando-se o método println. Este método
é definido em uma classe denominada PrintStream, que faz parte da API de I/O do Java. Não faz parte do escopo
deste livro discutir esta API, mas basta saber que ela define diversas classes utilizadas com o objetivo de ler e
escrever dados para elementos externos ao programa, como monitor, teclado e arquivos em disco.

Nos exemplos apresentados até agora, o método println foi utilizado para escrever texto em uma console do
monitor. Para isso, é necessário criar um objeto que represente essa console e invocar o método . Analise o
exemplo da classe TesteCurso2: nada disso foi feito e, no entanto, a mensagem foi escrita corretamente para o

r
monitor. Isso ocorre porque existe um atributo chamado out na classe System, que é inicializado automaticamente

.b
para representar o monitor. Este atributo funciona como uma variável global representando o monitor. A criação
deste tipo de atributos globais é feita utilizando-se o modificador static.

m
Perceba também que não foi necessária a criação de uma instância de System para acessar o atributo out. Essa
é outra característica dos elementos estáticos: eles ficam associados a uma determinada classe, e não a objetos

co
específicos da classe.

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 114


6.1 Atributos estáticos
Atributos estáticos são definidos através do uso do modificador static em sua declaração.

Sintaxe para declaração


* static <tipo do atributo> identificador;

*outros modificadores podem ser aplicados juntamente ao modificar static, como por exemplo,
modificadores de acesso public ou private. A ordem dos modificadores não é importante ,portanto pode

r
haver um atributo private static ou um static private.

.b
Outras características importantes de atributos estáticos são:

m
um atributo estático fica associado a uma classe e tem um valor único para toda a aplicação;
• atributos estáticos são inicializados com os mesmos valores de inicialização de atributos não
estáticos. Por exemplo:, um atributo do tipo int será inicializado para o valor 0;

co
• os atributos estáticos podem ser acessados diretamente a partir da classe e são alocados na
memória na primeira vez em que a classe for referenciada. Não é preciso, portanto, criar uma
instância;


• Sintaxe: NomeClasse.nomeAtributo
g.
o exemplo mais comum de atributos estáticos é o atributo out da classe System, utilizado no
in
System.out.println para impressão de dados na console. Lembre-se de que nunca foi
necessário criar uma instância de objeto da classe System para utilizar seu atributo out e,
nn

conseqüentemente, seu método println;


• o ciclo de vida do atributo estático de uma classe é o mesmo da aplicação, isto é, enquanto a
aplicação estiver rodando o atributo não será eliminado pelo Garbage Collector.
ai

6.1.1 Quando utilizar atributos estáticos?


.tr

Atributos estáticos devem ser utilizados quando for necessário compartilhar um valor entre todas as instâncias da
classe, desta forma a variável será alocada apenas uma vez na memória.
w

Imagine a classe Carro, contendo os seguintes atributos:


• fabricante: característica específica de cada Carro e, portanto, característica de cada instância;
w

• placa: cada Carro tem sua própria placa, que portanto é uma característica da instância;
• velocidade: cada Carro pode se movimentar desenvolvendo sua própria velocidade, o que
w

também é uma característica da instância, e não da classe;

Trainning Education Services - Todos os direitos reservados 115


• velocidadeMaximaPermitida: todos os carros devem obedecer a mesma velocidade máxima
permitida; esta característica se aplica a todas as instâncias e pode ser definida como um atributo
estático.

1. public class Carro {


2. private String fabricante;
3. private String placa;
4. private int velocidade;
5. public static int velocidadeMaximaPermitida = 60;

r
6.
7. public Carro(String fabricante, String placa, int velocidade) {

.b
8. this.fabricante = fabricante;
9. this.placa = placa;
10. this.velocidade = velocidade;

m
11. }
12.
13. public String getFabricante() {
14. return fabricante;

co
15. }
16.
17. public void setFabricante(String fabricante) {
18. this.fabricante = fabricante;
19. }
20.
21. public String getPlaca() {
22. return placa;
g.
23. }
in
24.
25. public void setPlaca(String placa) {
26. this.placa = placa;
nn

27. }
28.
29. public int getVelocidade() {
30. return velocidade;
31. }
ai

32.
33. public void setVelocidade(int velocidade) {
34. this.velocidade = velocidade;
.tr

35. }
36.
37. public void acelerar(int deltaV) {
38. velocidade += deltaV;
w

39. }
40.
41. public boolean ultrapassouLimite() {
42. return velocidade > velocidadeMaximaPermitida;
w

43. }
44.}
w

Código 6.2 - Carro.java

Trainning Education Services - Todos os direitos reservados 116


1. public class TesteCarro {
2. public static void main(String[] args) {
3.
4. System.out.print("Velocidade maxima permitida: " );
5. System.out.println(Carro.velocidadeMaximaPermitida);
6.
7. Carro c1 = new Carro("GM", "IBM9876", 50);
8. Carro c2 = new Carro("Volks", "SUN3344", 42);

r
9.
10. c1.acelerar(16);

.b
11. c2.acelerar(30);
12.
13. System.out.print("Carro " + c1.getPlaca() +" ultrapassou o limite ? ");
14. System.out.println(c1.ultrapassouLimite());

m
15. System.out.print("Carro " + c2.getPlaca() +" ultrapassou o limite ? ");
16. System.out.println(c2.ultrapassouLimite());
17.

co
18. Carro.velocidadeMaximaPermitida = 70;
19. System.out.print("\nVelocidade maxima permitida: ");
20. System.out.println(Carro.velocidadeMaximaPermitida);
21.
22. System.out.print("Carro " + c1.getPlaca() +" ultrapassou o limite ? ");
23.
24.
25.
26. }
System.out.println(c1.ultrapassouLimite()); g.
System.out.print("Carro " + c2.getPlaca() +" ultrapassou
System.out.println(c2.ultrapassouLimite());
o limite ? ");
in
27.}

Código 6.3 - TesteCarro.java


nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 117


Visualize graficamente o que significa ter o atributo velocidadeMaximaPermitida compartilhado por todas as
instâncias da classe:

Área de atributos estáticos

Carro.velocidadeMaximaPermitida: 60

r
.b
Carro c1 Carro c2
fabricante: GM fabricante: Volks

m
placa: IBM9876 placa: SUN3344
velocidade: 50 velocidade: 42

co
Figura 6.1 - representação dos atributos com velocidade máxima de 60

g.
Na primeira vez que a classe Carro for referenciada, o atributo velocidadeMaximaPermitida será criado,
não sendo necessário defini-lo a cada instância de classe.
in
Após invocar o método acelerar nos dois carros e alterar o atributo estático velocidadeMaximaPermitida eis a
nova situação:
nn

Área de atributos estáticos


ai

Carro.velocidadeMaximaPermitida: 70
.tr

Carro c1 Carro c2
w

fabricante: GM fabricante: Volks


placa: IBM9876 placa: SUN3344
w

velocidade: 66 velocidade: 72
w

Figura 6.2 - representação dos atributos com velocidade máxima de 70

Trainning Education Services - Todos os direitos reservados 118


6.1.2 Quando não utilizar atributos estáticos?

Não utilizar atributos estáticos para representar características da instância. Veja como foi criada uma classe
Carro com um atributo estático placa; assim, placa passa a ser um atributo compartilhado por todas as
instâncias da classe Carro.

1. public class Carro {

r
2. private String fabricante;
3. private static String placa;

.b
4. private int velocidade;
5. public static int velocidadeMaximaPermitida = 60;
6. // demais métodos idênticos ao exemplo anterior da classe Carro
7.}

m
Código 6.4 - Carro.java com placa estática

co
Compreenda melhor o efeito deste “compartilhamento” realizando o mesmo teste: TesteCarro

g.
in
nn
ai
.tr

Obs: Perceba que a placa do carro é a mesma para todos os objetos da classe Carro. Quando o valor da
placa é alterado para qualquer uma das instâncias da classe Carro, as demais são afetadas porque a variável
w

placa é estática e compartilhada indevidamente por todas as instâncias da classe.


w
w

Trainning Education Services - Todos os direitos reservados 119


Veja a representação gráfica para essa situação:

Área de atributos estáticos

Carro.velocidadeMaximaPermitida: 70

Carro.placa: SUN3344

r
Carro c1 Carro c2

.b
fabricante: GM fabricante: Volks
velocidade: 66 velocidade: 72

m
Figura 6.3 - representação dos atributos com placa estática

co
6.2 Métodos estáticos
O modificador static também pode ser aplicado a métodos. De maneira semelhante ao que ocorre para
g.
atributos, o uso do modificador static em métodos faz sua associação à classe em vez de fazê-lo à instância. A
maior parte dos métodos vistos até agora atuam sobre atributos de um objeto, mas este não é sempre o caso:
in
métodos que dependem apenas dos parâmetros recebidos e não atuam sobre atributos do objeto, normalmente
são métodos utilitários e podem ser transformados em métodos estáticos.
nn

Verifica-se exemplos de uso de métodos estáticos em Java, em classes utilitárias como a classe Math. Esta classe
possui diversos métodos para operações matemáticas como cálculo de raiz quadrada, funções trigonométricas,
logaritmos, arredondamento de números, geração de números aleatórios e outras. Veja um exemplo de sua
ai

utilização a seguir:
.tr

1. public class ExemploMath {


2. public static void main(String[] args) {
3. System.out.println("Exemplos do uso da classe Math");
w

4. System.out.println("raiz quadrada de 625: " + Math.sqrt(625));


5. System.out.println("numero aleatorio:" + Math.random());
6. System.out.println("4.79 arredondado:" + Math.round(4.79));
w

7. }
8.}
w

Código 6.5 - ExemploMath.java

Trainning Education Services - Todos os direitos reservados 120


r
.b
Note que não foi necessário criar uma instância da classe Math para utilizar seus métodos pois eles foram
acessados diretamente a partir do nome da classe.

m
Outro exemplo de uso de métodos estáticos em Java ocorre com o método System.gc(), apresentado no
capítulo anterior, que sugere a execução da coleta de lixo pela JVM. O exemplo mais comum de método estático é

co
o main, porque a JVM não instancia um objeto da classe indicada para execução mas apenas chama seu método
main.

Sintaxe para declaração de métodos estáticos:


g.
* static <tipo do retorno> nomeDoMetodo (<parametrosDeMetodos>){}
in
* outros modificadores podem ser aplicados juntamente ao modificar static, da mesma forma que é feito para
atributos. A ordem dos modificadores não é importante e, assim pode haver um método private static ou
nn

static private.

Um possível candidato ao uso de método estáticos é a classe Calculadora, apresentada no capítulo que abordou
ai

sobrecarga. Essa classe possui métodos que dependem apenas dos valores recebidos como parâmetros e não
manipula nenhum atributo, logo não existe a necessidade de criar várias instâncias da classe para executar
.tr

contas. Caso as várias operações dependessem do resultado de operações anteriores, o cenário seria diferente.

Veja o exemplo da classe modificada:


w
w
w

Trainning Education Services - Todos os direitos reservados 121


1. public class CalculadoraStatic {
2. public static int soma(int a, int b) {
3. return a + b;
4. }
5.
6. public static int soma(int a, int b, int c) {
7. int resultado = soma(a, b) + c;
8. return resultado;
9. }
10.
11. public static float soma(float a, float b) {
12. return a + b;

r
13. }

.b
14.
15. public static long soma(int[] numeros) {
16. long resultado = 0;
17. for (int i = 0; i < numeros.length; i++) {

m
18. resultado += numeros[i];
19. }
20. return resultado;

co
21. }
22.}
Código 6.6 - CalculadoraStatic.java

1. public class TesteCalculadoraStatic {


g.
in
2.
3. public static void main(String[] args) {
4. System.out.println("1 + 9 = " + CalculadoraStatic.soma(1, 9));
5. System.out.println("1 + 9.0F = " + CalculadoraStatic.soma(1, 9.0F));
nn

6. int num[] = { 1, 3, 6};


7. System.out.println("1 + 3 + 6 = " + CalculadoraStatic.soma(num));
8. }
9.}
ai

Código 6.7 - TesteCalculadoraStatic.java


.tr

Apesar do acesso a atributos e métodos estáticos ser feito a partir do nome da classe e não ser necessária a
criação de objetos, este acesso também pode ser feito a partir de instâncias. Isto pode ser visto no exemplo a
seguir:
w
w
w

Trainning Education Services - Todos os direitos reservados 122


1. public class Logger {
2. private static int qtdLogs;
3.
4. public static void logIt(String mensagem) {
5. String dataHora = "" + new java.util.Date();
6. System.out.println(dataHora + " : " + qtdLogs + " : " + mensagem);
7. qtdLogs++;
8. }
9.}
Código 6.8 - Logger.java

r
.b
1. public class TesteLogger {
2. public static void main(String[] args) {
3. Logger.logIt("Logger");

m
4. Logger log1 = new Logger();
5. log1.logIt("log1");
6. Logger log2 = new Logger();
7. log2.logIt("log2");

co
8. Logger.logIt("Logger");
9. }
10.}

g.
Código 6.9 - TesteLogger.java
in
nn
ai

Obs: observe que o valor de qtdLogs está sendo incrementado, mesmo quando se utilizam diferentes instâncias
.tr

de Logger para fazer as chamadas ao método logIt(). Isto acontece porque este atributo é estático e,
portanto, compartilhado por todas as instâncias da classe.
w
w
w

Trainning Education Services - Todos os direitos reservados 123


6.2.1 Restrições no uso de métodos estáticos

1. Um método estático pode acessar somente membros estáticos porque, como já foi visto, pode ser
chamado sem a necessidade de criação de uma instância da classe. Membros não estáticos são criados
somente na construção da instância.

1. public class Carro {

r
2.
3. private String fabricante;

.b
4. private String placa;
5. private int velocidade;
6. private static int velocidadeMaximaPermitida = 60;
7.

m
8. public Carro(String fabricante, String placa, int velocidade) {
9. this.fabricante = fabricante;
10. this.placa = placa;

co
11. this.velocidade = velocidade;
12. }
13.
14. public static int getVelocidadeMaximaPermitida() {
15. return velocidadeMaximaPermitida;
16.
17.
18.
19.
}

public static void setVelocidadeMaximaPermitida(int vmax) {


velocidadeMaximaPermitida = vmax;
g.
in
20. if(velocidade > velocidadeMaximaPermitida) {
21. setVelocidade(velocidadeMaximaPermitida);
22. }
nn

23. }
24.
25. public int getVelocidade() {
26. return velocidade;
27. }
ai

28.
29. public void setVelocidade(int velocidade) {
30. this.velocidade = velocidade;
31. }
.tr

32.
33. // demais getters e setters omitidos
34.}
w

Código 6.10 - Carro.java com métodos estáticos tentando acessar membros não estáticos
w
w

Trainning Education Services - Todos os direitos reservados 124


r
.b
2. Uma consequência do item anterior é que também não é possivel utilizar a variável this dentro de

m
métodos estáticos.

co
1. public class Carro {
2.
3. private String fabricante;
4. private String placa;
5. private int velocidade;
6.
7.
8.
private static int velocidadeMaximaPermitida = 60; g.
public Carro(String fabricante, String placa, int velocidade) {
in
9. this.fabricante = fabricante;
10. this.placa = placa;
11. this.velocidade = velocidade;
12. }
nn

13.
14. public static int getVelocidadeMaximaPermitida() {
15. return velocidadeMaximaPermitida;
16. }
17.
ai

18. public static void setVelocidadeMaximaPermitida(int vmax) {


19. velocidadeMaximaPermitida = vmax;
20. if(this.velocidade > velocidadeMaximaPermitida) {
.tr

21. this.setVelocidade(velocidadeMaximaPermitida);
22. }
23. }
24. public int getVelocidade() {
w

25. return velocidade;


26. }
27. public void setVelocidade(int velocidade) {
28. this.velocidade = velocidade;
w

29. }
30. // demais getters e setters omitidos
31.}
w

Código 6.11 - Carro.java utilizando a variável this em um método estático

Trainning Education Services - Todos os direitos reservados 125


6.3 Bloco de inicialização estático
Como pode ser feita a inicialização de um atributo estático? Para inicialização de atributos de instância há como
opções: a inicialização na declaração, a inicialização com construtores ou com blocos de inicialização de objetos.

inicialização na declaração:
private int codigo = 135;

r
inicialização com construtor:

.b
public Cliente(int codigo) {
this.codigo = codigo;
}

m
bloco de inicialização:

co
{
codigo = 135;
}

g.
Para atributos estáticos, há como opções: a inicialização na declaração, que ocorre de maneira idêntica a
inicialização de atributos não estáticos; e a inicialização com blocos de inicialização estáticos.
in
Sintaxe
nn

static { conjunto de instruções }

1. public class PaletaCores {


ai

2. private static int[] cores = new int[7];


3.
4. PaletaCores() {
.tr

5. System.out.println("Criando instancia da classe PaletaCores");


6. }
7.
8. static {
w

9. // hipoteticamente, serão atribuídos números inteiros às cores,


10. // como por exemplo: 0 branco, 1 azul, 2 vermelho, etc...
11. System.out.println("Inicializando array de cores"
12. + " no bloco de inicializacao estatico...");
w

13. for (int i = 0; i < cores.length; i++) {


14. cores[i] = i;
15. }
w

16. }
17.}

Código 6.12 - PaletaCores.java

Trainning Education Services - Todos os direitos reservados 127


Sabe-se que o bloco de inicialização de objetos é executado na chamada ao construtor, mas quando é executado
um bloco de inicialização estático? Para responder esta pergunta é necessário conhecer o ciclo de carregamento
de uma classe Java para uso em um programa:

1. na execução do código pela JVM uma classe é utilizada em alguma instrução. Esta utilização pode ser, por
exemplo: uma chamada a um método estático, acesso a um atributo estático ou chamada ao construtor da
classe;.
2. para executar a instrução, a JVM verifica se a classe já se encontra carregada em memória. Caso contrário é

r
necessário encontrar o arquivo .class correspondente e carregá-lo. Após carregar a classe, os seguintes

.b
passos são executados:

2.1. criação dos atributos estáticos;

m
2.2. execução do bloco de inicialização estático.

co
3. execução da instrução solicitada.

O código a seguir ilustra este comportamento:


g.
in
1. public class TestePaletaCores {
2. public static void main(String[] args) {
3. PaletaCores p1 = new PaletaCores();
4. PaletaCores p2 = new PaletaCores();
nn

5. PaletaCores p3 = new PaletaCores();


6. }
7.}

Código 6.13 - TestePaletaCores.java


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 128


Obs: Note que o bloco de inicialização estático foi executado apenas uma vez, independentemente do número de
instâncias criadas.

Algumas características importantes de blocos de inicialização estáticos são:

• um bloco de inicialização estático é executado somente uma vez: imediatamente após a primeira
referência à classe, isto é, no seu carregamento;

r
• como o bloco de inicialização estático é executado no carregamento da classe, conseqüentemente

.b
será executado antes da chamada ao construtor da classe;

• dentro de um bloco de inicialização estático são acessados somente atributos e métodos estáticos;

m
• blocos de inicialização estáticos não podem lançar exceções checked (este tópico será abordado

co
posteriomente);

• é possivel criar mais de um bloco de inicialização estático. Neste caso, os blocos serão executadas
na ordem em que aparecem no código da classe. g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 129


6.4 Representação do modificador static na UML
Atributos e métodos estáticos são representados utilizando-se palavras sublinhadas, como mostra o
exemplo abaixo:

r
.b
m
co
g.
Diagrama 6.1 - representação do modificador static na UML
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 130


6.6 Certificação Oracle Certified Java Programmer (OCJP)

1. Consider the following piece of code, and select all the statements that are true.

1. public class Foo {


2. int version = 5;
3. static String name = "Mach";
4.
5. public static void method(){
6. System.out.println(name + version);

r
7. }

.b
8.
9. public static void main(String[] args) {
10. Foo foo = new Foo();
11. foo.method();

m
12. }
13.}

co
A) The code compiles and displays "Mach5".
B) The code compiles, but throws an exception at runtime, because variable “version” isn't declared as
static.
g.
C) The code fails to compile because you can't make a static reference to a non-static variable.
D) The code will compile and display "Mach5" if “version” is declared to be static.
in
E) The code will compile by removing the static keyword from the declaration of method().
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 132


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Associação
.tr

Representação de associações na UML


Cardinalidade/Multiplicidade
w

Navegabilidade
Restrições
Associação reflexiva
w

Agregação
Composição
w

Dependência
Classe Associativa
Estudo de Caso

Trainning Education Services - Todos os direitos reservados 133


7 Associação
A associação é uma das formas mais simples de relacionamento entre classes e ocorre quando existe uma classe
que possui um atributo de outra classe (objetos ou array de objetos). Este tipo de relacionamento também é
conhecido por relacionamento "tem um(a)". Por exemplo, quando existe uma associação entre a classe Pessoa e
a classe Endereco, diz-se que uma pessoa "tem um" endereço.

r
7.1 Representação de associações na UML

.b
Uma associação é representada na UML com uma reta que liga duas classes. Além disto a UML
permite representar também as seguintes características de uma associação:

m
• nome: Nome da associação;

co
• sentido: Sentido de leitura da associação;
• cardinalidade / multiplicidade: um para um, um para muitos, muitos para muitos, etc;
• papéis: Os papéis da associação, ou seja, qual o papel na associação de cada elemento que


pertence a associação; g.
navegabilidade: Se uma das partes pode navegar pela outra parte e vice-versa;

in
restrições;
• tipo: associação, agregação e composição.
nn

Nome e Sentido:
ai
.tr
w
w

Diagrama 7.1 - nome da associação


w

Trainning Education Services - Todos os direitos reservados 135


7.2 Cardinalidade / Multiplicidade
Para definir a multiplicidade de um dos lados do relacionamento, utilizam-se alguns valores, entre eles:

1 Obrigatoriamente 1
0..1 Zero ou um
1..* Um ou mais
0..* Zero ou mais

r
* Zero ou mais

.b
Obs: Quando os valores para a cardinalidade não estão definidos, fica implícito que o valor da associação é 1.

m
Exemplo de associação 1 para 1:
O diagrama abaixo pode ser lido da seguinte forma: uma Pessoa tem um Endereco, e o Endereco pertence a

co
uma Pessoa.

g.
Diagrama 7.2 - associação 1 para 1
in
O diagrama acima mostra que a classe Pessoa tem um atributo do tipo Endereco, e a classe Endereco tem um
nn

atributo do tipo Pessoa.

Exemplo de associação 1 para muitos


ai

A partir do seguinte diagrama conclui-se que uma Empresa pode ter um ou mais Departamentos, e cada
Departamento pertence a apenas uma Empresa.
.tr
w

Diagrama 7.3 - associação 1 para muitos


w

No mesmo diagrama verifica-se que, na implementação, a classe Empresa deve ter uma coleção de
w

departamentos.

Trainning Education Services - Todos os direitos reservados 136


Exemplo de associação muitos para muitos:
O relacionamento “muitos-para-muitos” apresentado a seguir pode ser entendido da seguinte forma: um
funcionário trabalha para um ou mais departamentos, e um departamento emprega uma ou mais pessoas. Ou
seja, não há um Funcionário que não trabalha para nenhum departamento, assim como não há um departamento
que não emprega nenhum funcionário.

r
.b
Diagrama 7.4 - associação muitos para muitos

m
Papéis
O nome do papel explica como a classe participa do relacionamento.

co
Este nome pode ser utilizado para geração de código, definindo o nome do atributo que será gerado.

g.
in
Diagrama 7.5 - papéis da associação
nn

O diagrama acima representa uma Empresa que tem um ou mais Departamentos, ou seja, na classe Empresa
há um coletivo de departamentos e na classe Departamento há uma Empresa. Observe o seguinte código:
ai

1. public class Empresa {


2. private Departamento[] departamentos;
.tr

3. }

Código 7.1 - Empresa.java


w

1. public class Departamento {


w

2. private Empresa empresa;


3.}
w

Código 7.2 - Departamento.java

Trainning Education Services - Todos os direitos reservados 137


7.3 Navegabilidade
Para criar uma associação é preciso indicar que uma classe contém um atributo da outra classe e vice-versa.
Analise o código gerado para as classes Curso, Estudante e Endereco:

Curso.java
public class Curso {
private Estudante[] estudantesInscritos;
}

r
.b
Estudante.java
public class Estudante {

m
private Curso[] cursos;
private Endereco endereco;
}

co
Endereço.java
public class Endereco {

}
private Estudante estudante;
g.
in
Diagrama 7.6 - exemplo de cenário de escola

Observações:
nn

Note que o nome do atributo colocado na classe é igual ao nome utilizado na associação no diagrama UML.
No caso de relacionamentos “um-para-muitos” ou “muitos-para-muitos”, utiliza-se um array para representar a
coleção de objetos; no entanto, outras ferramentas de modelagem UML podem utilizar Collections 2, como por
ai

exemplo: ArrayList, List, SortedSet, ou qualquer outra.


.tr

Muitas vezes é interessante que uma classe tenha referência para outra e vice-versa, mas em outras
circunstâncias não é necessário, como no caso da classe Endereco. Será que realmente é necessário que cada
Endereco tenha uma referência para o Estudante?
w

Por isto existe o conceito de navegabilidade: quando não é definida explicitamente, a navegabilidade é bilateral,
w

isto é, ambos os lados da associação tem uma referência para o outro. Quando não se deseja que a
navegabilidade seja bilateral utiliza-se no diagrama uma seta contínua, indicando qual parte da associação tem
w

navegabilidade:o lado que não tiver seta será considerado sem navegabilidade.

2
Collections são classes que representam estruturas de dados em Java.

Trainning Education Services - Todos os direitos reservados 138


Para evitar que cada Endereco tenha uma referência para o Estudante que nele reside, utiliza-se a
navegabilidade unilateral na direção de Estudante para Endereco, indicando que o Endereco não tem
navegabilidade para a classe Estudante. Analise o código gerado e verifique como isso foi feito:

Curso.java
public class Curso {
private Estudante[] estudantesInscritos;

r
}

.b
Estudante.java
public class Estudante {

m
private Curso[] cursos;
private Endereco endereco;
}

co
Endereço.java
public class Endereco {
}
g.
Diagrama 7.7 - exemplo de cenário de escola modificado
in
A grande vantagem desta abordagem com navegabilidade unilateral é que a classe Endereco se torna mais
reutilizável. No exemplo a seguir com outro cenário de aplicativo, é necessária a classe Endereco, mas não a
nn

Estudante.
ai

Empresa.java
public class Empresa {
private Endereco endereco;
.tr

Endereço.java
w

public class Endereco {


}
w

Diagrama 7.8 - exemplo de reaproveitamento da classe Endereco


w

Pode-se utilizar a mesma classe Endereco, nos dois sistemas, o que não seria possivel se Endereco tivesse
uma associação bidirecional com Estudante.

Trainning Education Services - Todos os direitos reservados 139


7.4 Restrições
Restrições são utilizadas para garantir a integridade do sistema e são regras que devem ser respeitadas. É
possível impor restrições, como por exemplo: para que uma Matricula seja parte de uma Turma o pagamento
deve estar ok; caso contrário, aquela não é uma Matricula válida e não poderá ocupar uma vaga da Turma.

As restrições são representadas por chaves e devem ser separadas por vírgulas, no caso da existência de mais
de uma restrição:

r
.b
m
Diagrama 7.9 - restrição de pagamento

Ordenação

co
Quando há um relacionamento em que pelo menos uma das partes da associação tem multiplicidade maior que
um, é possível definir se os elementos devem ser mantidos em ordem ou não. Para que a ordenação seja levada
em consideração utiliza-se o símbolo {ordered}, que é uma restrição. Quando a ordenação não é necessária
simplesmente omite-se esse símbolo. g.
in
nn

Diagrama 7.10 - restrição de ordenação

7.5 Associação reflexiva


ai

Uma associação reflexiva é definida quando uma classe contém uma ou mais instâncias de objetos da própria
classe.
.tr

A associação tem inicio e fim na própria classe.


w
w
w

Diagrama 7.11 - associação reflexiva

Trainning Education Services - Todos os direitos reservados 140


7.6 Agregação
A agregação é uma forma de associação caracterizada por um relacionamento do tipo parte-todo, em que uma
das pontas da associação é a parte e a outro é o todo.

A agregação é representada na UML através de um losango branco,


posicionado no lado do todo.

r
Neste exemplo, a Turma é o todo, enquanto os Estudantes e o

.b
Instrutor são partes do todo.

m
Diagrama 7.12 - agregação

co
A leitura do diagrama apresentado traz as seguintes informações:
• a classe Turma tem referência para todos os Estudantes inscritos na Turma;

• a Turma tem referência para
g.
cada Estudante tem referência para a Turma na qual está matriculado;
o Instrutor que irá ministrá-la;

in
cada Instrutor tem uma referência para a sua Turma;
• há informações sobre a cardinalidade de cada associação: cada Turma possui zero
ou mais Estudantes, e cada Estudante pertence apenas a uma Turma. Da mesma
nn

forma, cada Turma tem um Instrutor, e cada Instrutor é responsável por uma
Turma.
ai

Além destas informações, por ser uma agregação, conclui-se que:


• A Turma é “hierarquicamente superior” aos Estudantes e ao Instrutor, ou seja, a Turma contém os
.tr

Estudantes e o Instrutor. Visto de outra forma, os Estudantes e o Instrutor fazem parte da turma.
w

A principal diferença entre uma agregação e uma associação está em que a agregação é um
relacionamento de um todo com suas partes. No exemplo, os estudantes são parte de uma
w

turma (agregação), mas não faz sentido dizer que uma pessoa é parte do endereço ou vice-
versa (associação). Na dúvida,utilize a associação.
w

Trainning Education Services - Todos os direitos reservados 141


7.7 Composição
Composição é um tipo de associação ainda mais forte que
agregação. A composição também é um relacionamento
caracterizado como parte / todo, mas, neste caso, o todo é
responsável pelo ciclo de vida da parte.

A composição é representada por um losango preto na ponta da

r
associação que representa o todo.

.b
Diagrama 7.13 - composição

m
A leitura do diagrama apresentado traz as seguintes informações:
• a classe Escola tem referência para todos os Departamentos da Escola;

co
• o Departamento tem uma referência para a Escola a qual pertence;
• o Instrutor tem referência para o seu TimeCard;
• cada TimeCard tem referência para o Instrutor o qual pertence;



g.
cada Escola tem um ou mais Departamentos, mas cada Departamento pertence a apenas uma Escola;
cada Instrutor tem um TimeCard, e cada TimeCard pertence a apenas um Instrutor;
se o objeto da classe Escola for destruído, todos os Departamentos devem ser excluídos também. O
in
mesmo acontece com o Instrutor e seu TimeCard, ou seja, o Departamento não faz sentido sem a Escola,
e o TimeCard não faz sentido sem o Instrutor.
nn

A maioria das ferramentas de modelagem tem a capacidade de gerar códigos automaticamente.


ai

Contudo, cada uma empregará formas diferentes para representar a “coleção de


Departamentos” da escola. Exemplo: um array de Departamento, List, Set, HashSet ou
.tr

qualquer outra implementação da interface Collection.


Isso é válido para todos os tipos de associação, ou seja, associação, agregação e composição.
w
w
w

Trainning Education Services - Todos os direitos reservados 142


7.8 Dependência
A dependência é representada graficamente por uma seta pontilhada, indicando que uma classe depende da outra
classe. Uma classe depender da outra, significa que ela utiliza instâncias ou membros estáticos da outra classe
em seu código. Este uso pode ocorrer,por exemplo, através de parâmetros recebidos nos métodos ou criação de
variáveis locais.

No exemplo utilizado, a classe GeradorRelatorios depende da classe Turma, que é recebida como

r
parâmetro no método imprimirTurma; portanto, se a classe Turma for removida a GeradorRelatorios não

.b
irá mais funcionar, ou então, alterações realizadas na Turma podem afetar a GeradorRelatorios.

m
co
Diagrama 7.14 - dependência

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 143


7.9 Classe Associativa
Em alguns cenários é possível modelar a própria associação como uma classe. Isto ocorre quando existem
atributos que não são relativos a nenhuma das classes da associação, mas à própria associação. Este tipo de
classe denomina-se classe associativa e pode ser representada através de uma classe conectada via uma linha
tracejada até a associação. Veja, a seguir um exemplo do diagrama UML e correspondente código Java.

r
.b
m
co
Diagrama 7.15 - classe associativa

Estudante.java
class Estudante {
private Matricula[] matriculas;
g.
in
}
nn

Turma.java
class Turma {
private Matricula[] matriculas;
ai

}
.tr

Matricula.java
class Matricula {
private Estudante estudante;
w

private Turma turma;


private int codigo;
w

private java.util.Date data;


}
w

Trainning Education Services - Todos os direitos reservados 144


7.10 Estudo de caso: Modelagem de uma empresa
Para entender melhor como ocorrem as interações entre classes, acompanhe a análise de um problema, a
modelagem da sua solução e, por último, a análise técnica das classes que a implementam.

• uma empresa pode ser representada por um conjunto de departamentos e escritórios;


• um departamento pode ser representado por um grupo de pessoas que trabalham para o
departamento;

r
• um escritório pode ser representado por um endereço e um CNPJ;

.b
• cada pessoa pode ser representada por um nome, um rg e um endereço.

Nota: Cada uma destas entidades (Empresa, Departamento, Pessoa, Endereco, Escritorio) têm muitas

m
outras características que podem ser utilizadas para representá-las; no entanto, serão utilizadas somente aquelas
consideradas essenciais para o entendimento do assunto.

co
Veja as representações em UML e em código Java necessárias para atender os requisitos identificados acima.
Para efeito de simplificação do código gerado, todos os métodos de encapsulamento (getters e setters), bem como
os construtores foram eliminados do código e do diagrama. g.
in
nn
ai
.tr

Diagrama 7.16 - diagrama de classes para a modelagem de uma empresa


w
w
w

Trainning Education Services - Todos os direitos reservados 145


1. class Empresa {
2. private Departamento departamentos[];
3. private Escritorio escritorios[];
4.}

Código 7.3 - Empresa.java

r
1. class Departamento {

.b
2. private String nome;
3. private Pessoa pessoas[];
4.}

m
Código 7.4 - Departamento.java

co
1. class Escritorio {
2. private Endereco endereco;
3.
4.}
private String cnpj; g.
in
Código 7.5 - Escritorio.java
nn

1. class Pessoa {
2. private Endereco endereco;
3. private String nome;
ai

4. private String rg;


5.}
.tr

Código 7.6 - Pessoa.java


w

1. class Endereco {
2. private String rua;
3. private int numero;
w

4.}
w

Código 7.7- Endereco.java

Trainning Education Services - Todos os direitos reservados 146


7.10.1 Laboratório Opcional de Modelagem

Objetivo:
Praticar o desenvolvimento de diagramas de classes.

Tabela de atividades:
Atividade OK

r
1. Criar um diagrama de classes para modelar um sistema de compras que atenda os seguintes

.b
requisitos:
O usuário pode visualizar um catálogo com todos os produtos disponíveis.

m
O Catálogo deve exibir as seguintes informações do produto:
• Nome
• Descrição

co
• Preço
• Imagem
• Código (com letras e números)
g.
O usuário pode adicionar ou remover produtos de sua lista de compras.
O usuário pode alterar a quantidade de um determinado produto de sua lista.
in
O valor de venda deverá ser recalculado à medida que forem feitas alterações na lista de compras..
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 151


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Herança
.tr

Representação de herança na UML


w

Exemplos
Herança e modificador private
w

Modificador protected
Referência implícita super
w

Construtores X Herança
Sobrescrita de métodos
Modificador final

Trainning Education Services - Todos os direitos reservados 153


8 Herança
Agora que você já conhece os atributos e métodos de classe, analise o exemplo de sintaxe mínima necessária a
uma classe:

class Pessoa {}

A princípio, a classe Pessoa parece uma classe vazia, sem funcionalidade e sem atributos, ou seja, uma classe

r
inútil. Todavia, já foi visto que o compilador adiciona o construtor padrão, portanto, mesmo sem nenhum atributo

.b
ou método já é possível criar uma instância da classe Pessoa.

Além disto, o compilador também garante que todas as classes contenham um mínimo de funcionalidades,

m
definidas na classe Object. Por isto, a classe Object é chamada de superclasse de todas as classes, porque,
com certeza, todas são derivadas dela.

co
Utilizando-se novamente o utilitário javap observe que, na verdade, a declaração da classe Pessoa é feita da
seguinte forma:
g.
in
nn
ai
.tr

A palavra chave extends faz com que a classe Pessoa herde todos os atributos e métodos definidos na classe
Object, ou seja, possua todos os métodos e atributos da superclasse .
w

Este é o conceito de herança, simplificadamente considerado como a capacidade que uma classe tem de herdar
w

atributos e métodos de outras classes. Assim como o relacionamento de associação também é conhecido como
relacionamento "tem um(a)", a herança entre classes também é denominada relacionamento do tipo "é um(a)",
w

porque uma das classes é uma especialização da outra.

Trainning Education Services - Todos os direitos reservados 155


Quando uma classe A herda funcionalidade (estende) da classe B, diz-se que a classe B é superclasse da
subclasse A.
A extends B ; portanto, B é superclasse de A.

Importante:
Java implementa somente herança simples, o que significa que cada classe pode estender
somente uma classe (em C++ é possível herdar várias classes ao mesmo tempo e essa

r
capacidade é denominada herança múltipla).

.b
8.1 Representação de herança na UML

m
A herança é representada na UML (Unified Modeling Language) da seguinte forma:

co
g.
in
Diagrama 8.1 - representação de herança
nn

A seta contínua indica que uma classe estende outra. O exemplo mostra que a classe Pessoa estende a classe
Object, herdando todos os seus métodos e atributos.
ai

Não é necessário que a classe filha esteja abaixo da classe pai, porque freqüentemente os diagramas contém um
grande número de classes, e nem sempre é possível manter essa forma.
.tr
w

Diagrama 8.2 - outra representação de herança


w
w

Trainning Education Services - Todos os direitos reservados 156


8.2 Exemplos
Neste exemplo de utilização de herança foi definida a classe Calculadora, que tem apenas um método: o
método soma. Criou-se também a classe CalculadoraPlus, que estende a classe Calculadora, herdando o
método soma, e define um método adicional multiplicacao.

1. public class Calculadora {


2. public int soma(int num1, int num2) {
3. int resultado = num1 + num2;
4. return resultado;

r
5. }

.b
6.}

Código 8.1 - Calculadora.java

m
1. public class CalculadoraPlus extends Calculadora {
2. public double multiplicacao(int num1, int num2) {
3. double resultado = num1 * num2;
4. return resultado;

co
5. }
6.}

Código 8.2 - CalculadoraPlus.java

1. public class TesteHeranca {


2. public static void main(String[] args) {
3. Calculadora calculadora = new Calculadora();
g.
in
4. int resultado1 = calculadora.soma(10, 37);
5. System.out.println("10 + 37 = " + resultado1);
6. CalculadoraPlus calcPlus = new CalculadoraPlus();
nn

7. // Utilização do método herdado da classe Calculadora


8. int resultado2 = calcPlus.soma(20, 79);
9. System.out.println("20 + 79 = " + resultado2);
10. // Utilização do método definido na classe CalculadoraPlus
11. double resultado3 = calcPlus.multiplicacao(10, 30);
ai

12. System.out.println("10 * 30 = " + resultado3);


13. }
14.}
.tr

Código 8.3 - TesteHeranca


w
w
w

Trainning Education Services - Todos os direitos reservados 157


Verifique a análise da classe Pessoa com atributos, métodos de acesso getters e setters e o construtor default.
Ela está estendida criando a classe Funcionario, que é uma especialização da classe Pessoa. Ela herdará os
atributos e métodos da classe Pessoa adicionando apenas atributos e métodos específicos da classe
Funcionario.

r
.b
m
co
g.
in
nn
ai
.tr
w

Diagrama 8.3 - hierarquia de classes para Pessoa


w

Vale lembrar que:


• um Funcionario é UMA Pessoa;
w

• uma Pessoa é UM Object.

Trainning Education Services - Todos os direitos reservados 158


1. public class Pessoa {
2. private Endereco endereco;
3. private String nome, rg;
4. public void setEndereco(Endereco end) {
5. this.endereco = end;
6. }
7. public Endereco getEndereco() {
8. return endereco;
9. }
10. public void setNome(String nome) {

r
11. this.nome = nome;
12. }

.b
13. public String getNome() {
14. return nome;
15. }
16. public void setRg(String rg) {

m
17. this.rg = rg;
18. }
19. public String getRg() {

co
20. return rg;
21. }
22. public void imprime() {
23. System.out.println("Nome: " + this.getNome());
24. System.out.println("RG: " + this.getRg());
25.
26.
27. }
28.}
g.
System.out.print("Endereco: " + this.getEndereco().getRua());
System.out.println(" , " + this.getEndereco().getNumero());
in
Código 8.4 - Pessoa.java
nn

1. public class Endereco {


2. private String rua;
3. private int numero;
4. public Endereco(String rua, int numero) {
ai

5. this.setRua(rua);
6. this.setNumero(numero);
7. }
8. public int getNumero() {
.tr

9. return numero;
10. }
11. public String getRua() {
12. return rua;
w

13. }
14. public void setNumero(int numero) {
15. this.numero = numero;
w

16. }
17. public void setRua(String rua) {
18. this.rua = rua;
w

19. }
20.}

Código 8.5 - Endereco.java

Trainning Education Services - Todos os direitos reservados 159


/*
* Como a classe Funcionario estende a classe Pessoa, ela terá todos os atributos
* e métodos da classe Pessoa.
*/
1. public class Funcionario extends Pessoa {
2.
3. private long carteiraProfissional;
4. private double salario;
5. private String dataAdmissao;

r
6.
7. public void setCarteiraProfissional(long carteira) {

.b
8. this.carteiraProfissional = carteira;
9. }
10.
11. public long getCarteiraProfissional() {

m
12. return this.carteiraProfissional;
13. }
14.

co
15. public void setSalario(long salario) {
16. this.salario = salario;
17. }
18.
19. public double getSalario() {
20.
21. }
22.
return this.salario;

23. public void setDataAdmissao(String data) {


g.
in
24. this.dataAdmissao = data;
25. }
26.
nn

27. public String getDataAdmissao() {


28. return this.dataAdmissao;
29. }
30.}
ai

Código 8.6 - Funcionario.java


.tr

Para compreender melhor os conceitos de herança, foi criada a classe TesteFuncionario, que utilizará
métodos e atributos herdados implicitamente pela classe Funcionario.
w
w
w

Trainning Education Services - Todos os direitos reservados 160


1. public class TesteFuncionario {
2.
3. public static void main(String[] args) {
4.
5. // Criando o endereço para o funcionário f
6. Endereco end1 = new Endereco("Rua das tulipas", 1200);
7.
8. // Criando o funcionário f
9. Funcionario f = new Funcionario();
10.

r
11. // atribuindo as características herdadas da classe Pessoa

.b
12. f.setNome("Pedro da Silva");
13. f.setEndereco(end1);
14. f.setRg("1234545");
15.

m
16. // atribuindo as características específicas de funcionários
17. f.setSalario(10000);
18. f.setCarteiraProfissional(123434L);
19.

co
20. // Chamando um método definido na classe Pessoa que, por sua vez,
21. // "conhece" apenas os atributos da classe Pessoa
22. f.imprime();
23. }
24.}
g.
Código 8.7 - TesteFuncionario.java
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 161


8.3 Herança e modificador private
Métodos ou atributos private só podem ser acessados diretamente na própria classe na qual são definidos. O
que acontece quando uma subclasse tenta acessar diretamente métodos ou atributos private, definidos na
superclasse?
Veja a seguir a tentativa de acessar diretamente os atributos nome, endereco e rg definidos na classe Pessoa,
dentro da classe Funcionario. O resultado foi um erro, porque estes atributos foram definidos como private
na classe Pessoa e, devido a isto, não estavam acessíveis a partir da subclasse Funcionario.

r
.b
1. public class Funcionario extends Pessoa {
2.
3. private long carteiraProfissional;

m
4. private double salario;
5. private String dataAdmissao;
6.

co
7. public void setCarteiraProfissional(long carteira) {
8. this.carteiraProfissional = carteira;
9. }
10. public long getCarteiraProfissional() {
11. return carteiraProfissional;
12. }
13. public void setSalario(double salario) {
14.
15. }
this.salario = salario;
g.
in
16. public double getSalario() {
17. return salario;
18. }
nn

19. public void setDataAdmissao(String dataAdmissao) {


20. this.dataAdmissao = dataAdmissao;
21. }
22. public String getDataAdmissao() {
23. return dataAdmissao;
ai

24. }
25. public void impressaoRecibo(int dia, int mes, int ano) {
26. System.out.println("\n\n------- Recibo pagamento ------");
27. System.out.print(" Eu, " + nome + ", portador do RG de numero: ");
.tr

28. System.out.print(rg + " declaro que recebi o valor de R$ " + salario);


29. System.out.print(" referente ao meu pagamento no dia "
30. + dia + "/" + mes + "/" + ano);
w

31. System.out.println("\n-----------------------------------\n\n");
32. }
33.}
w

Código 8.8 - Funcionario.java acessando atributos da superclasse


w

Trainning Education Services - Todos os direitos reservados 162


r
.b
8.4 Modificador protected

m
Em determinadas situações é interessante que alguns atributos estejam disponíveis para as classes filhas. Nestas
condições, é possivel utilizar o modificador protected em atributos ou métodos. Agora a classe Pessoa será

co
alterada fazendo com que seus atributos sejam declarados com o modificador protected, ao invés de
private, permitindo assim que sejam acessados a partir da classe Funcionario.

1. public class Pessoa {


2. protected Endereco endereco;
3. protected String nome;
4. protected String rg;
g.
in
5. public void setEndereco(Endereco endereco) {
6. this.endereco = endereco;
7. }
8. public Endereco getEndereco() {
nn

9. return endereco;
10. }
11. public void setNome(String nome) {
12. this.nome = nome;
13. }
ai

14. public String getNome() {


15. return nome;
16. }
.tr

17. public void setRg(String rg) {


18. this.rg = rg;
19. }
20. public String getRg() {
w

21. return rg;


22. }
23. public void imprime() {
24. System.out.println("Nome: " + nome);
w

25. System.out.println("RG: " + rg);


26. System.out.print("Endereco: " + endereco.getRua());
27. System.out.println(" , " + endereco.getNumero());
w

28. }
29.}

Código 8.9 - Pessoa.java com atributos protected

Trainning Education Services - Todos os direitos reservados 163


Com esta alteração, agora será possivel para a classe Funcionario acessar os atributos desejados dentro do
método imprimeRecibo.

r
.b
m
Representação UML do modificador protected

co
g.
Diagrama 8.4 - modificador protected
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 164


8.5 Referência implícita super
Para referenciar os atributos e métodos da classe pai (ou superclasse) utiliza-se a referência implícita super.
Esta referência é análoga à referência implícita this que, como já foi visto , é utilizada para acessar atributos e
métodos da própria classe. A referência super, por sua vez, é utilizada para acessar atributos e métodos da
superclasse, desde que visíveis de acordo com os modificadores de acesso.

O método impressaoRecibo será modificado na classe Funcionario, utilizando-se a referência implícita

r
super para acessar atributos da superclasse Pessoa.

.b
1. public class Funcionario extends Pessoa {

m
2.
3. private long carteiraProfissional;
4. private double salario;
5. private String dataAdmissao;

co
6.
7. public void setCarteiraProfissional(long carteiraProfissional) {
8. this.carteiraProfissional = carteiraProfissional;
9. }
10. public long getCarteiraProfissional() {
11.
12. }
return carteiraProfissional;

13. public void setSalario(double salario) {


g.
in
14. this.salario = salario;
15. }
16. public double getSalario() {
17. return salario;
nn

18. }
19. public void setDataAdmissao(String dataAdmissao) {
20. this.dataAdmissao = dataAdmissao;
21. }
22. public String getDataAdmissao() {
ai

23. return dataAdmissao;


24. }
25. public void impressaoRecibo(int dia, int mes, int ano) {
.tr

26. System.out.println("\n------- Recibo pagamento ----------");


27. System.out.print(" Eu, " + super.nome + ", portador do RG de numero: ");
28. System.out.print(super.rg +" declaro que recebi o valor de R$ "+ salario);
29. System.out.print(" referente ao meu pagamento no dia "
w

30. + dia + "/" + mes + "/" + ano);


31. System.out.println("\n-----------------------------------\n");
32. }
w

33.}
w

Código 8.10 - Funcionario.java utilizando a variável implícita super

Trainning Education Services - Todos os direitos reservados 165


1. public class TesteFuncionario {
2. public static void main(String[] args) {
3.
4. // Criando o endereco para o funcionário f
5. Endereco end1 = new Endereco("Rua das tulipas", 1200);
6.
7. // Criando o funcionário f
8. Funcionario f = new Funcionario();
9.
10. // atribuindo as características herdadas da classe Pessoa

r
11. f.setNome("Pedro da Silva");

.b
12. f.setEndereco(end1);
13. f.setRg("1234545");
14.
15. // atribuindo as características específicas de funcionários

m
16. f.setSalario(10000);
17. f.setCarteiraProfissional(123434L);
18. f.impressaoRecibo(16,4,2005);
19. }

co
20.}

Código 8.11 - TesteFuncionario.java utilizando o método impressaoRecibo

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 166


8.6 Construtores x Herança
Primeiramente é importante ressaltar que construtores não são herdados em hipótese nenhuma! Cada classe
deve declarar seus próprios construtores.

Além disso, toda classe deve chamar o construtor da superclasse dentro de seu próprio construtor, pois isso é
necessário para que seja feita a inicialização dos elementos herdados. Esta chamada ao construtor da
superclasse deve ser a primeira instrução do construtor da classe. Caso esta chamada não seja feita

r
explicitamente no código da classe, o compilador irá acrescentar uma chamada implícita ao construtor sem

.b
parâmetros da superclasse.

m
Sintaxe para chamar o construtor da superclasse:

co
super(<ZERO ou mais parametros>)

A seguinte instrução é incluída implicitamente pelo compilador Java em construtores que não fazem chamadas
explicitas a outros construtores:

super();
g.
in
Se a superclasse não possuir o construtor default (construtor padrão), isto é, se tiver apenas construtores com
nn

parâmetros, deve ser feita obrigatoriamente a chamada a um construtor existente da superclasse.

Para entender melhor o que isto significa, veja o que acontece quando se adiciona um construtor que receba
ai

todos os parâmetros de inicialização da classe Pessoa e é feita a recompilação das classes Funcionario e
Pessoa.
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 167


1. public class Pessoa {
2. protected Endereco endereco;
3. protected String nome;
4. protected String rg;
5.
6. Pessoa(Endereco e, String nome, String rg) {
7. this.setEndereco(e);
8. this.setNome(nome);
9. this.setRg(rg);
10. }
11. public void setEndereco(Endereco endereco) {

r
12. this.endereco = endereco;
13. }

.b
14. public Endereco getEndereco() {
15. return endereco;
16. }
17.

m
18. public void setNome(String nome) {
19. this.nome = nome;
20. }

co
21. public String getNome() {
22. return nome;
23. }
24. public void setRg(String rg) {
25. this.rg = rg;
26. }
27. public String getRg() {
28.
29. }
return rg;
g.
in
30. public void imprime() {
31. System.out.println("Nome: " + nome);
32. System.out.println("RG: " + rg);
nn

33. System.out.print("Endereco: " + endereco.getRua());


34. System.out.println(" , " + endereco.getNumero());
35. }
36.}
ai

Código 8.12 - Pessoa.java com construtor que recebe parâmetros


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 168


Mas por que a classe não compila?
Na verdade, o compilador, além de adicionar o construtor default quando nenhum construtor é
declarado explicitamente, adiciona a cláusula extends Object quando nenhuma outra declaração de
herança é feita; também adiciona uma chamada ao construtor da super classe,
sempre que esta operação não for feita explicitamente.

O que ocorreu foi que o compilador adicionou o seguinte fragmento de código, representando o construtor default

r
na classe Funcionario:

.b
Funcionario() {

m
super();
}

co
Ainda no mesmo exemplo, a classe Pessoa não possui um construtor default porque foi declarado um construtor
com três parâmetros da seguinte forma:

Pessoa(Endereco endereco, String nome, String rg)


g.
in
Como corrigir este problema?
Para corrigir este problema, é necessário declarar um construtor para que o compilador não
nn

adicione automaticamente o default com as características citadas acima. O construtor


declarado deve chamar explicitamente um construtor válido da classe Pessoa (superclasse)
como primeira instrução.
ai

Veja agora a classe Funcionario com um construtor válido.


.tr

1. public class Funcionario extends Pessoa{


2. private long carteiraProfissional;
3. private double salario;
w

4. private String dataAdmissao;


5.
6. public Funcionario(Endereco endereco, String nome, String rg) {
7. super(endereco, nome, rg);
w

8. }
9. //demais métodos idênticos ao exemplo anterior da classe Funcionario
10.}
w

Código 8.13 - Funcionario.java chamando o construtor da superclasse

Trainning Education Services - Todos os direitos reservados 169


O construtor é o elemento que define de que forma os objetos devem ser criados e quais os dados necessários
para criá-los. Isto também é válido no conceito de herança, no qual a classe filha é uma especialização da classe
pai. Veja a seguinte conclusão:

A classe pai (Pessoa) definiu a seguinte regra:


“Para criar uma instância da classe Pessoa é necessário indicar: nome, endereco e o RG da pessoa.” Por
conseguinte, a classe Funcionário, que é uma especialização da classe Pessoa, deve seguir as mesmas
regras de criação da classe Pessoa (nome, endereço, RG).

r
.b
O compilador garante que as regras de construção de objetos definidas na classe pai serão seguidas nas
classes filhas quando ele adiciona uma chamada ao construtor padrão da superclasse, obrigando a classe filha a
chamar um construtor válido da superclasse.

m
• É importante ressaltar que a chamada ao construtor da superclasse deverá

co
sempre ser a primeira instrução do construtor!
• Como ambas devem ser a primeira instrução do construtor, não é permitido fazer
uma chamada ao this() e outra ao super(), ou vice-versa.

1. public class Funcionario extends Pessoa {


g.
in
2. public Funcionario(Endereco endereco, String nome, String rg) {
3. System.out.println("Construtor da classe Funcionario");
4. super(endereco, nome, rg);
5. }
nn

6. // ... o restante da classe foi omitido


7.}

Código 8.14 - Funcionario.java com chamada inválida ao construtor da superclasse


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 170


8.6.1 Seqüência completa de inicialização dos objetos em Java
Anteriormente foi apresentada a seqüência de inicialização de objetos em Java, iniciada a partir da chamada ao
construtor da classe. Complementando a seqüência para incluir as chamadas aos construtores das superclasses,
há as seguintes operações:
1. espaço em memória é alocado para o objeto sendo construído;
2. cada um dos atributos do objeto é criado e inicializado para seu valor default;
3. é chamado o construtor da superclasse;
4. cada um dos atributos da superclasse é criado e inicializado para seu valor default;

r
5. a inicialização dos atributos via declaração e o código do bloco de inicialização da superclasse são

.b
executados na ordem em que aparecem;
6. o código do construtor da superclasse é executado;

m
7. a inicialização dos atributos via declaração e o código do bloco de inicialização da classe são executados
na ordem em que aparecem;
8. o código do construtor da classe é executado.

co
Esta seqüência pode ser vista na execução das classes de exemplo a seguir:

1. public class ExemploSuperClasse {


2.
3.
int campoSuper = 25;
{
g.
in
4. System.out.println("Bloco de inicializacao da superclasse");
5. }
6. ExemploSuperClasse() {
nn

7. System.out.println("Construtor da superclasse");
8. }
9.}

Código 8.15 - ExemploSuperClasse.java


ai
.tr

1. public class ExemploSubClasse extends ExemploSuperClasse {


2. int campo = 15;
3. {
4. System.out.println("Bloco de inicializacao da subclasse");
w

5. }
6.
7. ExemploSubClasse() {
w

8. System.out.println("Construtor da subclasse");
9. }
10.}
w

Código 8.16 - ExemploSubClasse.java

Trainning Education Services - Todos os direitos reservados 171


1. public class TesteInicializacaoObjetos {
2. public static void main(String[] args) {
3. ExemploSubClasse sub = new ExemploSubClasse();
4. }
5.}
Código 8.17 - TesteInicializacaoObjetos.java

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 172


new ExemploSubclasse()

Espaço em memória é alocado para o


objeto sendo construído

ExemploSubclasse@3554

Cada um dos atributos do objeto é criado


e inicializado para seu valor padrão campo = 0

r
.b
ExemploSubclasse@3554

É chamado o construtor da superclasse

m
Cada um dos atributos da superclasse é campo = 0

co
criado e inicializado para seu valor padrão campoSuper = 0

ExemploSubclasse@3554
A inicialização dos atributos via
declaração e o código do bloco de
g. campo = 0
in
inicialização da superclasse são campoSuper = 25
executados na ordem em que aparecem
ExemploSubclasse@3554
nn

O código do construtor da superclasse é


executado
ai
.tr

A inicialização dos atributos via


declaração e o código do bloco de campo = 15
inicialização da classe são executados na campoSuper = 25
w

ordem em que aparecem


ExemploSubclasse@3554
w

O código do construtor da classe é


w

executado

Figura 8.1 - inicialização completa de objetos Java

Trainning Education Services - Todos os direitos reservados 173


8.7 Sobrescrita de métodos
Sobrescrita de método = override
A sobrescrita ou sobreposição de métodos, mais conhecida em inglês como override, é uma prática muito comum
em Java. Quando se estende uma classe e se pretende alterar o comportamento de um método herdado, é
necessário reescrever o método na classe filha, sobrescrevendo o método herdado da superclasse.

As seguintes regras devem ser respeitadas para sobrescrever um método de uma superclasse:

r
o novo método deve ter exatamente o mesmo nome daquele que quer se sobrescrever, caso

.b
contrário será criado apenas um novo método, ao invés de sobrescrevê-lo;
• o método deverá ter a mesma lista de parâmetros, caso contrário será uma sobrecarga de método
(overload) e não uma sobrescrita;

m
• o tipo do valor de retorno do método deverá ser o mesmo do método que está se sobrescrevendo,
caso contrário ocorrerá um erro de compilação. A partir do Java 5 foi introduzido a covariância de

co
valores de retorno, que permite que o tipo retornado seja também uma subclasse do tipo retornado
pelo método sobrescrito. A covariância será abordada mais adiante;
• não se pode lançar exceções que não estejam declaradas no método, mas apenas as mesmas


g.
exceções declaradas na assinatura do método ou que sejam subclasses daquela declarada (este
tópico será discutido mais adiante, no capítulo de Tratamento de Erros);
um método static não pode sobrescrever um método não static e vice-versa;
in
• um método não deve ter um modificador de acesso mais restritivo que o método sobrescrito.
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 174


Veja um exemplo de sobrescrita para o método imprime da classe Pessoa:

1. public class Pessoa {


2. protected Endereco endereco;
3. protected String nome;
4. protected String rg;
5.
6. public Pessoa(Endereco e, String nome, String rg) {
7. this.setEndereco(e);
8. this.setNome(nome);
9. this.setRg(rg);
10. }

r
11.

.b
12. public void imprime() {
13. System.out.println("Nome: " + nome);
14. System.out.println("RG: " + rg);
15. System.out.print("Endereco: " + endereco.getRua());

m
16. System.out.println(" , " + endereco.getNumero());
17. }
18.
19. //demais métodos idênticos ao exemplo anterior da classe Pessoa

co
20.
21.}

Código 8.17 - Pessoa.java

1. public class Funcionario extends Pessoa{


2.
g.
in
3. private long carteiraProfissional;
4. private double salario;
5. private String dataAdmissao;
nn

6.
7. public Funcionario(Endereco e, String nome, String rg,
8. long carteira, double salario, String dataAdmissao) {
9. super(e, nome, rg);
10. this.setCarteiraProfissional(carteira);
ai

11. this.setSalario(salario);
12. this.setDataAdmissao(dataAdmissao);
13. }
14.
.tr

15. public void imprime() {


16. System.out.println("Imprimindo dados do funcionario");
17. super.imprime();
18. System.out.println("carteira profissional: " + carteiraProfissional);
w

19. System.out.println("salario: " + salario);


20. System.out.println("dataAdmissao: " + dataAdmissao);
21. }
w

22.
23. //demais métodos idênticos ao exemplo anterior de Funcionario
24.}
w

Código 8.18 - Funcionario.java com sobrescrita do método imprime

Trainning Education Services - Todos os direitos reservados 175


1. public class TesteSobrescrita {
2. public static void main(String[] args) {
3.
4. // Criando um endereço
5. Endereco end1 = new Endereco("Rua das tulipas", 1200);
6.
7. // Criando a pessoa p e imprimindo seus dados
8. Pessoa p = new Pessoa(end1, "Maria da Silva", "9876543");
9. p.imprime();
10.

r
11. //Imprimindo uma linha em branco
12. System.out.println();

.b
13.
14. // Criando o funcionário f e imprimindo seus dados
15. Funcionario f = new Funcionario(end1, "Pedro da Silva", "1234545",

m
16. 123434L, 10000, "16/04/2001");
17. f.imprime();
18. }
19.}

co
Código 8.19 - TesteSobrescrita.java

g.
in
nn
ai
.tr

Observe que o intuito da sobrescrita feita na classe Funcionario, foi adequar o método imprime, herdado de
w

Pessoa, para que também imprima os valores dos atributos do funcionário. Note também, que para evitar
duplicação de código nas duas classes, no método sobrescrito foi feita a chamada ao método herdado original,
w

utiizando-se a variável implícita super.


w

super.imprime();

Trainning Education Services - Todos os direitos reservados 176


Representando a sobrescrita na UML

A sobrescrita de métodos na UML é representada repetindo o método na classe filha que herda o
método.

r
.b
m
Diagrama 8.5 - sobrescrita de métodos

co
8.7.1 Sobrescrita do método toString()
Para entender melhor como funciona a sobrescrita, veja como sobrescrever um método
g.
que todas as classes herdam da classe Object. Será sobrescrito o método
toString(), que tem como objetivo criar uma representação do objeto como uma
in
String. Esta representação pode ser utilizada para imprimir o objeto na console, para
salvá-lo em um arquivo texto, etc. No método toString()são escolhidos os atributos
nn

considerados necessários para representar o objeto, e eles são concatenados de forma


que a String resultante atenda o objetivo proposto.
ai

Este método é implementado na classe Object para retornar a seguinte String:

<nomeDaClasse>@hashCode
.tr

Agora ele será reescrito na classe Pessoa, fazendo com que retorne uma String contendo o nome, RG e
w

endereço, ao invés de retornar algo parecido com Pessoa@12342.


w
w

Trainning Education Services - Todos os direitos reservados 177


1. public class Pessoa {
2.
3. private Endereco endereco;
4. private String nome;
5. private String rg;
6.
7. Pessoa(Endereco e, String nome, String rg) {
8. this.setEndereco(e);
9. this.setNome(nome);
10. this.setRg(rg);
11. }

r
12.
13. public Endereco getEndereco() { return endereco; }

.b
14. public String getNome() { return nome; }
15. public String getRg() { return rg; }
16.
17. public void setEndereco(Endereco endereco) {

m
18. this.endereco = endereco;
19. }
20. public void setNome(String nome) {

co
21. this.nome = nome;
22. }
23. public void setRg(String rg) {
24. this.rg=rg;
25. }
26. public void imprime() {
27.
28.
29.
System.out.println("Nome: " + nome);
System.out.println("RG: " + rg);
System.out.print("Endereco: " + endereco.getRua());
g.
in
30. System.out.println(" , " + endereco.getNumero());
31. }
32.
nn

33. public String toString() {


34. String tmpPessoa = "Nome: " + nome + "\n";
35. tmpPessoa += "RG: " + rg + "\n";
36. tmpPessoa += "Endereco " +endereco.getRua() + ", " + endereco.getNumero();
37. return tmpPessoa;
ai

38. }
39.}
Código 8.20 - Pessoa.java com sobrescrita do método toString
.tr

E quando o método toString() é chamado?


Este método é chamado sempre que um objeto é impresso utilizando-se: System.out.println(<objeto>)
w

ou quando ocorre a concatenação de uma String com um objeto.


w

Para entender melhor este exemplo, observe o resultado gerado pela execução da classe
TestePessoaToString apresentada abaixo.
w

Trainning Education Services - Todos os direitos reservados 178


1. public class TestePessoaToString {
2. public static void main(String[] args) {
3. Endereco e = new Endereco("Av. Bernardino de Campos", 327);
4. Pessoa p = new Pessoa(e, "Antonio Claudio", "1231321");
5. // O método toString() será chamado automaticamente
6. System.out.println(p);
7. System.out.println();
8. String texto = "Dados da pessoa : \n" + p;
9. System.out.println(texto);
10. }
11.}

r
Código 8.21 - TestePessoaToString.java

.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 179


8.8 Modificador final
O modificador final pode ser utilizado na declaração de atributos, métodos e classes, tendo comportamento
diferente em cada uma das situações.

8.8.1 Modificador final na declaração de classes


O modificador final pode ser utilizado na declaração de classes, indicando que a classe não poderá ser
estendida por outra, ou seja, não poderá ser herdada.

r
.b
1. public final class ContaCorrente {
2. //Corpo da classe

m
3.}

Código 8.22 - ContaCorrente.java

co
1. public class ContaCorrenteEspecial extends ContaCorrente{
2.
3.}
g.
in
Código 8.23 - ContaCorrenteEspecial.java
nn
ai
.tr
w
w

Na tentativa de estender a classe ContaCorrente na classe ContaCorrenteEspecial, ocorreu um erro de


compilação que demonstra que a classe é final e não pode ser herdada.
w

Trainning Education Services - Todos os direitos reservados 181


8.8.2 Modificador final na declaração de métodos
O modificador final pode ser utilizado na declaração de um método, para que ele não possa ser sobrescrito em
classes filhas.

1. public class ContaPoupanca {


2. protected double saldo;
3.
4. public ContaPoupanca(double saldoInicial) {
5. this.saldo = saldoInicial;
6. }

r
7. public final void saque(double valor) {
8. if (saldo > valor)

.b
9. saldo -= valor;
10. else
11. System.out.println("Saldo insuficiente");

m
12. }
13.}

Código 8.24 - ContaPoupanca.java

co
Na próxima classe ocorre a tentativa de alterar o método saque, mudando seu comportamento através da
sobrescrita.

1. class ContaPoupancaEspecial extends ContaPoupanca {


2.
3. public double limite = 1000;
g.
in
4.
5. ContaPoupancaEspecial(double saldo) {
6. super(saldo);
7. }
nn

8. public void saque(double valor) {


9. if (saldo + limite > valor) saldo -= valor;
10. }
11.}
ai

Código 8.25 - ContaPoupancaEspecial.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 182


Como já foi visto, não é possível sobrescrever o método saque, porque ele foi declarado como final na super
classe.

8.8.3 Modificador final na declaração de atributos


O modificador final quando utilizado em atributos, define que somente uma atribuição deverá ser feita ao atributo,
podendo ser feita na declaração ou no construtor. Isto é o equivalente a criação de constantes.

Se o atributo for do tipo primitivo, depois de feita a inicialização, não é possível mais alterar o seu conteúdo. Veja o

r
exemplo da classe Pedido, a seguir:

.b
m
1. public class Pedido {
2.
3. //declaração de constantes
4. public final static int NOVO = 1;

co
5. public final static int APROVADO = 2;
6. public final static int CANCELADO = 3;
7.
8. //declaração de atributos
9. private final int codigo;
10.
11.
12.
13.
private int status;

public Pedido(int cod) {


this.codigo = cod;
g.
in
14. this.setStatus(Pedido.NOVO);
15. }
16.
nn

17. public void setStatus(int status) {


18. this.status = status;
19. }
20.
21. public void setCodigo(int codigo) {
ai

22. this.codigo = codigo;


23. }
24.
25. public int getCodigo() {
.tr

26. return codigo;


27. }
28.
29. public int getStatus() {
w

30. return status;


31. }
32.}
w

Código 8.26 - Pedido.java com atribuição inválida para variável final


w

Trainning Education Services - Todos os direitos reservados 183


r
.b
Ocorre um erro de compilação no método setCodigo, devido a tentativa de associar um novo valor ao atributo
codigo. Para compilar a classe basta remover este método. Este é um exemplo de atributo somente para leitura.

m
Note também a declaração de constantes estáticas na classe para definir possíveis valores para o atributo status.

co
Este tipo de uso, onde combinam-se os modificadores final e static para definir constantes é bem comum. A
classe utilitária Math define um atributo final static para a constante PI.

g.
Se o atributo for do tipo reference, já se sabe que a variável armazena uma referência para o objeto e, por isto,
não é possível alterar tal referência. No entanto, pode-se chamar métodos e atributos do objeto referenciado,
alterando-se seu estado.
in
Veja o que ocorre a seguir para a classe OrdemDeCompra: nesta classe foi criada um atributo da classe Cliente
com o modificador final, e apesar de não ser possivel associar uma ordem de compra a um novo cliente, é
nn

possivel mudar o valor dos atributos do cliente.


ai

1. public class OrdemDeCompra {


2. public final Cliente cliente;
.tr

3.
4. public OrdemDeCompra (Cliente cliente) {
5. this.cliente = cliente;
6. }
w

7.}

Código 8.27 - OrdemDeCompra.java


w
w

Trainning Education Services - Todos os direitos reservados 184


1. public class Cliente {
2. private String nome;
3. public Cliente(String nome) {
4. this.nome = nome;
5. }
6. public String getNome() {
7. return nome;
8. }
9. public void setNome(String nome) {
10. this.nome = nome;
11. }
12.}

r
.b
Código 8.28 - Cliente.java

1. public class TesteOrdemDeCompra {


2.

m
3. public static void main(String[] args) {
4. Cliente cliente = new Cliente("Antonio Pereira");
5. OrdemDeCompra ordem = new OrdemDeCompra(cliente);
6.

co
7. //é possivel alterar os dados do cliente
8. ordem.cliente.setNome("Marcos Pereira");
9.
10. //não é possivel atribuir um novo cliente ao pedido
11.
12.
13.
14.}
}
Cliente cliente2 = new Cliente("Ana Silva");
ordem.cliente = cliente2;
g.
in
Código 8.29 - TesteOrdemDeCompra.java
nn
ai
.tr
w

Observe que ocorreu um erro na tentativa de atribuição de um novo Cliente ao atributo cliente da classe
w

TesteOrdemDeCompra.
w

• É importante ressaltar que o modificador final também pode ser aplicado a


variáveis locais e parâmetros de métodos.

Trainning Education Services - Todos os direitos reservados 185


8.9 Certificação Oracle Certified Java Programmer (OCJP)
1. Consider the following piece of code:

1. public class Vehicle {


2. public void move() {
3. System.out.println("move");
4. }
5. }
6. public class VehicleOnWheels extends Vehicle{

r
7. public void move() {

.b
8. System.out.println("moves on wheels");
9. }
10.}
11.public class Car extends VehicleOnWheels {

m
12. public void move() {
13. System.out.println("move on 4 wheels");
14. }
15.

co
16. public static void main(String[] args) {
17. Car car = new Car();
18. //insert code here
19. }
20.} g.
in
Which instruction can replace the comment if you want to access de ancestor method move in Vehicle so it prints
out the String "move":
nn

A) car.super().super().move();
B) car.parent().parent().move();
C) car.move();
ai

D) none of the above;


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 186


2. Consider the following piece of code:

1. public class Super {


2. public Super() {
3. System.out.println("value = " + getValue());
4. }
5.
6. public int getValue() {
7. return -1;
8. }
9.}

r
10.

.b
11.public class Sub extends Super {
12. private int value = 15;
13.
14. public int getValue() {

m
15. return value;
16. }
17.
18. public static void main(String[] args) {

co
19. Sub sub = new Sub();
20. }
21.}

What is the result of compiling the classes and running Sub:


g.
in
A) prints out "value = -1"
B) prints out "value = 15";
nn

C) prints out "value = 0";


D) prints out "value = null";
E) runtime error: value is not defined
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 187


3. What will be the result of compiling and running the following code?

1. class Qualquer {
2. int a;
3.
4. Qualquer (int a) {
5. this.a = a;
6. }
7.
8. void setA(int a) {

r
9. this.a = a;

.b
10. }
11.
12. public String toString() {
13. return "" + a;

m
14. }
15.}
16.
17. class CJFoo {

co
18. public static void main(String a[]) {
19. Qualquer d1 = new Qualquer(1);
20. Qualquer d2 = new Qualquer(2);
21. amethod(d1, d2);
22. System.out.println("d1 is : " + d1 + " / d2 is : " + d2);
23.
24.
25.
}

static void amethod(Qualquer p1, Qualquer p2) {


g.
in
26. p1.setA(100);
27. p2 = p1;
28. }
29.}
nn

A) Doesn’t compile
ai

B) Doesn’t run
C) d1 is: 100 / d2 is: 100
.tr

D) d1 is: 2 / d2 is: 2
E) d1 is 100 / d2 is 2
w
w
w

Trainning Education Services - Todos os direitos reservados 188


4. What is the result of compiling and running the following classes:

1: public class Foo {


2: void method() {
3: System.out.println("Inside foo method!!");
4: }
5: }
6: public class Bar extends Foo{
7: static void method() {
8: System.out.println("Inside bar method!!");

r
9: }

.b
10:
11: public static void main(String[] args) {
12: Bar b = new Bar();
13: }

m
14: }

co
A) Compilation error at line 2.
B) Compilation error at line 7.
C) No compilation error, but runtime exception at line 2.
D) No compilation error, but runtime exception at line 7.

5. Consider the class defined below:


g.
in
nn

1. public class FinalArray {


2. public static void main(String[] args) {
3. final int[] primeNumbers = {1,2,3,5};
4. primeNumbers[3] = 7;
5. for (int i = 0; i < primeNumbers.length; i++) {
ai

6. System.out.print(primeNumbers[i]+", ");
7. }
8. }
9.}
.tr

Which is the generated output?


w

A) The code doesn’t compile


B) The code doesn’t run
w

C) 1, 2, 3, 5,
D) 1, 2, 3, 7,
w

Trainning Education Services - Todos os direitos reservados 189


6. Which statements concerning the code below are true?

1. class Point {
2. private int x, y;
3.
4. public Point(int x, int y) {
5. this.x = x;
6. this.y = y;
7. }
8.}

r
9. class Shape {

.b
10. public final void drawLine(Point start, Point end) {
11. //code to draw line
12. }
13.}

m
14.class Triangle extends Shape{
15. private Point a, b, c;
16.
17. public Triangle(Point a, Point b, Point c) {

co
18. this.a = a;
19. this.b = b;
20. this.c = c;
21. }
22.
23.
24.
25.
public void draw() {
drawLine(a,b);
drawLine(b,c);
g.
in
26. drawLine(c,a);
27. }
28.}
nn

29.public class TestTriangle {


30.
31. public static void main(String[] args) {
32. Point a = new Point(0,0);
33. Point b = new Point(15,15);
ai

34. Point c = new Point(30,0);


35. Triangle t = new Triangle(a,b,c);
36. t.draw();
37. }
.tr

38.}
w

A) The code will not compile because Shape is not also declared as final.
B) The code will not compile because you cannot invoke a final method from a subclass.
w

C) The code will compile and run fine.


D) The code will compile but will throw a NoSuchMethodException when TestTriangle is run.
w

Trainning Education Services - Todos os direitos reservados 190


7. Which statements concerning the relationships between the following classes are true?

1. class Ace {
2. Case c = new Case();
3.}
4.
5. class Base {
6.}
7.
8. class Case extends Ace {

r
9. Base b = new Base();
10.}

.b
m
A) A Base is a Case.
B) An Ace has a Base.
C) A Case is an Ace.

co
D) An Ace is a Case.
E) A Case has a Base.

g.
8. What is the result when you compile and run the following code?
in
1. class Animal {
2. private String name;
3. Animal(String name) {
4. System.out.println("Inside Animal's constructor");
nn

5. this.name = name;
6. }
7.}
8.
9. class Dog extends Animal {
ai

10. Dog() {
11. System.out.println("Inside dog's constructor");
12. }
.tr

13.
14. public static void main(String[] args) {
15. Dog d = new Dog();
16. }
w

17.}

A) will print: "Inside Animals's constructor" followed by "Inside dog's constructor"


w

B) will print: "Inside dog's constructor"


C) Compile time error
w

D) Runtime error

Trainning Education Services - Todos os direitos reservados 191


CAPÍTULO

r
.b
m
co
g.
in
nn
ai

Enumerações
.tr

Introdução ao uso de enumerações


w

Imprimindo os elementos da enumeração


Adicionando atributos e métodos à enumeração
Representando enumerações na UML
w
w

Trainning Education Services - Todos os direitos reservados 193


9 Enumerações
Até a versão 1.4 da plataforma Java, muito freqüentemente eram utilizadas constantes estáticas inteiras para
representar um conjunto finito de tipos, tais como cores, dias da semana, tipos de produtos, status de pedidos e
outros, dados que geralmente estão associados a uma classe e não estão persistidos. O exemplo abaixo ilustra
essa situação típica:

r
1. public class Cliente {
2.

.b
3. public final static int PESSOA_JURIDICA = 1;
4. public final static int PESSOA_FISICA = 2;
5. private String nome;
6. private String email;

m
7. private int tipo;
8.
9. public Cliente(String nome, String email, int tipo) {

co
10. this.nome = nome;
11. this.email = email;
12. this.tipo = tipo;
13. }
14.
15.
16.
17.
18.
public String getNome() {

}
return nome;
g.
in
19. public void setNome(String nome) {
20. this.nome = nome;
21. }
nn

22.
23. public String getEmail() {
24. return email;
25. }
26.
ai

27. public void setEmail(String email) {


28. this.email = email;
29. }
30.
.tr

31. public int getTipo() {


32. return tipo;
33. }
34.
w

35. public void setTipo(int tipo) {


36. this.tipo = tipo;
37. }
w

38.}

Código 9.1 - Cliente.java com constantes estáticas


w

Trainning Education Services - Todos os direitos reservados 195


1. public class TesteCliente {
2. public static void main(String[] args) {
3. Cliente c = new Cliente("Maria", "maria@gc.com.br",
4. Cliente.PESSOA_FISICA);
5. System.out.println("tipo de cliente criado = " + c.getTipo());
6. }
7.}

Código 9.2 - TesteCliente.java

r
.b
m
co
g.
Nesta abordagem não há como restringir o valor que será passado pelo usuário no construtor da classe Cliente,
ou seja, se o usuário passar um valor inteiro inválido, como por exemplo 7 não haverá erro de compilação. Não há,
também, como obrigá-lo a utilizar a constante estática ao invés do número inteiro. Os trechos de código a seguir
in
ilustram estas possibilidades:
nn

• uso de valor inválido para o atributo tipo:


Cliente c = new Cliente("Maria", "maria@gc.com.br",7);

• uso de um valor inteiro em vez das constantes pré-definidas:


ai

Cliente c = new Cliente("Maria", "maria@gc.com.br",2);

Note também que trabalhar com o tipo inteiro pode ser inconveniente em vários casos, exigindo um tratamento
.tr

especial do código, como já apresentado. Ao imprimir o tipo do cliente na console, não há certeza se o tipo é
pessoa física ou jurídica pois o valor impresso foi o número 2.
w

Para resolver todos estes problemas, foi criado no Java5 um novo tipo de dado denominado enumeração (enum).
Este novo tipo garante o uso de valores pertencentes a um conjunto pré-definido, ou seja, garante o uso de tipos
w

seguros, daí também ser conhecido por type-safe enumeration.


w

Trainning Education Services - Todos os direitos reservados 196


9.1 Introdução ao uso de enumerações
Para declarar uma enumeração utiliza-se a palavra reservada enum seguida do nome desejado, seguindo a
convenção de nomes das classes (iniciado com letra maíuscula). Os valores da enumeração são colocados entre
chaves e separados por vírgula.

sintaxe para declaração de enumerações:


<modificadores> enum nomeEnum { listaValores }

r
.b
O exemplo abaixo declara uma enumeração com dois valores somente: PESSOA_JURIDICA e PESSOA_FISICA.
Note que a propriedade / atributo que irá receber um valor da enumeração na classe, neste caso o atributo tipo,
deve ser declarado com o mesmo nome da enumeração, indicando assim que somente valores da enumeração

m
serão válidos.

co
1. public class Cliente {
2.
3. public enum TipoCliente { PESSOA_FISICA, PESSOA_JURIDICA };
4. private TipoCliente tipo;
5.
6.
7.
8.
private String nome;
private String email;
g.
public Cliente(String nome, String email, TipoCliente tipo) {
in
9. this.nome = nome;
10. this.email = email;
11. this.tipo = tipo;
nn

12. }
13. public String getNome() {
14. return nome;
15. }
16. public void setNome(String nome) {
ai

17. this.nome = nome;


18. }
19. public String getEmail() {
20. return email;
.tr

21. }
22. public void setEmail(String email) {
23. this.email = email;
24. }
w

25. public TipoCliente getTipo() {


26. return tipo;
27. }
w

28. public void setTipo(TipoCliente tipo) {


29 this.tipo = tipo;
30. }
w

31.}

Código 9.3 - Cliente.java com enumeração

Trainning Education Services - Todos os direitos reservados 197


A enumeração e seus itens podem ser acessados como variáveis estáticas, ou seja, o nome da classe que contém
a enumeração, seguido do nome do item da enumeração.

Cliente.TipoCliente.PESSOA_FISICA

O exemplo abaixo instancia um objeto da classe Cliente passando um dos valores da enumeração ao
construtor.

r
.b
1. public class TesteClienteEnumeracao {
2. public static void main(String[] args) {
3. Cliente c = new Cliente("Maria", "maria@gc.com.br",

m
4. Cliente.TipoCliente.PESSOA_FISICA);
5. System.out.println("tipo de cliente criado = " + c.getTipo());
6. }
7.}

co
Código 9.4 - TesteClienteEnumeracao.java

g.
in
nn

No exemplo anterior a enumeração foi criada dentro da classe Cliente, porque representa um tipo específico desta
ai

classe. Podem ser criadas enums em seu próprio arquivo .java, quando se deseja uma melhor reutilização. Isso
pode ser visto a seguir, definindo um tipo para representar os meses do ano.
.tr

1. public enum Mes {


2. JANEIRO, FEVEREIRO, MARCO, ABRIL, MAIO, JUNHO, JULHO,
3. AGOSTO, SETEMBRO, OUTUBRO, NOVEMBRO, DEZEMBRO
4.}
w

Código 9.5 - Mes.java


w
w

Trainning Education Services - Todos os direitos reservados 198


Enumerações também podem ser utilizadas em instruções switch, conforme mostra o código a seguir:

1. public class TesteMes {


2. public static void main(String[] args) {
3. Mes mes = Mes.JANEIRO;
4. String mensagem = (mesFeriasEscolares(mes)?" ":" nao ")
5. + "eh mes de ferias escolares";
6. System.out.println(mes + mensagem);
7. }
8. private static boolean mesFeriasEscolares(Mes mes) {
9. switch (mes) {

r
10. case DEZEMBRO:

.b
11. case JANEIRO:
12. case FEVEREIRO:
13. case JULHO:
14. return true;

m
15. default:
16. return false;
17. }

co
18. }
19.}

Código 9.6 - TesteMes.java

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 199


9.2 Imprimindo os elementos da enumeração
Todas as enumerações têm um método estático values(), que retorna um array com os elementos da
enumeração na mesma ordem em que foram declarados. Desta forma pode ser utilizado um laço for, ou mais
facilmente o enhanced for para imprimir os elementos da enumeração.

1. public class TesteImpressaoEnum {


2. public static void main(String[] args) {

r
3. Cliente c = new Cliente("Maria", "maria@gc.com.br",
4. Cliente.TipoCliente.PESSOA_FISICA);

.b
5. System.out.println("Tipos de cliente:");
6. for (Cliente.TipoCliente tipo : Cliente.TipoCliente.values()) {
7. System.out.println(tipo);
8. }

m
9. }
10.}

co
Código 9.7 - TesteImpressaoEnum.java

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 200


9.3 Adicionando atributos e métodos à enumeração
Atributos e métodos podem ser adicionados à enumeração. Como os elementos da enumeração são suas próprias
instâncias, devem ser construídos através da chamada a um construtor válido (que não pode ser declarado com
os modificadores public ou protected).

No exemplo a seguir a enumeração tem três atributos: dias, horaInicio e horaTermino. Foi definido um
construtor que inicializa estes atributos. Repare que cada elemento da enumeração foi construído passando

r
valores para este construtor.

.b
1. public enum Periodo{
2. DIURNO_INTEGRAL ("Seg a Sex", 10, 18),
3. DIURNO_MATUTINO ("Seg a Sex", 8,12),

m
4. NOTURNO ("Seg a Sex", 19, 23);
5.
6. private String dias;
7. private int horaInicio;

co
8. private int horaTermino;
9.
10. Periodo (String dias, int horaInicio, int horaTermino){
11. this.dias = dias;
12. this.horaInicio = horaInicio;
13.
14.
15.
}
this.horaTermino = horaTermino;

public String getDias() { return dias; }


g.
in
16. public int getHoraInicio() { return horaInicio;}
17. public int getHoraTermino() { return horaTermino;}
18. public int getTotalPeriodo(){ return horaTermino - horaInicio;}
19.}
nn

Código 9.8 - Periodo.java


ai

1. public class Turma {


2. private String curso;
3. private Periodo periodo;
.tr

4. public Turma(String curso, Periodo periodo){


5. this.setCurso(curso);
6. this.setPeriodo(periodo);
7. }
w

8. public String getCurso() { return curso; }


9. public void setCurso(String curso) { this.curso = curso; }
10. public Periodo getPeriodo() { return periodo; }
w

11. public void setPeriodo(Periodo periodo) { this.periodo = periodo;}


12.}
Código 9.9 - Turma.java
w

Trainning Education Services - Todos os direitos reservados 201


A classe a seguir utiliza a classe Turma, e consequentemente sua enumeração Periodo. Veja que os métodos
da enumeração podem ser chamados sobre cada elemento da enumeração, neste caso DIURNO_INTEGRAL,
DIURNO_MATUTINO ou NOTURNO.

1. public class TesteTurma {


2. public static void main(String[] args) {
3. Turma t = new Turma("Academia do Java", Periodo.DIURNO_INTEGRAL);
4. System.out.println("\t- Curso : " + t.getCurso());
5. System.out.println("\t- Hora inicio:"+t.getPeriodo().getHoraInicio());

r
6. System.out.println("\t- Hora termino:"

.b
7. + t.getPeriodo().getHoraTermino());
8. }
9.}

m
Código 9.10 - TesteTurma.java

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 202


9.4 Representando enumerações na UML
Não existe um símbolo específico para representação de enumerações no diagrama de classes da
UML. Uma possibilidade é utilizar a representação padrão de classe marcada com o estereótipo
<<enumeration>>. Estereótipos são textos contendo uma ou mais palavras entre << e >> e representam um
mecanismo de extensão da linguagem UML. Os valores da enumeração são representados como atributos
estáticos.

r
.b
m
co
g.
in
Diagrama 9.1 - enumeração Periodo
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 203


9.5 Certificação Oracle Certified Java Programmer (OCJP)
1. Given the following code:

1:enum Animal {
2: DOG("walk"), BIRD("fly"), FISH("swim");
3: String movement;
4: Animal(String s) {
5: movement = s;
6: }
7:}

r
8:
9:public class TestEnum {

.b
10: static Animal animal;
11: public static void main(String[] args) {
12: System.out.println(animal.DOG.movement + " " + animal.FISH.movement);

m
13: }
14:}

What is the result of compiling and running the code? (choose 1 answer)

co
A) walk swim
B) Multiple compilation errors
C) Compilation fails due to an error on line 2
D) Compilation fails due to an error on line 3
E) Compilation fails due to an error on line 4
g.
in
F) Compilation fails due to an error on line 12

2. Given the following code:


nn

1. enum FooEnum {
2. FOO_VALUE
3.}
4.class Foo {
ai

5. enum BarEnum {
6. BAR_VALUE
7. }
.tr

8. void method() {
9. enum BazEnum {
10. BAZ_VALUE
11. }
w

12. }
13.}
w

Which statements are true? (select the correct answer)


A) The code compiles.
w

B) If the enumeration FooEnum is removed the code compiles.


C) If the enumeration BarEnum is removed the code compiles.
D) If the enumeration BazEnum is removed the code compiles.

Trainning Education Services - Todos os direitos reservados 204


CAPÍTULO

10

r
.b
m
co
g.
in
nn
ai

Classes abstratas e interfaces


.tr

Modificador abstract
w

Interfaces
w
w

Trainning Education Services - Todos os direitos reservados 205


10 Classes abstratas e interfaces
Um dos objetivos almejados no desenvolvimento de sistemas de software é o reaproveitamento de código já
escrito. Não é interessante, nem eficiente escrever o mesmo código diversas vezes. O paradigma de orientação a
objetos oferece diversos mecanismos que auxiliam neste objetivo.

Um destes mecanismos é a herança, que foi estudada no capítulo anterior. Através da herança, é possível
reaproveitar atributos e métodos escritos para superclasses nas subclasses. Nos exemplos de herança vistos até

r
agora, a superclasse contém um código completo e pronto para ser utilizado, independente da existência de

.b
subclasses: a classe Pessoa, por exemplo, pode ser utilizada em vários sistemas de software, mas em outros
sistemas, talvez fosse necessário utilizar uma classe mais específica, como Funcionário.

m
Existem cenários, porém, nos quais apenas parte das funcionalidades são descritas na superclasse. Neste caso
ela funciona como um modelo que deve ser completado pela subclasse. Em outros cenários, é necessário

co
somente criar um contrato de alto nível para interação entre aplicativos, definindo apenas nomes de métodos,
listas de parâmetros e valores de retorno desejados, mas sem especificar os detalhes da implementação. Para
suportar estes cenários utiliza-se elementos denominados classes abstratas e interfaces, que serão descritos a
seguir. g.
in
10.1 Modificador abstract
O modificador abstract pode ser utilizado para classes e métodos.
nn

10.1.1 Classes abstratas


O modificador abstract é usado para indicar que uma classe não está pronta para ser utilizada e não pode ser
ai

instanciada, mas apenas estendida.


.tr

Sintaxe para declaração de classes abstratas


*abstract class nomeDaClasse {}
w

*o modificador abstract pode ser combinado com outros modificadores, em qualquer ordem
w
w

Trainning Education Services - Todos os direitos reservados 207


Importante
• Uma classe pode ser declarada como abstract sem conter nenhum método
abstrato, indicando apenas que ela não poderá ser instanciada.
• Uma classe abstrata pode conter métodos não abstratos.
• Se a classe contiver pelo menos um método abstrato, será obrigatoriamente
declarada como abstract.

Veja a seguir um exemplo simples de classe abstrata:

r
.b
1. public abstract class FormatadorRecibo {
2.
3. private String nomeEmpresa;
4.

m
5. public void setNomeEmpresa(String nomeEmpresa) {
6. this.nomeEmpresa = nomeEmpresa;
7. }

co
8.
9. public String getNomeEmpresa() {
10. return this.nomeEmpresa;
11. }
12.
13. public String gerarRecibo(String nomeCliente, double valor,
14.
15.
16. }
String data, String motivo) {
return "método em construção...";
g.
in
17.}

Código 10.1 - FormatadorRecibo.java


nn

Na classe TesteRecibo tentou-se criar uma instância da classe FormatadorRecibo que resultou em um erro
na compilação, indicando que a classe é abstrata e não pode ser instanciada.
ai

1. public class TesteRecibo {


2. public static void main(String[] args) {
3. FormatadorRecibo fr = new FormatadorRecibo();
.tr

4. fr.setNomeEmpresa("Rain microsystems do Brasil");


5. String texto = fr.gerarRecibo("William Gates", 2000.0, "11/04/2004",
6. "Aluguel de Servidores");
7. }
w

8.}

Código 10.2 - TesteRecibo.java


w
w

Trainning Education Services - Todos os direitos reservados 208


r
Como a classe FormatadorRecibo não poderá ser instanciada diretamente, será necessário criar uma

.b
subclasse que a estenda, ou seja, a classe FormatadorRecibo serve como um padrão para outras classes.

m
Veja o exemplo da classe FormatadorModeloA, que estende a classe FormatadorRecibo e sobrescreve seu
método gerarRecibo:

co
1. public class FormatadorModeloA extends FormatadorRecibo {
2.
3. public String gerarRecibo(String nomeCliente, double valor,
4.
5.
6.
7.
String data, String motivo) {

return "Nos da " + super.getNomeEmpresa() +


" recebemos de " + nomeCliente +
g.
in
8. " em " + data +
9. " o valor de R$ " + valor +
10. " referente a " + motivo;
nn

11.
12. }
13.}

Código 10.3 - FormatadorModeloA.java


ai

1. public class TesteReciboModeloA {


2.
3. public static void main(String[] args) {
.tr

4.
5. FormatadorModeloA fA = new FormatadorModeloA();
6. fA.setNomeEmpresa("Rain microsystems do Brasil");
7. String texto = fA.gerarRecibo("William Gates", 2000, "11/04/2004",
w

8. "Aluguel de Servidores");
9. System.out.println(texto);
10. }
w

11.}

Código 10.4 - TesteReciboModeloA.java


w

Trainning Education Services - Todos os direitos reservados 209


r
Até aqui verificou-se que não é possível instanciar classes marcadas com o modificador abstract. Na prática

.b
uma classe abstrata serve para acomodar métodos abstratos, como será visto a seguir.

10.1.2 Métodos Abstratos

m
O desenvolvedor de software freqüentemente se depara com a máxima universal: “existe mais de uma forma de
resolver um problema”. Muitas vezes uma rotina de software pode ser escrita de várias formas para atingir um

co
mesmo resultado.
• utilizando racionalmente a memória em um ambiente restrito;
• ou, minimizando as operações de I/O em um ambiente de resposta rápida;


g.
ou, visando a simplicidade e a clareza do código fonte para manutenções freqüentes;
ou, utilizando bibliotecas ou APIs para integrar com outros sistemas corporativos;
in
• etc.
nn

A orientação a objetos facilita a convivência com esses dilemas do desenvolvimento de software com o conceito
de métodos abstratos.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 210


Um método abstrato é utilizado em uma classe quando o desenvolvedor ou o projetista de software percebe que:
• é possível implementar um método de várias maneiras interessantes;
• e/ou ainda não existem requisitos bem definidos para decidir por uma implementação de método.

Um método abstrato define um ponto de diversificação, indicando que mais de uma solução técnica pode ser
adotada.

Podem existir métodos abstratos somente dentro de classes abstratas. Isso fará com que estes métodos tenham

r
de ser obrigatoriamente implementados nas subclasses não-abstratas. Um método abstrato tem a seguinte

.b
semântica:

• declara-se apenas a sua estrutura (tipo de retorno, nome, parâmetros de entrada e exceções)

m
incluindo o modificador abstract;
• não se declara corpo de instruções;

co
• finaliza-se a declaração com ponto e virgula (;).

Sintaxe para declaração de métodos abstratos


g.
* abstract <tipo do retorno> nomeDoMetodo (<parametrosDeMetodos>);
in
*o modificador abstract pode ser combinado com outros modificadores, em qualquer ordem
nn

Métodos abstratos são utilizados para definir contratos de comportamento, garantindo que serão implementados
nas classes filhas.
ai

Importante
.tr

• Sempre que se declara um método como abstract, a classe também deverá


ser declarada como abstract.

w

Todas as classes filhas deverão obrigatoriamente implementar os métodos


abstratos, ou então, serem declaradas como abstratas.
w
w

Trainning Education Services - Todos os direitos reservados 211


Veja novamente o exemplo da classe abstrata FormatadorRecibo declarando o método gerarRecibo()
como abstrato:

1. public abstract class FormatadorRecibo {


2.
3. private String nomeEmpresa;
4.
5. public void setNomeEmpresa(String nomeEmpresa) {
6. this.nomeEmpresa = nomeEmpresa;
7. }
8.

r
9. public String getNomeEmpresa() {
10. return this.nomeEmpresa;

.b
11. }
12.
13. public abstract String gerarRecibo(String nomeCliente, double valor,
14. String data, String motivo);

m
15.
16.}

co
Código 10.5 - FormatadorRecibo com método abstrato

Agora, todas as subclasses não-abstratas serão obrigadas a implementar o método gerarRecibo. Na classe

g.
FormatadorModeloB, a seguir, não está implementado o método gerarRecibo e, por isso,ocorrerá um erro de
compilação.
in
1. public class FormatadorModeloB extends FormatadorRecibo {
2.
3. private String simboloMoeda;
4.
nn

5. public String getSimboloMoeda() { return simboloMoeda; }


6.
7. public void setSimboloMoeda(String simboloMoeda) {
8. this.simboloMoeda = simboloMoeda;
9. }
ai

10.}

Código 10.6 - FormatadorModeloB.java incorreto


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 212


Como diz a própria mensagem do compilador, para corrigir este erro será necessário implementar o método
gerarRecibo com a assinatura correta ou definir a classe FormatadorModeloB como abstract, indicando
que a classe também não está pronta para ser utilizada, e que não poderá ser instanciada.

Veja agora a classe FormatadorModeloB,corrigida, implementando o método gerarRecibo.

1. public class FormatadorModeloB extends FormatadorRecibo {


2.

r
3. private String simboloMoeda;
4.

.b
5. public String getSimboloMoeda() {
6. return simboloMoeda;
7. }

m
8.
9. public void setSimboloMoeda(String simboloMoeda) {
10. this.simboloMoeda = simboloMoeda;
11. }

co
12.
13. public String gerarRecibo(String nomeCliente, double valor,
14. String data, String motivo) {
15. return "Recebemos de " + nomeCliente +
16. " o valor de " + this.getSimboloMoeda() + " " + valor +
17.
18.
19. }
20.}
" referente a " + motivo + ". \n" +
super.getNomeEmpresa() + ", " + data;
g.
in
Código 10.7 - FormatadorModeloB.java corrigido
nn

Repare que o método gerarRecibo de FormatadorModeloB sobrescreve o método abstrato de


FormatadorRecibo (mesmo retorno, nome e parâmetros de entrada).
ai

Veja agora o código da classe de teste:

1. public class TesteReciboModeloB {


.tr

2. public static void main(String[] args) {


3.
4. FormatadorModeloB fB = new FormatadorModeloB();
5. fB.setNomeEmpresa("Coffe & Milk");
w

6. fB.setSimboloMoeda("Euro$");
7. String texto = fB.gerarRecibo("Serafim da Silva", 4, "16/09/2004",
8. "cafe com bolinhos");
w

9. System.out.println(texto);
10. }
11.}
w

Código 10.8 - TesteReciboModeloB.java

Trainning Education Services - Todos os direitos reservados 213


r
10.1.3 Representando o modificador abstract em UML

.b
Classes abstratas

m
Classes abstratas são representadas na UML com seus nomes escritos em itálico, como se vê no
exemplo da classe FormatadorRecibo .

co
Métodos abstratos
Métodos abstratos também são representados escritos em itálico.

g.
in
nn
ai
.tr
w
w
w

Diagrama 10.1 - representação de classes e métodos abstratos

Trainning Education Services - Todos os direitos reservados 214


10.1.4 Erros comuns
1. Declarar métodos abstratos e não declarar a classe como abstrata.
Veja o exemplo da classe FormatadorRecibo abaixo, sem o modificador abstract na
declaração da classe:

1. public class FormatadorRecibo {

r
2.
3. private String nomeEmpresa;

.b
4.
5. public void setNomeEmpresa(String nomeEmpresa) {
6. this.nomeEmpresa = nomeEmpresa;
7. }

m
8.
9. public String getNomeEmpresa() {
10. return this.nomeEmpresa;

co
11. }
12.
13. public abstract String gerarRecibo(String nomeCliente, double valor,
14. String data, String motivo);
15.
16.} g.
Código 10.9 - FormatadorRecibo.java sem o uso do modificador abstract na declaração da classe
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 215


2. Declarar métodos abstratos com a implementação vazia, em vez de terminados com
ponto e vírgula (;). Veja o exemplo a seguir para a classe FormatadorRecibo:

1. public abstract class FormatadorRecibo {


2.
3. private String nomeEmpresa;
4.

r
5. public void setNomeEmpresa(String nomeEmpresa) {
6. this.nomeEmpresa = nomeEmpresa;

.b
7. }
8.
9. public String getNomeEmpresa() {

m
10. return this.nomeEmpresa;
11. }
12.
13. public abstract String gerarRecibo(String nomeCliente, double valor,

co
14. String data, String motivo) {}
15.
16.}

Código 10.10 - FormatadorRecibo.java com método abstrato incorreto


g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 216


3. Implementar o método na subclasse sem respeitar a assinatura definida na
superclasse. Veja o exemplo com a classe FormatadorModeloC:

1. public class FormatadorModeloC extends FormatadorRecibo {


2.
3. //A ordem dos parâmetros nomeCliente e valor está invertida
4. public String gerarRecibo(double valor, String nomeCliente,

r
5. String data, String motivo) {

.b
6.
7. return "Nós da " + super.getNomeEmpresa() +
8. " recebemos de " + nomeCliente +
9. " em " + data +

m
10. " o valor de R$ " + valor +
11. " referente a " + motivo;
12. }
13.}

co
Código 10.11 - FormatadorModeloC.java

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 217


10.2 Interfaces
Antes de discutir o conceito de interfaces em Java é interessante pensar sobre o conceito de interface fora do
Java:

1) O que representa a interface do Windows?


A interface desse sistema operacional representa o que pode ser visto e como é possível interagir com o Sistema
Operacional, através de seus botões, menus, ícones, etc.

r
.b
2) Para que serve a interface USB?
Através de um padrão estabelecido diversos dispositivos podem ser conectados via USB. Na prática, o USB define

m
uma forma de conectar e expandir a capacidade de um computador. De um lado, há a indústria que definiu um
padrão e o publicou; de outro, fabricantes que estudaram os padrões e desenvolveram dispositivos que podem se
comunicar via USB.

co
g.
in
nn
ai
.tr

Figura 10.1 - interfaces


w

De uma forma geral, as interfaces definem um contrato para comunicação entre dois elementos ( usuário e
sistema operacional, computador e periféricos, etc).
w
w

Trainning Education Services - Todos os direitos reservados 220


10.2.1 Interfaces em Java
No caso do Java, o objetivo das interfaces é estabelecer um contrato para comunicação entre elementos de
software, mais especificamente, entre classes.

Um exemplo comum é a comunicação entre um aplicativo Java e um banco de dados. No aplicativo existem
classes responsáveis por interagir com o banco, e esta comunicação é feita através de um driver que contém os
comandos e funcionalidades oferecidas pelo banco ao aplicativo. Apesar de cada banco poder oferecer
funcionalidades diferentes, existe um conjunto mínimo comum a todos os bancos: um exemplo de funcionalidade

r
comum é abrir uma conexão.

.b
No entanto, como cada banco de dados possui o seu próprio driver com um conjunto diferente de comandos, o

m
código necessário para abrir uma conexão é diferente para cada banco. Desta forma para cada banco de dados
será necessário escrever um código diferente no aplicativo, de acordo com as características do driver utilizado.

co
Se for estabelecido um contrato de comunicação, ou seja, se for estabelecido um conjunto de comandos comuns
através da definição de uma interface, pode-se aproveitar o mesmo código para comunicação com bancos
diferentes.
g.
Percebendo isso, o JCP (Java Community Process) desenvolveu a API JDBC (Java DataBase Connectivity), que é
um dos exemplos de uso de interfaces.
in
Nela são definidos todos os comportamentos de infra-estrutura que devem ser implementados pelos fabricantes
nn

de banco de dados. Entre eles pode-se citar as funcionalidades para:

• obter uma conexão;


• executar um comando SQL;
ai

• fechar a conexão.
.tr

Com esta especificação em mãos, cada fabricante deverá implementar as suas classes (seguir suas regras),
usando as interfaces que compõem o JDBC. Isso garante ao desenvolvedor de aplicações uma certeza das
funcionalidades que estarão disponíveis.
w
w
w

Trainning Education Services - Todos os direitos reservados 221


r
.b
m
co
Figura 10.2 interfaces em Java

A modelagem com interfaces proporciona uma grande flexibilidade para os sistemas porque através de seu uso é
g.
possível separar totalmente a especificação da implementação, e obter soluções que podem facilmente trabalhar
com implementações diferentes da mesma interface.
in
10.2.2 Definindo uma Interface
nn

Em Java, uma interface define um contrato de comunicação entre classes. Esta comunicação ocorre através de
chamadas de métodos, então é natural imaginar que uma interface defina quais métodos devem estar presentes
em uma determinada classe. É possível definir dois elementos na comunicação entre classes: uma classe cliente,
ai

que faz as chamadas de métodos, e uma classe de implementação, que recebe as chamadas de métodos e
executa o código correspondente. Do ponto de vista da classe cliente, a interface deve definir quais os possiveis
.tr

métodos a serem chamados, e do ponto de vista da classe de implementação, a interface deve definir quais
métodos devem ser implementados.
w

Sintaxe para declaração de interfaces


<modificadores> interface nomeDaInterface {
w

//definição de constantes
//definição de métodos abstratos
w

Trainning Education Services - Todos os direitos reservados 222


A interface é um protótipo de classe, com uma estrutura semelhante a de uma classe abstrata. Uma diferença
importante é que uma classe abstrata pode definir métodos concretos e uma interface só pode definir métodos
abstratos. Isso reforça o objetivo da interface de apenas definir o comportamento (métodos) desejado em termos
de entradas (parâmetros dos métodos) e saídas (valores de retorno dos métodos), e não do código necessário
para sua implementação.

Assim como uma classe concreta que tem como superclasse uma classe abstrata é obrigada a sobrescrever os
métodos abstratos herdados, uma classe que implementa uma interface é obrigada a criar implementações para

r
os métodos da interface.

.b
Veja a seguir algumas características importantes dos membros de uma interface:

m
Métodos
Uma interface pode conter apenas métodos abstratos. No entanto, não é necessário utilizar o modificador

co
abstract, visto que, todos os métodos definidos em uma interface são abstratos por padrão.

Todos os métodos de uma interface são públicos mesmo que não seja utilizado o modificador de acesso public.
g.
Os únicos modificadores permitidos para os métodos definidos nas interfaces são: public e abstract.
in
Atributos
Uma interface pode conter apenas atributos públicos, e explicitamente inicializados, não havendo nenhuma
nn

restrição para utilização do modificador static ou final.

Todos os atributos de uma interface são final (constantes) e static por default, mesmo quando não
ai

explicitamente declarados.

Veja a seguir um exemplo de interface:


.tr

1. public interface Transportavel {


2.
w

3. public static final String UNIDADE_VOLUME = "cm3";


4. public String UNIDADE_PESO = "kg";
5.
w

6. public double getVolume();


7. public double getPeso();
8. public int getEmpilhamentoMaximo();
9.}
w

Código 10.12 - Transportavel.java

Trainning Education Services - Todos os direitos reservados 223


Interfaces devem ser definidas em arquivos com o mesmo nome da interface declarada, com a extensão .java.
Serão compiladas para geração do arquivo .class, identicamente às classes convencionais.

Não é possível criar instâncias de interfaces seguindo o mesmo conceito de classes abstratas.

A abstração (análise focada) também é importante ao projetar uma interface. No exemplo a

r
interface Trasportavel foi projetada para um sistema de logística.

.b
Uma prática é usar, quando possível, um adjetivo como nome de uma interface – como, entre
outras: Transportavel, Tributavel, Vendavel, Rastreavel, Perecivel.

m
10.2.3 Implementando uma Interface

co
Para implementar uma interface em uma classe utiliza-se a instrução implements, sendo obrigatório
implementar todos os métodos definidos pela interface, e respeitar a assinatura dos métodos.

Sintaxe para implementação de interfaces


<modificadores> class nomeDaClasse implements nomeDaInterface { }
g.
in
A classe Mobilia, apresentada, a seguir, implementa a interface Transportavel, e por isso implementa todos
os seus métodos:
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 224


1. public class Mobilia implements Transportavel {
2.
3. private String tipo;
4. private String fabricante;
5. private String material;
6. private double altura, largura, profundidade;
7. private double peso;
8.
9. public Mobilia(String tipo, String fabricante, String material,
10. double alt, double larg, double prof, double peso ) {
11. this.tipo = tipo;

r
12. this.fabricante = fabricante;
13. this.material = material;

.b
14. this.altura = alt;
15. this.largura = larg;
16. this.profundidade = prof;

m
17. this.peso = peso;
18. }
19.
20. // Implementação obrigatória dos métodos da interface

co
21.
22. public double getVolume() {
23. double vol = this.altura * this.largura * this.profundidade;
24. return vol;
25. }
26.
27. public double getPeso() {
28.
29. }
return this.peso;
g.
in
30.
31. public int getEmpilhamentoMaximo() {
32. return 2;
nn

33. }
34.
35. // getters & setters para demais atributos
36.
37. public double getAltura() { return altura; }
ai

38. public void setAltura(double altura) { this.altura = altura; }


39. public String getFabricante() { return fabricante; }
40. public void setFabricante(String fabricante) { this.fabricante = fabricante; }
41. public double getLargura() { return largura; }
.tr

42. public void setLargura(double largura) { this.largura = largura; }


43. public String getMaterial() { return material; }
44. public void setMaterial(String material) { this.material = material; }
45. public double getProfundidade() { return profundidade; }
w

46. public void setProfundidade(double prof) { this.profundidade = prof; }


47. public String getTipo() { return tipo; }
48. public void setTipo(String tipo) { this.tipo = tipo; }
w

49. public void setPeso(double peso) { this.peso = peso; }


50.}
w

Código 10.13 - Mobilia.java implementando a interface Transportavel

Trainning Education Services - Todos os direitos reservados 225


Imagine que muitas outras classes poderiam implementar esta interface, pois existem muitas coisas transportáveis
que são possíveis de modelar, como por exemplo: equipamentos eletrônicos, pessoas, roupas, animais, CDs,
DVDs, alimentos, etc.

É possível implementar mais do que uma interface em cada classe. A interface Perecivel define métodos para
capturar a temperatura de conservação e a quantidade de dias de validade. A classe AlimentoBase deverá ser
adaptada às interfaces Transportavel e Perecivel. A subclasse Alimento será empregada com um
adaptador, para assumir as características das interfaces.

r
.b
1. public interface Perecivel {
2. public int getTemperaturaDeConservacao();
3. public int getDiasDeValidade();

m
4.}

Código 10.14 - Perecivel.java

co
1. public abstract class AlimentoBase {
2.
3. private String nome;
4. private int temperatura;
5. private double volumeCm3;
6. private int pesoGramas;
g.
in
7.
8. public AlimentoBase(String nome, int temperatura, int gramas, double cm3) {
9. this.nome = nome;
10. this.temperatura = temperatura;
nn

11. this.pesoGramas = gramas;


12. this.volumeCm3 = cm3;
13. }
14.
15. public String getNome() { return nome; }
ai

16. public void setNome(String nome) { this.nome = nome; }


17. public int getPesoGramas() { return pesoGramas; }
18. public void setPesoGramas(int pesoGramas) { this.pesoGramas = pesoGramas; }
.tr

19. public int getTemperatura() { return temperatura; }


20. public void setTemperatura(int temperatura) {this.temperatura = temperatura; }
21. public double getVolumeCm3() { return volumeCm3; }
22. public void setVolumeCm3(double volumeCm3) { this.volumeCm3 = volumeCm3; }
w

23.}

Codigo 10.15 - AlimentoBase.java (não implementa nenhuma interface)


w
w

Trainning Education Services - Todos os direitos reservados 226


1. public class Alimento extends AlimentoBase implements Transportavel, Perecivel {
2.
3. private int empilhamentoMaximo;
4. private int diasDeValidade;
5.
6. public Alimento(String nome, int temperatura, int gramas,
7. double cm3, int empilhamento, int validade) {
8. super(nome, temperatura, gramas, cm3);
9. this.empilhamentoMaximo = empilhamento;
10. this.diasDeValidade = validade;
11. }

r
12.
13. public double getVolume() {

.b
14. return super.getVolumeCm3();
15. }
16.
17. public double getPeso() {

m
18. return super.getPesoGramas()/1000;
19. }
20.

co
21. public int getEmpilhamentoMaximo() {
22. return this.empilhamentoMaximo;
23. }
24.
25. public int getTemperaturaDeConservacao() {
26.
27. }
28.
return super.getTemperatura();

29. public int getDiasDeValidade() {


g.
in
30. return this.diasDeValidade;
31. }
32.}
nn

Código 10.16 - Alimento.java implementando as interfaces Transportavel e Perecivel


ai

Criou-se a classe TesteInterface para testar a utilização das classe Mobilia e Alimento e, em
conseqüência, para testar a utilização das interfaces Transportavel e Perecivel.
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 227


1. public class TesteInterface {
2. public static void main(String[] args) {
3.
4. Mobilia mob = new Mobilia("mesa","Moveis Silva","madeira/formica/metal",
5. 115, 70, 90, 11);
6. System.out.println("Mobilia: " + mob.getTipo());
7. System.out.println("volume: " + mob.getVolume()
8. + Transportavel.UNIDADE_VOLUME);
9. System.out.println("peso: " + mob.getPeso()+Transportavel.UNIDADE_PESO);
10. System.out.println("empilhamento max: " + mob.getEmpilhamentoMaximo());
11. System.out.println();

r
12.

.b
13. Alimento junk = new Alimento("hamburguer", -2, 350, 260d, 6, 30);
14. System.out.println("Alimento: " + junk.getNome());
15. System.out.println("volume: " + junk.getVolume()
16. + Transportavel.UNIDADE_VOLUME);

m
17. System.out.println("peso: "+junk.getPeso()+ Transportavel.UNIDADE_PESO);
18. System.out.println("empilhamento max: " + junk.getEmpilhamentoMaximo());
19. System.out.println("conservacao: " + junk.getTemperaturaDeConservacao()
20. + "C");

co
21. System.out.println("dias de validade: " + junk.getDiasDeValidade());
22. }
23.}

g.
Código 10.17 - TesteInterface.java
in
nn
ai
.tr
w

Uma classe abstrata pode implementar uma interface sem implementar todos os seus
métodos, pois já foi visto que uma classe abstrata pode possuir métodos abstratos. Os
w

métodos da interface não implementados pela classe abstrata serão considerados como
abstratos. Qualquer classe não-abstrata que estenda a classe abstrata terá que implementar
w

todos os métodos “pendentes”.

Trainning Education Services - Todos os direitos reservados 228


10.2.4 Estendendo uma Interface
Uma interface pode ser estendida por outras, fazendo com que a interface filha herde todos os métodos definidos
pela super-interface, ou seja, as classes que implementarem a interface filha terão que implementar todos os
métodos definidos nas duas interfaces.

Quando se quer especificar uma nova categoria de classes, que é um subconjunto das classes definidas pela
super-interface, utiliza-se herança de interface.

r
.b
No exemplo utilizado, tendo em vista um sistema de logística, será criada a interface Inflamavel, a partir de
Transportavel,. Desta forma, fica garantido que todas as classes que implementarem a interface Inflamavel

m
obrigatoriamente irão implementar a interface Transportavel, assumindo as características de transporte.

co
1. public interface Inflamavel extends Transportavel {
2. public int getTemperaturaMaxima();
3.}

Código 10.18 - Inflamavel.java


g.
A classe GalaoDeCombustivel terá que implementar os métodos definidos na interface Transportavel assim
in
como os métodos da interface Inflamavel. É importante garantir que, conceitualmente, a classe que implementa
a interface realmente seja Inflamavel e Transportavel.
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 229


1. public class GalaoDeCombustivel implements Inflamavel {
2.
3. private String nomeCombustivel;
4. private double densidade; // em g/cm3
5. private int temperaturaDeTransporte;
6.
7. public GalaoDeCombustivel(String nomeCombustivel, double densidade,
8. int tempTransporte) {
9. this.nomeCombustivel = nomeCombustivel;
10. this.densidade = densidade;

r
11. this.temperaturaDeTransporte = tempTransporte;

.b
12. }
13.
14. public int getTemperaturaMaxima() {
15. return (int) (temperaturaDeTransporte * 1.4d);

m
16. }
17.
18. public double getVolume() { return 3785; } // 1 galao = 3.785 L
19.

co
20. public double getPeso() {
21. double pesoGramas = getVolume() * densidade;
22. return pesoGramas / 1000;
23. }
24.
25. public int getEmpilhamentoMaximo() { return 3; }
26.
27. public String getNomeCombustivel() { return nomeCombustivel; }
g.
in
28. public double getDensidade() { return densidade; }
29. public int getTemperaturaDeTransporte() { return temperaturaDeTransporte; }
30.
31.}
nn

Código 10.19 - GalaoDeCombustivel.java


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 230


10.2.5 Representando interfaces na UML

A interface pode ser representada de duas formas na UML:

• a primeira forma é com a figura de um círculo com o respectivo nome abaixo deste símbolo. Nesse caso
representa-se a implementação de interface com uma linha ligando a classe, mas não é possível a
representação de atributos e métodos;

r
.b
m
co
Diagrama 10.2 - representação simplificada de interfaces


g.
a segunda maneira, mais usual, é através do estereótipo <<interface>>. Estereótipos são textos
contendo uma ou mais palavras entre << e >> e representam um mecanismo de extensão da linguagem
in
UML. Nesse caso, a representação da implementação deve ser feita utilizando uma seta pontilhada
ligando a classe e a interface.
nn
ai
.tr
w
w
w

Diagrama 10.3 - representação completa de interface

Trainning Education Services - Todos os direitos reservados 231


Dessa forma, é possível representar os atributos e métodos definidos na interface.

Herança de interfaces é representada com o mesmo símbolo utilizado para representação de herança de classes
concretas, isto é, com uma seta contínua partindo da interface pai até a sub-interfaces.

r
.b
m
co
g.
in
Diagrama 10.4 - herança entre interfaces
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 232


10.2.6 Interface vs. Abstract

É uma boa prática de modelagem de classes trabalhar sempre no sentido do mais abstrato para mais concreto, do
genérico para o específico e assim por diante. Para organizar melhor essa prática, veja alguns recursos:

• interface - tudo é abstrato, separação total de definição e implementação;


• classes abstratas - parte concreto, parte abstrato;
• classes concretas - tudo concreto;

r
• classes final - definição completa de um objeto.

.b
Diagrama de abstração / concretização

m
Classe final

co
- Classe concreta que,não
pode ser estendida
Classe abstrata - Maior nível de
- Parte abstrata especialização
- Parte completa - Definição completa
g.
in
Interface Classe concr eta
nn

- Genérico - Classe pronta para ser


- Especificação (abstrata) usada.
- Maior nível de abstração - Concretização de classe
abstrata ou interface.
- Reflete um objeto do
mundo real.
ai

- Pode ser extendida.


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 233


10.2.7 Erros comuns

1. Método não implementado.


Veja no próximo exemplo que a classe Mobilia não implementa o método getVolume
definido na interface Transportável:

r
1. public class Mobilia implements Transportavel {

.b
2.
3. private String tipo, fabricante, material;
4. private double altura, largura, profundidade, peso;
5.

m
6. public Mobilia(String tipo, String fabricante, String material,
7. double alt, double larg, double prof, double peso ) {
8. this.tipo = tipo;
9. this.fabricante = fabricante;

co
10. this.material = material;
11. this.altura = alt;
12. this.largura = larg;
13. this.profundidade = prof;
14.
15. }
16.
this.peso = peso;

17. public int getEmpilhamentoMaximo() {


g.
in
18. return 2;
19. }
20.
21. //getters e setters
nn

22. public double getPeso() { return this.peso; }


23. public void setPeso(double peso) { this.peso = peso; }
24. public String getTipo() { return tipo; }
25. public void setTipo(String tipo) { this.tipo = tipo; }
26. public String getFabricante() { return fabricante; }
ai

27. public void setFabricante(String fabricante) { this.fabricante = fabricante; }


28. public String getMaterial() { return material; }
29. public void setMaterial(String material) { this.material = material; }
.tr

30. public double getAltura() { return altura; }


31. public void setAltura(double altura) { this.altura = altura; }
32. public double getLargura() { return largura; }
33. public void setLargura(double largura) { this.largura = largura; }
w

34. public double getProfundidade() { return profundidade; }


35. public void setProfundidade(double profundidade) {
36. this.profundidade = profundidade;
w

37. }
38.}
w

Código 10.20 - Mobilia.java faltando a implementação do método getVolume

Trainning Education Services - Todos os direitos reservados 234


2. Ausência do modificador public na implementação do método (modificador com
menor acessibilidade).
É importante lembrar que todos os métodos definidos numa interface são
públicos. Não é possivel restringir a acessibilidade numa sobrescrita de métodos
e todas as implementações de métodos de interfaces também devem ser públicas. Veja abaixo
onde não foi colocado o modificador public no método getDiasDeValidade, definido pela
interface Perecivel e implementado pela classe Alimento.

r
1. public class Alimento extends AlimentoBase implements Transportavel, Perecivel {

.b
2.
3. private int empilhamentoMaximo;
4. private int diasDeValidade;
5.

m
6. public Alimento(String nome, int temperatura, int gramas,
7. double cm3, int empilhamento, int validade) {
8. super(nome, temperatura, gramas, cm3);
9. this.empilhamentoMaximo = empilhamento;

co
10. this.diasDeValidade = validade;
11. }
12. public double getVolume() {
13. return super.getVolumeCm3();
14. }
15. public double getPeso() {
16.
17. }
return super.getPesoGramas()/1000;
g.
in
18. public int getEmpilhamentoMaximo() {
19. return this.empilhamentoMaximo;
20. }
21. public int getTemperaturaDeConservacao() {
nn

22. return super.getTemperatura();


23. }
24.
25. int getDiasDeValidade() {
26. return this.diasDeValidade;
ai

27. }
28.}
.tr

Código 10.21 - Alimento.java sem o modificador public no método getDiasDeValidade


w
w
w

Trainning Education Services - Todos os direitos reservados 236


3. Instanciação de interface.
Veja um exemplo na classe TesteInterface, da tentativa de criar uma instância de Perecivel.

1. public class TesteInterface {


2. public static void main(String[] args) {

r
3. Perecivel perecivel = new Perecivel();
4. }

.b
5.}

Código 10.22 - TesteInterface.java instanciando interface

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 237


4. Terminar a definição do método com {} ao invés de ;
Veja o exemplo para a interface Perecivel modificada para exibir o erro. Note que este é
um erro de criação incorreta de método abstrato:

1. public interface Perecivel {

r
2. public int getTemperaturaDeConservacao() {}

.b
3. public int getDiasDeValidade();
4.}

Código 10.23 - Perecivel.java com definição de método não abstrato

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 238


10.3 Certificação Oracle Certified Java Programmer (OCJP)

1. Which of the following statements are true? (Select 2 answers)

A) An interface cannot contain variables


B) Interfaces cannot have constructors
C) A class may either extend one other class or implement interfaces, but it can't do both,

r
D) A class may implement many interfaces.

.b
2. What is the result of compiling the following classes:

m
1. class Foo {

co
2. void foo() {
3. System.out.println("Inside foo method");
4. }
5. }
6.
7. abstract class Bar extends Foo {
8.
9. }
10.
abstract void bar();
g.
in
11.abstract class Baz extends Bar {
12.}
13.
nn

14.class Xyz extends Baz {


15. void bar() {
16. System.out.println("Inside overriden bar method");
17. }
18.}
ai
.tr

A) Compilation error: an abstract class cannot extend a concrete class


B) Compilation error: an abstract class cannot extend another abstract class
C) Compilation error: an abstract class must define at least one abstract method
w

D) Compiles without error.


w
w

Trainning Education Services - Todos os direitos reservados 241


CAPÍTULO

11

r
.b
m
co
g.
in
nn
ai

Polimorfismo
.tr

Cast de objetos
w

Polimorfismo
Tipos de retorno covariantes e polimorfismo
w

Acoplamento e polimorfismo
w

Trainning Education Services - Todos os direitos reservados 243


11 Polimorfismo
Um dos recursos mais poderosos da orientação a objetos é o polimorfismo, particularmente em sua forma
denominada vinculação dinâmica (dynamic binding). É através dele que se consegue a verdadeira flexibilidade no
desenvolvimento de sistemas de software. No capítulo anterior foram apresentados os conceitos de classes
abstratas e interfaces, permitindo a programação baseada em modelos de classes e contratos. O polimorfismo é
fortemente baseado nestes conceitos.

r
Antes de apresentar o conceito de polimorfismo é importante entender como ocorre em Java a conversão de tipos

.b
entre objetos ou cast de objetos.

11.1 Cast de objetos

m
Em algumas condições, é necessário mudar a forma de operar e "visualizar" um objeto. Nestas situações

co
emprega-se as operações de cast para trabalhar com o objeto, utilizando parte ou todos seus métodos e atributos.

Relembre o cast de primitivos:


short s = 4096; g.
float f = s; // cast up, foram copiados os 16 bits da variável s para os 32 bits de um float
int i = 123; // 32 bits
in
byte b = (byte) i; // cast down : foram copiados os 8 bits menos significativos de i para os 8 bits de um byte
nn

A operação de cast de objetos é semelhante à operação de cast de tipos primitivos, mas com uma diferença
fundamental: os objetos por trás das variáveis não são copiados ou truncados; no máximo, as características e
funcionalidades estarão apenas ocultas, podendo ser restituídas posteriormente.
ai

Para entender estas operações visualise a estrutura hierárquica das seguintes classes:
.tr
w
w
w

Diagrama 11.1 - Hierarquia de classes

Trainning Education Services - Todos os direitos reservados 245


É possível fazer cast de classes desde que estejam em uma mesma hierarquia, mas nunca entre classes "irmãs",
tal como Funcionario e Cliente.

Vale reforçar que cast não representa uma mudança estrutural do objeto, mas tão somente uma mudança no tipo
de variável reference que está apontando para o objeto na memória. Imagine por exemplo que um objeto em
memória seja como uma televisão e a referência para o objeto representa o controle remoto. Mesmo que uma TV
tenha 70 funções diferentes, só é possivel acionar aquelas que estão disponíveis no controle remoto. Utilizando-se
um controle genérico que serve para vários tipos de aparelhos,há um conjunto restrito de botões mas caso seja

r
utilizado um controle específico para o tipo e marca da TV acessa-se todas suas funções. O cast de objetos

.b
consiste na troca do controle remoto utilizado para acessar um objeto.

As classes Pessoa, Cliente e Funcionario apresentadas a seguir serão utilizadas nos exemplos de cast.

m
1. public class Pessoa {

co
2. private String nome;
3. private long rg;
4. public String getNome() {
5. return nome;
6. }
7. public void setNome(String nome) {
8.
9. }
this.nome = nome;
g.
in
10. public long getRg() {
11. return rg;
12. }
13. public void setRg(long rg) {
nn

14. this.rg = rg;


15. }
16.}

Código 11.1 - Pessoa.java


ai

1. public class Cliente extends Pessoa {


2. private String cpf;
.tr

3.
4. public String getCpf() {
5. return cpf;
6. }
w

7.
8. public void setCpf(String cpf) {
9. this.cpf = cpf;
w

10. }
11.}
w

Código 11.2 - Cliente.java

Trainning Education Services - Todos os direitos reservados 246


1. public class Funcionario extends Pessoa {
2. private String carteiraProfissional;
3. private double salario;
4.
5. public String getCarteiraProfissional() {
6. return carteiraProfissional;
7. }
8.
9. public void setCarteiraProfissional(String carteiraProfissional) {
10. this.carteiraProfissional = carteiraProfissional;

r
11. }
12.

.b
13. public double getSalario() {
14. return salario;
15. }
16.

m
17. public void setSalario(double salario) {
18. this.salario = salario;
19. }

co
20.
21. public double calculaPagamento() {
22. return salario;
23. }
24.}
g.
Código 11.3 - Funcionario.java
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 247


11.1.1 Cast up (Widening)
Com base na hierarquia apresentada, e havendo uma variável declarada e instanciada, conclui-se que:
• Cliente é uma Pessoa, e toda Pessoa é um Object.

Portanto, é possível realizar a operação de widening, visualizando um objeto da classe Cliente como Pessoa ou
Object, mas o objeto não perderá definitivamente suas características de Cliente. Seguindo a analogia
apresentada anteriormente, é possível utilizar um controle remoto de Pessoa e Object para acessar um objeto

r
do tipo Cliente, que continua sendo um Cliente independente do controle utilizado.

.b
1. public class TesteCastUp {
2.

m
3. public static void main(String[] args) {
4.
5. // O objeto c foi declarado e instanciado como Cliente

co
6. Cliente c = new Cliente();
7.
8. // Casting UP explicito do objeto da classe Cliente para classe Pessoa
9. Pessoa p = (Pessoa) c;
10.
11.
12.
13.
14.
// Casting UP do objeto da classe Cliente para classe Pessoa
Pessoa p2 = c;

// Casting UP do objeto da classe Cliente para Pessoa


g.
in
15. Pessoa p3 = new Cliente();
16.
17. // Casting UP explícito do objeto da classe Cliente para classe Object
nn

18. Object o = (Object) c;


19.
20. // Casting UP do objeto da classe Cliente para classe Object
21. Object o2 = c;
22. }
ai

23.}

Código 11.4 - TesteCastUp.java


.tr

Ao visualizar um Cliente como uma Pessoa perde-se a capacidade de manipular os métodos getCpf e
setCpf. mas ainda é possível trabalhar com os getters e setters para nome e rg.
w

Apesar da variável de manipulação ser do tipo Pessoa o objeto continua sendo um Cliente,
w

que não perdeu seu cpf.


w

Ao visualizar uma pessoa como um Object torna-se possível manipular apenas os membros (atributos e
métodos) definidos na classe Object, como toString().

Trainning Education Services - Todos os direitos reservados 248


11.1.2 Cast down (Narrowing)
A operação de cast down (narrowing) é oposta à operação de cast up (widening), isto é, em vez de generalizar
um objeto ele será especializado. Utilizando o exemplo anterior, isso corresponde a trocar um controle remoto
genérico por um controle remoto mais específico do objeto.

A generalização é uma operação mais previsível do que a especialização, porque a análise da hierarquia de
classes permite saber se a operação é ou não possível; na especialização, ao contrário, a operação irá depender
do tipo real do objeto, que, por sua vez, depende da forma como ele foi criado. O tipo real do objeto é definido pelo

r
construtor que foi chamado quando ele foi instanciado.

.b
Então, se um objeto é criado e declarado como Cliente, e sofre um cast up para Pessoa é possível fazer o cast

m
down para voltar a visualizá-lo como Cliente, porque o tipo real do objeto é Cliente. No entanto, se um
objeto é criado e declarado como Pessoa, não é possível fazer o cast down para transformá-lo em Cliente. Se

co
o tipo real é Pessoa, significa que o objeto não tem os atributos e métodos específicos de Cliente, que no
exemplo são cpf e seus respectivos getters e setters. Voltando à analogia anterior, não adianta tentar usar os
botões do controle remoto para funções não suportadas no modelo de TV utilizado.

g.
Ratificando, todo Cliente é uma Pessoa (possui todos os atributos e métodos de Pessoa), mas nem toda
Pessoa é um Cliente e por isso toda operação de cast down deverá ser feita sempre de forma explícita. Esta
in
obrigatoriedade significa que o compilador não pode garantir que os tipos sejam válidos, e o programador está
assumindo a responsabilidade. Caso a conversão seja inválida será gerado um erro em tempo de execução.
nn

1. public class TesteCastDown {


2.
3. public static void main(String[] args) {
ai

4. Cliente c = new Cliente();


5.
6. // Cast UP de Cliente para Pessoa
7. Pessoa p = c;
.tr

8.
9. // Cast DOWN de Pessoa para Cliente
10. Cliente c2 = (Cliente) p;
11.
w

12. // Criação de uma instância da classe Pessoa


13. Pessoa p2 = new Pessoa();
14.
w

15. // Cast DOWN INVÁLIDO de Pessoa para Cliente


16. Cliente c3 = (Cliente) p2;
17. }
w

18.}

Código 11.5 - TesteCastDown.java

Trainning Education Services - Todos os direitos reservados 249


r
11.1.3 Operador instanceof

.b
O operador instanceof é utilizado, antes da operação de cast down, para verificar se o objeto referenciado por
uma variável é compatível com uma determinada classe ou interface. Com isso evita-se o problema

m
ClassCastException verificado no exemplo anterior.

co
1. public class TesteOperadorInstanceof {
2.
3. public static void main(String[] args) {
4. Pessoa p = new Pessoa();
5.
6.
7.
8.
if (p instanceof Cliente) {
Cliente c = (Cliente) p; // cast down seguro
System.out.println("CPF: " + c.getCpf());
} else if (p instanceof Funcionario) {
g.
in
9. Funcionario f = (Funcionario) p; // cast down seguro
10. System.out.println("Salario: " + f.getSalario());
11. } else {
12. System.out.println("Nao eh Cliente nem Funcionario");
nn

13. }
14. }
15.}
ai

Código 11.6 - TesteOperadorInstanceof.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 250


11.2 Polimorfismo

Polimorfismo é uma palavra de origem grega que significa muitas formas. Essa palavra é usada para nomear um
poderoso recurso da Programação Orientada a Objetos (POO) que é utilizado da seguinte forma:

• define-se um tipo base (classe ou interface) e cria-se classes derivadas, por herança ou por
implementação de interface, e assim obtêm-se várias formas para um tipo base;

r
.b
• utiliza-se uma declaração de variável de um tipo-base para manipular (via cast up) um objeto de
qualquer um de seus tipos derivados.

m
co
Onde uma superclasse é esperada utiliza-se uma instância de uma subclasse.
Onde uma interface é esperada utiliza-se uma instância de uma classe implementadora.

g.
Essa abordagem otimiza a escrita de código, permitindo que um aplicativo cliente trabalhe com tipos mais
in
genéricos, em vez de precisar tratar cada tipo específico, quando o comportamento desejado é o mesmo para
ambos. Veja a seguir como isso acontece com as classes Contabilidade, FuncionarioCLT e
nn

FuncionarioPJ, inicialmente sem o uso do polimorfismo:


ai

1. public class FuncionarioCLT extends Funcionario {


2. public double calculaPagamento() {
.tr

3. double pagamento = 0.0;


4. //aplica regra de cálculo do pagamento de CLT
5. System.out.println("Calculando pagamento de FuncionarioCLT");
6. return pagamento;
w

7. }
8.}
w

Código 11.7 - FuncionarioCLT.java


w

Trainning Education Services - Todos os direitos reservados 251


1. public class FuncionarioPJ extends Funcionario {
2. public double calculaPagamento() {
3. double pagamento = 0.0;
4. //aplica regra de cálculo do pagamento de PJ
5. System.out.println("Calculando pagamento de FuncionarioPJ");
6. return pagamento;
7. }
8.}

Código 11.8 - FuncionarioPJ.java

r
1. public class ContabilidadeSemPolimorfismo {

.b
2.
3. public void gerarDemonstrativo(FuncionarioCLT func) {
4. System.out.println("O funcionario: " + func.getNome());

m
5. System.out.println("Recebeu o pagamento de "+func.calculaPagamento());
6. }
7.
8. public void gerarDemonstrativo(FuncionarioPJ func) {

co
9. System.out.println("O funcionario: " + func.getNome());
10. System.out.println("Recebeu o pagamento de "+func.calculaPagamento());
11. }
12.}

g.
Código 11.9 - ContabilidadeSemPolimorfismo.java
in
Perceba que o código dos dois métodos gerarDemonstrativo é idêntico. Um dos princípios da boa
programação orientada a objetos é que a repetição de código deve ser evitada mas como evitar a repetição do
código apresentado acima se os parâmetros recebidos são de tipos diferentes? Apesar dos tipos recebidos serem
nn

diferentes, ambos são subclasses de Funcionario, e mais importante, o código utiliza apenas métodos definidos
na superclasse. Assim,neste cenário é possivel obter redução do código utilizando o polimorfismo e, para isso
basta definir um único método que recebe como parâmetro a superclasse Funcionario, e eliminar os métodos
ai

redundantes, como pode ser observado no exemplo a seguir:


.tr

1. public class Contabilidade {


2.
3. public void gerarDemonstrativo(Funcionario func) {
w

4. System.out.println("O funcionario: " + func.getNome());


5. System.out.println("Recebeu o pagamento de "+func.calculaPagamento());
6. }
w

7.}

Código 11.10 - Contabilidade.java utilizando polimorfismo


w

Mas se a referência é para Funcionário, não vai ser chamado o método definido na superclasse em vez dos
métodos sobrescritos nas subclasses? Para responder esta pergunta basta recordar a analogia do controle

Trainning Education Services - Todos os direitos reservados 252


remoto: as funcionalidades estão presentes na TV e não no controle remoto. Da mesma forma, a variável de
referência apenas fornece uma maneira de acessar os métodos no objeto, mas o código está implementado no
objeto e não na referência. O método calculaPagamento será chamado no tipo real do objeto, e esse tipo será
conhecido em tempo de execução.

Esta capacidade de chamar o método desejado a partir do tipo real do objeto em tempo de execução é chamada
vínculo dinâmico (dynamic binding ou late binding).

r
O exemplo a seguir ilustra este comportamento:

.b
1. public class TesteDynamicBinding {
2.

m
3. public static void main(String[] args) {
4. Funcionario f = new FuncionarioCLT();
5. f.calculaPagamento();

co
6. f = new FuncionarioPJ();
7. f.calculaPagamento();
8. }
9.}

g.
Código 11.11 - TesteDynamicBinding
in
nn
ai
.tr

As duas principais formas de se beneficiar do polimorfismo na POO são:.


w

• parâmetros e retornos polimórficos (dynamic binding)



w

coleções heterogêneas

A classe RelatorioPessoas apresentada a seguir será utilizada nos próximos exemplos de polimorfismo:
w

Trainning Education Services - Todos os direitos reservados 253


1. public class RelatorioPessoas {
2.
3. public void imprime(Pessoa p) {
4. System.out.println("Nome: " + p.getNome() + "\trg: " + p.getRg());
5. }
6.
7. public int imprimeArray(Pessoa[] pessoas) {
8. int quantidadeImpressa = 0;
9. for (int i = 0; i < pessoas.length; i++) {
10. if (pessoas[i] == null) continue;
11. imprime(pessoas[i]);
12. quantidadeImpressa++;

r
13. }

.b
14. return quantidadeImpressa;
15. }
16.}

m
Código 11.12 - RelatorioPessoas.java

11.2.1 Parâmetros polimórficos

co
Considerando a hierarquia de classes Pessoa, Cliente e Funcionário: onde uma Pessoa é esperada pode
ser utilizado um Cliente ou um Funcionário.

1. public class TesteParametroPolimorfico {


2.
g.
in
3. public static void main(String[] args) {
4.
5. Pessoa p = new Pessoa();
nn

6. p.setNome("Willian Gates da Silva");


7. p.setRg(181920212223L);
8.
9. Cliente c = new Cliente();
10. c.setNome("Luiz Antonio Faria Lima");
ai

11. c.setRg(272829303132L);
12. c.setCpf("6544566-54");
13.
14. Funcionario f = new Funcionario();
.tr

15. f.setNome("Americo Vespucio da Gama");


16. f.setRg(495051525354L);
17. f.setSalario(2650.0);
18. f.setCarteiraProfissional("86554877899");
w

19.
20. RelatorioPessoas relatorio = new RelatorioPessoas();
21. relatorio.imprime(p); // Pessoa
w

22. relatorio.imprime(c); // Cliente


23. relatorio.imprime(f); // Funcionário
24.
w

25. }
26.}

Código 11.13 - TesteParametroPolimorfico.java

Trainning Education Services - Todos os direitos reservados 254


O método imprime(Pessoa c) da classe RelatorioPessoas recebe um parâmetro do tipo Pessoa, que
poderá ser um objeto de qualquer subclasse de Pessoa, (Cliente ou Funcionario),e por isso é considerado
um parâmetro polimórfico.

r
.b
m
co
11.2.2 Coleções Heterogêneas

1. public class TesteArrayHeterogeneo {


2.
3. public static void main(String[] args) {
4. Pessoa p = new Pessoa();
g.
in
5. p.setNome("Willian Gates da Silva");
6. p.setRg(181920212223L);
7.
nn

8. Cliente c = new Cliente();


9. c.setNome("Luiz Antonio Faria Lima");
10. c.setRg(272829303132L);
11. c.setCpf("6544566-54");
12.
ai

13. Funcionario f = new Funcionario();


14. f.setNome("Americo Vespucio da Gama");
15. f.setRg(495051525354L);
16. f.setSalario(2650.0);
.tr

17. f.setCarteiraProfissional("86554877899");
18.
19. Pessoa[] pessoas = new Pessoa[3];
20. pessoas[0] = f; // Funcionário
w

21. pessoas[1] = p; // Pessoa


22. pessoas[2] = c; // Cliente
23.
w

24. RelatorioPessoas relatorio = new RelatorioPessoas();


25. relatorio.imprimeArray(pessoas);
26. }
w

27.}

Código 11.14 - TesteArrayHeterogeneo.java

Trainning Education Services - Todos os direitos reservados 255


O array pessoas pode armazenar qualquer tipo de Pessoa, ou seja, Pessoa e qualquer subclasse, como
Cliente e Funcionário. Por isso este array é uma coleção heterogênea.

r
.b
m
11.3 Tipos de retorno covariantes e polimorfismo

co
Até a versão 1.4 da plataforma Java, a sobrescrita de métodos era válida somente se o nome do método, os tipos
dos parâmetros e o tipo de retorno fossem mantidos, Então, imagine o seguinte cenário: há uma interface
chamada BaseDAO que é a super-interface de todas as classes de acesso a camada de persistência; essa

g.
interface define um método que retorna um objeto dado a primary key do objeto, ou seja, o índice no banco de
dados. Veja no exemplo abaixo:
in
1. public interface BaseDAO {
2. public Object getByPrimaryKey(Object o);
nn

3.}

Código 11.15 - BaseDAO.java


ai

Cada implementação desta interface retorna um objeto de um tipo diferente, no entanto, pela definição de
sobrescrita retorna-se somente objetos do mesmo tipo definido na interface, como pode ser observado a seguir:
.tr

1. public class ClienteDAOSemCovariancia implements BaseDAO {


2.
w

3. public Object getByPrimaryKey(Object o) {


4. return null;
5. }
w

6.}

Código 11.16 - ClienteDAOSemCovariancia


w

Trainning Education Services - Todos os direitos reservados 256


Ao utilizar a classe ClienteDAOSEmCovariancia, sabe-se que o método getByPrimaryKey retorna um objeto
da classe Cliente, no entanto é necessário fazer o Cast Down de Object para Cliente toda vez que o
método for utilizado, conforme pode-se observar no exemplo a seguir:

1. public class TesteClienteDAOSemCovariancia {


2.
3. public static void main(String args) {
4. ClienteDAOSemCovariancia dao = new ClienteDAOSemCovariancia();
5. Cliente c = (Cliente) dao.getByPrimaryKey(new Integer(20));

r
6. }
7.}

.b
Código 11.17 - TesteClienteDAOSemCovariancia.java

m
Com a introdução dos valores de retorno covariantes, é possível alterar o tipo de retorno de um método
sobrescrito, desde que o novo tipo de retorno seja derivado (subclasse ou implementação da interface) do tipo

co
definido no método que está sendo sobrescrito, facilitando assim a tarefa do usuário que utiliza os métodos
sobrescritos. O mesmo exemplo seria implementado com covariância da seguinte forma:

1. public class ClienteDAO implements BaseDAO {


2.
3. public Cliente getByPrimaryKey(Object o) {
g.
in
4. return null;
5. }
6.}
nn

Código 11.18 - ClienteDAO.java

Na classe ClienteDAO altera-se o tipo de retorno do método getByPrimaryKey, indicando que o método
ai

retorna um Cliente ao invés de um Object. Isto só é possível porque Cliente é uma subclasse de Object.
.tr

A facilidade pode ser observada na classe que utiliza o método sobrescrito. Perceba que no código abaixo não foi
necessário fazer casting de Object para Cliente, porque o método já retorna um objeto do tipo Cliente.
w

1. public class TesteClienteDAO {


2. public static void main(String args) {
w

3. ClienteDAO dao = new ClienteDAO();


4. Cliente c = dao.getByPrimaryKey(new Integer(20));
5. }
w

6.}

Código 11.19 - TesteClienteDAO.java

Trainning Education Services - Todos os direitos reservados 257


11.4 Acoplamento e polimorfismo
Como já foi visto no capítulo sobre encapsulamento, acoplamento é o grau de conhecimento da estrutura de uma
classe ou conjunto de classes para que ela seja utilizada por outras. Baixo acoplamento pode ser obtido através
do uso de polimorfismo, tanto com o uso de herança quanto de interfaces. O acoplamento pode ser melhor
visualizado através de um diagrama de classes. O diagrama a seguir mostra o acoplamento entre as classes
Contabilidade e as diversas implementações de Funcionário.

r
.b
m
co
g.
in
Diagrama 11.2 - Acoplamento entre a classe Contabilidade e implementações de Funcionario sem o
nn

uso de polimorfismo
ai
.tr
w
w
w

Diagrama 11.3 - Acoplamento entre a classe Contabilidade e Funcionario após o uso de polimorfismo

Trainning Education Services - Todos os direitos reservados 258


Perceba que no primeiro diagrama existe uma dependência (acoplamento) entre a classe Contabilidade e as
classes FuncionarioCLT e FuncionarioPJ. No segundo diagrama a classe Contabilidade possui um
acoplamento apenas com a classe Funcionario.

Um dos ganhos obtidos com o baixo acoplamento é a facilidade na manutenção do sistema. Em sistemas com alto
acoplamento, alterações nas classes provocam um efeito cascata de alteração em múltiplas classes. No primeiro
exemplo se fosse alterado o nome da classe FuncionarioPJ para FuncionarioTerceirizado seria

r
necessário alterar também a classe Contabilidade. Já no segundo exemplo, somente a classe

.b
FuncionarioPJ seria alterada.

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 259


11.5 Certificação Oracle Certified Java Programmer (OCJP)

1. Assume that Triangle and Circle are both subclasses of class Shape.
Given the declarations:
Shape shape = new Shape();
Triangle triangle = new Triangle();
Circle circle = new Circle();

r
.b
Which statement best describes the result of attempting to compile and execute the following statement:
shape=triangle;

m
A) Compiles and definitely legal at runtime
B) Does not compile

co
C) Compiles and but may be illegal at runtime

2. Given:

1: class Animal {
g.
in
2: String getName() { return "animal"; }
3: Animal getType() { return this; }
4: }
5: class Mammal extends Animal {
nn

6: // insert code here


7:}
8: class Dog extends Mammal { }
ai

Which statement(s), inserted at line 6, will compile? (choose 3 answers)


A) Mammal getType(){return this;}
.tr

B) String getType(){return "this";}


C) Animal getType(){return this; }
w

D) Dog getType(){return new Dog ();}


w
w

Trainning Education Services - Todos os direitos reservados 261


CAPÍTULO

12

r
.b
m
co
g.
in
nn
ai

Pacotes
.tr

Declarando o pacote das classes


Utilizando classes de outros pacotes
w

Representação de pacotes na UML


Dicas para utilização de pacotes
Componentes:JAR (Java ARchive)
w

Diagrama de componentes
w

Trainning Education Services - Todos os direitos reservados 263


12 Pacotes
Imagine só um único projeto com 100 ou, até mesmo, 1000 classes e todos os arquivos no mesmo diretório...
Parece caótico, não é? Na realidade, as classes em Java são organizadas da mesma forma como se organizam
nossos arquivos, ou seja, em diretórios. No entanto, a JVM precisa de alguma diretiva para localizar arquivos que
estão em diretórios diferentes, e, para isso, utiliza-se a estrutura de pacotes.

É importante entender, desde o ínicio, que a estrutura de pacotes está baseada na estrutura de diretórios. No

r
entanto, para se referir a pacotes dentro do código não se utiliza uma barra, mas um ponto separando os

.b
diretórios.

Todas as APIs do Java estão organizadas em pacotes, como se verifica na documentação Javadoc:

m
Lista de classes do pacote selecionado; ou

co
todas, se forem selecionadas All Classes
Lista de pacotes do Java SE

g.
in
nn
ai
.tr
w
w
w

Figura 12.1 - lista de pacotes das APIs do Java SE

Trainning Education Services - Todos os direitos reservados 265


O arquivo que contém as classes do JDK pode ser encontrado no diretório de instalação do JDK (JAVA_HOME)
em JAVA_HOME/jre/lib/rt.jar. Abra este arquivo com um utilitário de descompactação, como se fosse um
arquivo .zip para analisá-lo.

r
.b
m
co
g.
Figura 12.2 - estrutura interna do arquivo rt.jar
in
nn
ai
.tr
w
w

A estrutura de diretórios é análoga à estrutura de


w

pacotes encontrada na documentação Javadoc.

Figura 12.3 - estrutura interna do arquivo rt.jar navegando para o pacote java

Trainning Education Services - Todos os direitos reservados 266


12.1 Declarando o pacote das classes
Já foi visto que as classes do JDK estão organizadas em pacotes, e conseqüentemente em diretórios. Porém não
basta simplesmente colocar o arquivo Java na estrutura de diretórios desejada. É preciso declarar no próprio
código qual é esta estrutura. Isso é feito através da instrução package.

Sintaxe para declaração de pacotes:

r
package nomeCompletoDoPacote;

.b
A instrução package deverá sempre ser a primeira instrução da classe, e o nome do pacote será a estrutura de
diretórios onde se encontra a classe, mas lembrando que deverá ser utilizado ponto como separador em vez da

m
barra. É importante destacar que a estrutura de diretórios não consiste no caminho absoluto utilizado desde o
diretório raiz do sistema de arquivos, mas sim de um caminho relativo. O início deste caminho relativo corresponde

co
ao classpath configurado para a aplicação, que normamente é o diretório corrente.

Todas as classes de um mesmo pacote devem conter a mesma instrução package como primeira instrução do
arquivo no qual a classe foi declarada. g.
Convenciona-se declarar nomes de pacotes utilizando uma URL invertida: normalmente a URL do “proprietário” da
in
classe como, por exemplo, sua empresa ou a empresa para quem você está desenvolvendo.Aqui será utilizada a
URL da trainning.com.br que será declarada como br.com.trainning.
nn

Veja como colocar a classe ExemploPacote no diretório br/com/trainning/exemplos e fazer a declaração


do pacote como primeira instrução da classe.
ai

1. package br.com.trainning.exemplos;
.tr

2.
3. public class ExemploPacote {
4. public static void main(String[] args) {
5. System.out.println("Esta classe esta dentro de um pacote!!");
w

6. }
7. }

Código 12.1 - ExemploPacote.java


w
w

Trainning Education Services - Todos os direitos reservados 267


12.1.1 Compilando classes que estão em pacotes
É uma boa prática criar diretórios específicos para cada um dos projetos que estão sendo desenvolvidos. Isso
significa que não se deve usar o diretório raiz da máquina como diretório base para as aplicações.

Suponha que esteja desenvolvendo um projeto no subdiretório projeto1 localizado na pasta projetos:
dentro dele, será criada a estrutura de diretórios do pacote, (br/com/trainning)e, neste caso, a compilação e
também a execução, como será visto no tópico seguinte, deverão ser feitas a partir da raiz da estrutura de
pacotes, isto é, do diretório projeto1.

r
.b
c:\projetos\projeto1> javac br\com\trainning\exemplos\*.java

m
ou então,

co
c:\projetos\projeto1> javac br\com\trainning\exemplos\ExemploPacote.java

12.1.2 Executando classes que estão em pacotes


g.
A execução de classes que estão em pacotes também deverá ser realizada a partir do diretório raiz da aplicação.
No entanto, não se está executando um arquivo qualquer, mas uma classe e, por isso, é necessário usar a
in
estrutura de pacotes do Java, em que os diretórios serão separados por pontos ao invés de barras.

c:/projetos/projeto1> java br.com.trainning.exemplos.ExemploPacote


nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 268


12.1.3 Erros comuns

1. É comum tentar compilar ou executar a classe de outros diretórios diferentes do diretório


raiz da aplicação como, por exemplo, no mesmo diretório da classe.
Quando a classe não tem dependência com outras, normalmente não ocorrem erros na compilação,
mas na execução.

r
.b
m
co
g.
in
nn

Para corrigir este erro basta executar a classe do diretório correto, ou seja, do diretório raiz da aplicação.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 269


12.2 Utilizando classes de outros pacotes
Uma classe não tem automaticamente acesso à classes de outros pacotes. Para utilizar uma classe que está em
outro pacote e, conseqüentemente, em outro diretório há duas opções:
1. utilizar o nome completo da classe (fully qualified name), que inclui também o nome do pacote (Ex:
br.com.trainning.ExemploPackage)
2. importar a classe através da instrução import. Desta forma, não é necessário utilizar o nome completo

r
da classe no código

.b
Sintaxe para importação de classes:
import nomeCompletoDaClasse;

m
<declaração de classe ou interface>
ou

co
import nomePacote.*;
<declaração de classe ou interface>

as classes do pacote utilizando “*”.


g.
É possível importar apenas uma classe do pacote, indicando apenas o nome completo da classe, ou então, todas

Diferente da instrução package, que pode aparecer somente uma vez na


in
classe, a instrução import pode aparecer diversas vezes, porém deve sempre ser utilizada antes da declaração da
classe ou interface.
nn

A classe Date do pacote java.util será utilizada nos exemplos com o intuito de aprender a importar classes
que não estejam no mesmo diretório, isto é, que não estejam no mesmo pacote. Esta classe representa datas em
ai

Java.
.tr

Quando se constrói um objeto da classe Date utilizando o construtor padrão, o objeto é inicializado para o valor
da data atual do sistema operacional.
w

Observe a seguir que apenas a classe Date do pacote java.util foi importada, e dentro do método main
foi criada uma instância da classe e impressa na console:
w
w

Trainning Education Services - Todos os direitos reservados 270


1. package br.com.trainning.testes;
2.
3. import java.util.Date;
4.
5. public class TesteImport {
6.
7. public static void main(String[] args) {
8. Date d = new Date();
9. System.out.println(d);
10. }
11.}

r
Código 12.2 - TesteImport.java

.b
m
co
g.
Também é possível importar todas as classes de um pacote, utilizando * no lugar do nome da classe. No exemplo
in
abaixo é novamente utilizada a classe Date mas agora importando todas as classes do pacote.
nn

1. package br.com.trainning.testes;
2.
3. import java.util.*;
4.
5. public class TesteImportPacote {
ai

6.
7. public static void main(String[] args) {
8. Date d = new Date();
.tr

9. System.out.println(d);
10. }
11.}
w

Código 12.3 - TesteImportPacote


w
w

Trainning Education Services - Todos os direitos reservados 271


r
A utilização do import utilizando “*” não afeta a performance, porque a JVM carrega as classes sob demanda e

.b
não quando um import é realizado.

m
IMPORTANTE
• Para aumentar a legibilidade do código, é conveniente declarar explicitamente o

co
import individual das classes;
• Além das classes do próprio pacote, as únicas classes que podem ser utilizadas
diretamente no código sem a necessidade de importação são aquelas do pacote
g.
java.lang. Neste pacote estão as classes consideradas fundamentais da
linguagem, como a classe System e String, entre outras.
in
Outra opção para trabalhar com classes de outros pacotes é usar o nome completo da classe como pode ser visto
a seguir. Neste caso não é necessário utilizar a instrução import.
nn

1. package br.com.trainning.testes;
2.
ai

3. public class TesteNomeCompleto {


4.
5. public static void main(String[] args) {
.tr

6. java.util.Date d = new java.util.Date();


7. System.out.println(d);
8. }
9. }
w

Código 12.4 - TesteNomeCompleto


w
w

Trainning Education Services - Todos os direitos reservados 272


12.2.1 Modificador padrão / package
Antes de abordar o modificador padrão, convém relembrar os outros modificadores de acesso já estudados.

Modificador public
Definem-se como public:
• classes;
• construtores;.
• métodos;

r
• atributos.

.b
Os elementos que estiverem com o modificador de acesso public poderão ser acessados por outros métodos e
construtores de quaisquer classes (inclusive as que estão em outros pacotes).

m
Modificador private
Definem-se como private:

co
• construtores;
• métodos;
• atributos.
g.
Os elementos que estiverem com o modificador de acesso private não poderão ser acessados externamente
in
por nenhuma instância de outras classes e, portanto,, poderão ser acessados exclusivamente pelos elementos da
própria classe.
nn

Modificador protected
Definem-se como protected:
ai

• construtores;

.tr

métodos;
• atributos.
w

Os elementos demarcados como protected, serão acessíveis pelos métodos e construtores de suas classes
filhas e todas as classes que estiverem no mesmo pacote.
w
w

Trainning Education Services - Todos os direitos reservados 273


Modificador padrão (também conhecido como friendly ou package)
O modificador padrão estará sinalizado implicitamente quando não for colocado nenhum modificador de acesso

Ele podem ser declarado em:


• classes;
• construtores;
• métodos;
• atributos.

r
.b
Os elementos demarcados por este modificador podem ser acessados, por método ou construtores da classes
definidas no mesmo pacote.

m
Tabela 12.1 - Modificadores de acesso e o comportamento entre pacotes:

co
Acessível Modificador Acesso permitido
Permite acesso a qualquer classe
public

protected
g.
Qualquer classe do mesmo pacote ou qualquer
sub-classe pode acessar o metodo ou atributo
protected.
in
Permite acesso a qualquer classe do mesmo
não especificado pacote
nn

Somente a própria classe pode acessar o


private método ou atributo private.
Restritivo
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 274


12.2.2 Importando duas classes com o mesmo nome em pacotes diferentes
Por vezes, é necessário importar duas classes que possuem o mesmo nome, mas estão localizadas em pacotes
diferentes. No Java SE, existem duas classes Date em diferentes pacotes: uma no java.sql, e outra no
java.util. Para usar as duas na mesma classe é necessário utilizar o nome totalmente qualificado (full qualified
name) da classe sempre que for feita alguma referência.

Não se pode fazer o import das duas classes explicitamente, porque o compilador detecta a ambigüidade,
gerando uma mensagem de erro, conforme demonstra o código abaixo e a saída da compilação:

r
.b
1. package br.com.trainning.erros;
2.

m
3. import java.util.Date;
4. import java.sql.Date;
5.
6. public class ExemploAmbiguo {

co
7.
8. }

Código 12.5 - ExemploAmbiguo.java


g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 275


Também não é possivel resolver a ambigüidade fazendo um import do pacote inteiro. Veja as importações dos
pacotes completos java.util e java.sql:

1. package br.com.trainning.erros;
2.
3. import java.util.*;
4. import java.sql.*;
5.
6. public class ExemploImportAmbiguo {
7.

r
8. public static void main(String[] args) {

.b
9. Date data = new Date();
10. System.out.println("java.util.Date = " + data);
11. // Operações que utilizam classes do pacote java.sql
12. }

m
13.}

Código 12.6 - ExemploImportAmbiguo.java

co
g.
in
nn
ai
.tr

É possivel resolver a ambigüidade utilizando o nome completo das classes, em vez de importá-las como
demonstrado a seguir:
w
w
w

Trainning Education Services - Todos os direitos reservados 276


1. package br.com.trainning.exemplos;
2.
3. public class ExemploSemImport {
4. public static void main(String[] args) {
5. java.util.Date data = new java.util.Date();
6. // A data do pacote java.sql deverá ser construída passando
7. // um long referente ao número de milisegundos desde 01/01/1970
8. // Obtém-se o número de milisegundos desde 01/01/1970 chamando
9. // o método getTime da classe java.util.Date
10. long miliSegundos = data.getTime();
11. java.sql.Date dataSQL = new java.sql.Date(miliSegundos);
12.

r
13. System.out.println("java.util.Date = " + data);

.b
14. System.out.println("java.sql.Date = " + dataSQL);
15. }
16.}

m
Código 12.7 - ExemploSemImport.java

co
g.
in
nn

Outra solução para a ambigüidade, é fazer um import explícito somente de uma das classes e o import do
pacote inteiro da outra. No exemplo utilizado, ao fazer um import explícito para a classe java.util.Date e um
import do pacote inteiro java.sql.*, pode se usar a classe Date sem utilizar o nome totalmente qualificado;
ai

o compilador assumirá que a classe Date que se quer utilizar é a do pacote java.util, visto que foi feito um
import explícito. Se for necessário utilizar também a classe java.sql.Date o nome completo deve ser
.tr

utilizado.
w
w
w

Trainning Education Services - Todos os direitos reservados 277


1. package br.com.trainning.exemplos;
2.
3. import java.util.Date;
4. import java.sql.*;
5.
6. public class ExemploImportCorreto {
7.
8. public static void main(String[] args) {
9. Date data = new Date();
10. System.out.println("java.util.Date = " + data);
11. }
12. }

r
.b
Código 12.8 - ExemploImportCorreto.java

Se nenhuma das instruções de import for explícita ou ambas forem explícitas, ocorrerá um erro de compilação.

m
co
12.2.3 Trabalhando com classes que estão em pacotes diferentes
Como foi visto anteriormente, a estrutura de diretórios foi criada para melhor organização das classes; logo não
adiantaria criar apenas um pacote e colocar todas as classes de um projeto dentro dele.
g.
No entanto, muitas vezes uma classe utiliza outra: a classe Pessoa utiliza a classe Endereco mas elas não
in
estarão necessariamente no mesmo pacote.
nn

Para permitir que a classe Pessoa possa acessar a classe Endereco é preciso seguir os seguintes passos:
1. colocar cada um dos arquivos das classes em seus respectivos pacotes
2. adicionar a instrução package em cada uma delas, respeitando a estrutura de diretórios
3. colocar a instrução de import adequada na classe Pessoa para que a JVM possa carregar a classe
ai

Endereco quando necessário


.tr

Veja como fazer isso colocando as classes Pessoa e Endereco em pacotes diferentes.
w

Obs: Os métodos da classe Pessoa foram omitidos no exemplo, pois são irrelevantes neste contexto.
w
w

Trainning Education Services - Todos os direitos reservados 278


1. package br.com.trainning.model;
2.
3. import br.com.trainning.util.Endereco;
4.
5. public class Pessoa {
6.
7. private Endereco endereco;
8. private String nome;
9. private String rg;
10. // Os métodos da classe foram omitidos
11. }

r
Código 12.9 - Pessoa.java

.b
m
1. package br.com.trainning.util;
2.
3. public class Endereco {

co
4.
5. private String rua;
6. private int numero;
7. // Os métodos da classe foram omitidos
8. }
g.
Código 12.10 - Endereco.java
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 279


12.2.4 Erros comuns

1. Esquecer de colocar a instrução de import na classe e tentar utilizá-la.

1. package br.com.trainning.exemplos.erros; 2.

3. public class ExemploFaltaImport {


4. public static void main(String[] args) {
5. Date d = new Date();
6. System.out.println(d);

r
7. }
8. }

.b
Código 12.11 - ExemploFaltaImport.java

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 280


2. Realizar imports ambiguos.
Com freqüência utiliza-se mais do que um import de pacotes inteiros, sem se conhecer todas as
classes de todos os pacotes. Se houver classes com o mesmo nome, ocorre um erro de compilação
como foi mostrado no exemplo da classe ExemploImportAmbiguo (Código 12.6) em que há um
import do pacote java.util.* e outro do pacote java.sql.*.

r
.b
3. Utilizar import antes da instrução package.

m
1. import java.util.Date;
2. package br.com.trainning.exemplos.erros;
3.

co
4. public class ExemploImportAntes {
5. public static void main(String[] args){
6. Date d = new Date();
7. System.out.println(d);
8. }
9. } g.
Código 12.12 - ExemploImportAntes.java
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 281


4. Tentar acessar a classe, método ou atributo de classes declaradas em outros pacotes sem serem
declaradas com o modificador de acesso public.

Observe a classe Endereco declarada com o modificador padrão, ou seja, permitindo acesso somente a classes
do mesmo pacote.

1. package br.com.trainning.util;
2. class Endereco {

r
3.
4. private String rua;

.b
5. private int numero;
6.//Os métodos da classe foram omitidos
7. }

m
Código 12.13 - Endereco.java com modificador default

A classe Pessoa (Código 12.9) utiliza a classe Endereco, mas a classe Endereco não oferece acesso

co
para classes definidas em outros pacotes.

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 282


Há muitos erros gerados pelo acesso ilegal à classe Endereço, porque em cada método de acesso ao atributo
endereco, um erro é gerado.

5. As classes estão nos diretórios corretos, mas a instrução package não foi colocada.

Nos exemplos a seguir omitiu-se a instrução package das classes Pessoa e Endereco.

1. import br.com.trainning.util.Endereco;

r
2.

.b
3. public class Pessoa {
4.
5. private Endereco endereco;
6. private String nome;

m
7. private String rg;
8. // Os métodos da classe foram omitidos
9. }

co
Código 12.14 - Pessoa.java sem a instrução package

1. public class Endereco {


2.
3.
4.
private String rua;
private int numero;
g.
in
5. // Os métodos da classe foram omitidos
6. }

Código 12.15 - Endereco.java sem a instrução package


nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 283


12.3 Importação estática (static import)

A utilização de métodos estáticos até a versão 1.4 da plataforma Java exige que a chamada ao método seja
prefixada com o nome da classe.

1. package br.com.trainning.util;
2.
3. public class Logger {

r
4. public static final int DEBUG = 0;
5. public static final int ERROR = 1;

.b
6. public static void log (String msg, int level){
7. System.out.println("["+level+"]"+msg);
8. }

m
9. }

Código 12.16 - Logger.java

co
1. package br.com.trainning.testes; 2.
3. import br.com.trainning.util.Logger;
4.
g.
in
5. public class TesteSemStaticImport {
6. public static void main(String[] args){
7. Logger.log("Facil, facil....", Logger.DEBUG);
8. }
nn

9. }

Código 12.17 - TesteSemStaticImport.java


ai

Em muitas situações é necessário definir constantes e métodos que deverão ser utilizadas em várias classes
muito frequentemente. Para que o código não se torne muito redundante e repetitivo, os programadores
.tr

começaram a colocar as constantes e métodos estáticos em uma interface ao invés de colocar em uma classe.
Desta forma, ao invés de importar a classe quando necessário, implementa-se a interface.
w

Esta não é considerada uma boa prática, e foi definida como Constant Interface Antipattern no livro Effective
3
Java.
w
w

3
Este livro, escrito por Joshua Bloch, é considerado uma das melhores referências para boas práticas na
linguagem Java.

Trainning Education Services - Todos os direitos reservados 284


12.3.1 Como utilizar importação estática?
A partir da versão 5 foi incluido o suporte a um novo tipo de importação, denominada importação estática, a partir
do uso da instrução import. O import estático é análogo ao import tradicional, mas importa métodos e
atributos estáticos de classes ao invés de importar classes de pacotes.

A sintaxe é ligeiramente diferente, visto que é necessário adicionar a palavra static na declaração de import.

Sintaxe para importação estática:

r
import static nomeCompletoDaClasse.nomeMembro;

.b
ou
import static nomeCompletoDaClasse.*;

m
Usando importação estática podem ser utilizados os métodos e atributos estáticos sem a necessidade de utilizar o
nome da classe.

co
1. package br.com.trainning.testes;
2.
3. import static br.com.trainning.util.Logger.*;
4.
5. public class TesteComStaticImport {
g.
in
6. public static void main(String[] args) {
7. log("Facil, facil....", DEBUG);
8. }
9. }
nn

Código 12.18 - TesteComStaticImport.java


ai

12.3.2 Quando devemos utilizar importação estática?


.tr

• Devemos utilizar importação estática quando estamos fazendo uso intenso de métodos estáticos de
uma determinada classe;
w

• Devemos utilizar importação estática para substituir o uso do Constant Interface Anti-pattern;
w

• Não devemos utilizar importação estática para todos os métodos estáticos, pois isto pode diminuir a
legibilidade e consequentemente a manutenibilidade do código, já que não saberemos em qual classe
w

o método estático está declarado.

Trainning Education Services - Todos os direitos reservados 285


12.4 Representação de pacotes na UML

Pacotes são representados na UML através de diagramas de classes.

Um pacote é representado na UML pelo símbolo de pasta cujo nome pode ser colocado na guia superior esquerda
ou no meio do desenho.

r
.b
m
Diagrama 12.1 - representando pacotes em UML

co
g.
in
Diagrama 12.2 - representação alternativa de pacotes em UML
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 286


Também é possível representar a dependência entre classes que estão em pacotes diferentes, como se vê no
diagrama abaixo:

r
.b
m
co
Diagrama 12.3 - dependências entre classes

g.
Em determinadas situações não é necessário especificar a dependência entre classes, mas somente a
dependência entre os pacotes, como se observa no seguinte diagrama:
in
nn
ai
.tr
w
w
w

Diagrama 12.4 - representando dependências entre pacotes

Trainning Education Services - Todos os direitos reservados 287


12.5 Dicas para utilização de pacotes
A seguir são apresentadas algumas boas práticas e convenções na utilização de pacotes.

• Iniciar os pacotes com o domínio da internet invertido mais o nome da empresa proprietária ou
desenvolvedora, como por exemplo: br.com.trainning, com.mysql, br.com.seudominio.

• Não utilizar pacotes iniciados com java, javax, ou domínios de outras empresas.

r
.b
• Ao criar pacotes utilizar apenas letras minúsculas e apenas nomes com uma palavra, de acordo com
a convenção de nomenclatura da Sun,

m
• Evitar a dependência circular entre pacotes como pode ser visto no diagrama abaixo:

co
g.
in
Diagrama 12.5 - dependência circular entre pacotes
Neste caso específico, o ideal é que o pacote de business dependa do pacote que contém as classes de
modelo, mas que a recíproca não seja verdadeira:
nn
ai
.tr

Diagrama 12.6 - corrigindo a dependência circular entre pacotes


w

• Pacotes devem conter um conjunto de classes de uma mesma “família”. Por exemplo: o pacote
w

br.com.trainning.model contém classes do modelo, o pacote


br.com.trainning.business contém classes de lógica de negócio, ou seja, evitar, sempre que
w

possível, misturar classes muito diferentes em um mesmo pacote. Não faz sentido colocar a classe
Logger dentro do pacote br.com.trainning.model, ou br.com.trainning.business.

Trainning Education Services - Todos os direitos reservados 288


• É comum dividir as classes por projetos, ou seja, ter diversos projetos sob um mesmo domínio.
Depois, cada projeto é dividido em pacotes de acordo com a funcionalidade das classes, seguindo a
convenção utilizada nas classes pertencentes ao Java SE e Java EE, ou seja, um pacote para
modelo, um pacote para utilitários, um pacote para camada de persistência, e outros.

r
.b
m
co
g.
in
nn

Diagrama 12.7 - representação de diversos pacotes


ai

Caso seja necessário, pode haver mais subdivisões referentes a módulos de um mesmo projeto, ou qualquer
divisão que faça sentido no cenário da empresa, projeto e equipe de desenvolvimento.
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 289


12.6 Componentes: JAR (Java ARchive)
Após conhecer como organizar as classes de um projeto Java em pacotes, é necessário estudar como fazer a
distribuição dessas classes. O software desenvolvido em Java pode ser um aplicativo ou uma biblioteca utilitária,
que deve ser instalado ou distribuido para ser utilizado em outros computadores. Existe um padrão para
empacotamento das classes em um único arquivo chamado JAR (Java ARchive), que é idêntico ao formato zip, e
pode ser feito com qualquer utilitário de compressão e descompressão de arquivos ZIP.

r
Existe, entre outros utilitários do JDK, um denominado jar, que é responsável pela criação, descompactação e

.b
atualização dos arquivos com terminação *.jar.

Para obter a ajuda desse utilitário basta digitar jar na linha de comando e todas as opções serão exibidas.

m
co
g.
in
nn
ai
.tr
w
w
w

Para mais infomações, consulte a documentação dos utilitários distribuída juntamente com o JDK que pode ser
encontrada em: %JAVA_HOME%\docs\tooldocs\tools.html

Trainning Education Services - Todos os direitos reservados 290


Agora aprenda a executar as seguintes tarefas:
• criar um JAR simples;
• extrair as classes de um JAR;
• criar um JAR executável.

12.6.1 Criação de um JAR simples


A criação de um JAR é feita utilizando o utilitário jar da seguinte forma:

r
.b
jar –cvf nomeDoJar.jar raizDoPacote

c: Create (criação de arquivo jar)

m
v: Verbose (imprimir na console todas as operações que estão sendo executadas)
f: File (nome do arquivo a ser criado)

co
No exemplo, há a seguinte estrutura de diretórios:

g.
in
nn
ai

Figura 12.4 - estrutura de diretórios do exemplo


.tr

A partir do diretório projeto1, o utilitário jar será executado, passando os seguintes parâmetros:
jar –cvf testeJAR.jar br
w
w
w

Trainning Education Services - Todos os direitos reservados 291


r
.b
m
O arquivo testeJAR.jar é gerado e todos os arquivos encontrados abaixo do diretório br foram adicionados.

co
Examine o conteúdo do arquivo testeJAR.jar, abrindo-o com algum utilitário de descompactação.

g.
in
nn
ai
.tr
w

Figura 12.5 - conteúdo do arquivo testeJAR.jar


w

Note que foi criado um arquivo MANIFEST.MF no diretório META-INF; ele será visto mais adiante no tópico que
explicará a execução de arquivos JAR.
w

Trainning Education Services - Todos os direitos reservados 292


12.6.2 Extração das classes de um JAR
Para extrair os arquivos de um arquivo JAR, ZIP ou similar basta passar os parâmetros xvf para o utilitário jar,
pois eles indicam:

x: eXtract (extrair os arquivos do JAR);


v: Verbose (imprimir na console todas as operações que estão sendo executadas);
f: File (nome do arquivo que queremos descompactar)

r
A extração dos arquivos do JAR gerado no exemplo anterior pode ser feita com o seguinte comando:

.b
jar –xvf testeJAR.jar

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 293


12.6.3 Criação de um JAR executável
Para gerar um JAR executável é necessário indicar no arquivo MANIFEST.MF o nome da classe, cujo método
main, deverá ser executado em decorrência da chamada ao JAR.
Somente uma classe poderá ser indicada neste arquivo, porque apenas um método main é executado.

Formato do arquivo MANIFEST.MF


Manifest-Version: Versão do arquivo

r
Created-By: Criador do arquivo

.b
Main-Class: Nome totalmente qualificado da classe que queremos executar

Para transformar o JAR de exemplo em um arquivo executável deve ser criado um arquivo MANIFEST.MF

m
conforme o código de exemplo apresentado a seguir:

co
Manifest-Version: 1.0
Created-By: trainning
Main-Class: br.com.trainning.testes.TesteImport
g.
Código 12.19 - MANIFEST.MF
in
Sempre que o utilitário jar gera ou altera um arquivo, um MANIFEST.MF é criado e adicionado automaticamente
ao diretório META-INF. Para adicionar um arquivo MANIFEST.MF específico, basta utilizar o parâmetro m (indica
nn

que será feita a inclusão de um Manifest.MF) e indicar o local onde o arquivo pode ser encontrado.

A adição de um arquivo manifest.MF no exemplo apresentado pode ser feita com o seguinte comando:
ai

jar -cvfm testeJARExecutavel.jar META-INF/MANIFEST.MF br


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 294


Depois de alterar o arquivo MANIFEST.MF, gerado automaticamente na execução anterior do utilitário jar, o
utilitário será novamente executado, indicando onde está o MANIFEST.MF, para que ele faça a inclusão
corretamente.

r
.b
m
co
12.6.4 Execução de um JAR
g.
Para executar um arquivo JAR (que tenha definido corretamente o MANIFEST.MF) usa-se o utilitário java,
passando –jar como argumento, assim como o nome do arquivo que se quer executar.
in
Sintaxe:
java –jar nomeJar.jar
nn

Para executar o JAR gerado no exemplo basta utilizar o seguinte comando:


java –jar testeJARExecutavel.jar
ai
.tr
w

Como esperado, o método main da classe TesteImport foi executado, imprimindo a data do sistema na
console.
w
w

Trainning Education Services - Todos os direitos reservados 295


12.6.5 Disponibilizando um JAR para muitas aplicações
Para disponibilizar as classes contidas em um JAR para outras aplicações basta colocar o endereço e o nome do
JAR na variável de ambiente CLASSPATH.

No exemplo utilizado:
CLASSPATH = C:\Projetos\projeto1\testeJARExecutavel.jar

Veja a criação de uma classe chamada TesteJar, que utiliza a classe Endereco contida no

r
testeJARExecutavel.jar. Esta classe será colocada em um diretório isolado, neste caso, na raiz do sistema

.b
de arquivos:

m
1. package br.com.trainning.testes;
2.
3. import br.com.trainning.util.Endereco;

co
4.
5. public class TesteJar {
6.
7. public static void main(String[] args) {
8.
9.
10.
11.}
}
Endereco e = new Endereco("Av. Paulista", 1000);
System.out.println(e);
g.
in
Código 12.20 - TesteJar.java
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 296


O endereço do testeJARExecutavel.jar não foi colocado no CLASSPATH, portanto a classe Endereco não
pôde ser encontrada e, então é preciso indicar para o utilitário javac onde o JAR pode ser encontrado. Isto é feito
através do uso do argumento -classpath.

Sintaxe do argumento -classpath para o compilador javac


javac –classpath enderecoDoJAR/nomeDoJar.jar nomeClasseParaCompilar.java

r
.b
m
co
g.
in
nn
ai
.tr

IMPORTANTE
Quando se utiliza o argumento classpath, fica estabelecido que o compilador ou o utilitário
em questão deverá procurar por arquivos somente no(s) diretório(s) indicados.
w

Para executar a classe TesteJar também será necessário indicar ao utilitário java onde
w

encontrar o JAR que contém a classe Endereço, assim como foi feito para a compilação,
w

Sintaxe do argumento -classpath para o utilitário java


java –classpath enderecoDoJAR/nomeDoJar.jar nomeClasseParaExecucao

Trainning Education Services - Todos os direitos reservados 297


r
.b
m
O utilitário java não pode encontrar a classe que se quer executar, visto que ela não está no
CLASSPATH, ou seja, não está no jar testeJARExecutavel.jar; então é necessário indicar

co
que o utilitário java também deverá procurar as classes no diretório corrente, pois é lá que se
encontra a classe TesteJar.

g.
Isso é feito concatenando o ponto ( . ) no CLASSPATH; no Windows, a concatenação é feita utilizando ponto e
in
virgula (;) e no Linux utilizando dois pontos ( : ) .
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 298


12.7 Diagrama de componentes
Um componente oferece uma visão da funcionalidade de um conjunto de artefatos nele contidos.
Artefatos podem ser: arquivos de configuração, internacionalização, diretórios, classes ou até mesmo
pacotes.

Componentes são representados na UML da seguinte forma:

r
.b
Diagrama 12.8 - exemplo de componente

m
Os artefatos podem, ou não, ser exibidos dentro de um componente.

co
g.
in
nn

Diagrama 12.9 - representando artefatos dentro de um componente


ai

Existem alguns estereótipos freqüentemente utilizados para componentes. Abaixo são apresentados alguns deles:
.tr

<<executable>>: Utilizado para representar componentes executáveis.


w

Diagrama 12.10 - componente executável


w

<<library>>: Utilizado para representar bibliotecas, ou APIs.


w

Diagrama 12.11 - biblioteca de componentes

Trainning Education Services - Todos os direitos reservados 299


<<WAR>>: Utilizado para representar aplicações Web JavaEE (Web ARchive).

Diagrama 12.12 - componente web


<<EJBSession>> : Utilizado para representar componentes de negócio Java EE Enterprise Java Beans do tipo
Session.

r
.b
Diagrama 12.13 - componente EJB session bean

m
Dependência entre componentes

co
A dependência entre componentes é representada na UML com a mesma seta utilizada para representar a
dependência entre classes e pacotes, isto é, uma seta pontilhada ligando os componentes como pode ser visto no
seguinte diagrama:
g.
in
nn

Diagrama 12.14 - dependência entre componentes

Desta forma, fica indicado que para a AplicacaoWeb funcionar é necessário ter a biblioteca dateutils.jar.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 300


12.9 Certificação Oracle Certified Java Programmer
(OCJP)
1. Select the most appropriate answer. A method without any modifier is accessible
to: (1 answer)
A) any class
B) any class within the same package
C) any class within the same file
D) any subclass of this class.

r
.b
2. Which of the modifiers of member methods and member variables allows access to all subclasses?
(select 2 answers)

m
A) public
B) private

co
C) protected
D) No modifier(default)

3. Given two files:

1. package aj2.cap12.cert;
2.
g.
in
3. public class Util {
4. public static final int MY_CONSTANT = 2;
5. public static int doCalculation(int param) {
nn

6. return (param++) * param;


7. }
8. }

1. import aj2.cap12.cert.Util.*;
ai

2. import java.lang.System.out;
3. public class UtilClient {
4. public static void main(String[] args) {
5. out.println(doCalculation(MY_CONSTANT));
.tr

6. }
7. }
w

What is the result? (1 answer)


A) 4
w

B) 6
C) 9
w

D) Compilation fails.
E) An exception is thrown at runtime.

Trainning Education Services - Todos os direitos reservados 302


CAPÍTULO

13

r
.b
m
co
g.
in
nn
ai

Tratamento de erros
.tr

Exceptions
Tratamento de Exceções
w

Sobrescrita de métodos e lançamento de exceções


Assertions
w
w

Trainning Education Services - Todos os direitos reservados 303


13 Tratamento de erros
O tratamento de erros é uma característica fundamental para sistemas de software, porque é praticamente
impossível criar uma aplicação totalmente livre de erros.

Erros não são necessariamente causados por falhas no desenvolvimento.


Veja alguns exemplos:
• um servidor de banco de dados pode estar fora do ar;

r
• um arquivo de configuração pode ter sido removido acidentalmente;

.b
• o usuário pode ter digitado um valor não aceitável.

m
Não tratar os erros oriundos dessas situações previsíveis é considerada uma falha no desenvolvimento do
software, portanto, é necessário “preparar algumas respostas” para essas situações.

Se o banco de dados estiver fora do ar, o que deve ser feito?

co
[ ] A mensagem de erro deve ser impressa na console.
[ ] A mensagem de erro deve ser impressa em uma área visível pelo usuário
(Interface Gráfica, Aplicações Web, etc..).
g.
[ ] Um e-mail deve ser enviado para o administrador do banco de dados.
[ ] A operação deve ser logada em arquivo.
in
[ ] Os dados do usuário devem ser temporariamente salvos em arquivo.
[ ] Outras.________________________________________________________.
nn

Não existe uma única resposta para esta pergunta, pois ela simplesmente dependerá da situação. O que não
pode ser feito é ignorar o erro e continuar o processamento normal do programa, como se nada tivesse
acontecido.
ai
.tr

Infelizmente verifica-se que é muito comum não se dar atenção ao tratamento de erros em
aplicações. Por isso, é importante reforçar aqui a necessidade do planejamento no
tratamento de erros.
w
w
w

Trainning Education Services - Todos os direitos reservados 305


13.1 Exceções
Uma exceção é a indicação de que algum problema ocorreu durante a execução do programa. Chama-se de
tratamento de exceções ou tratamento de erros o mecanismo de sinalização de erros na plataforma Java.

Java define um conjunto de classes que representam erros. Como existe uma grande diversidade de erros
possíveis, existem muitos tipos nativos da linguagem, cada um tratando um conjunto específico de problemas.
Tais exceções usualmente são definidas dentro de cada um dos pacotes, podendo ser subdivididas em diversos

r
conjuntos.

.b
O pacote java.io, por exemplo, possui uma família de classes de exceção derivadas de IOException e o
pacote java.sql contém uma família derivada de SQLException.

m
Através da extensibilidade oferecida pela linguagem, é possível criar tipos próprios (classes) de exceções e, para

co
isso basta estender a classe java.lang.Exception.

Cada método pode lançar uma ou mais exceções, ou seja, em vez de retornar um valor (ou simplesmente
g.
terminar a execução normalmente e retornar para o ponto em que o método foi chamado), o método sinaliza o
código chamador, informando que aconteceu algo inesperado. O mecanismo de tratamento de erros em Java
permite reconhecer esta sinalização e executar alguma ação de tratamento do erro ocorrido.
in
Conheça agora a hierarquia de classes de exceções em Java e o funcionamento detalhado do mecanismo de
nn

sinalização e tratamento de erros.

13.1.1 Hierarquia das classes de erro


ai

Embora o tratamento de erros esteja associado à idéia de Exceptions, existe uma super classe de Exception
denominada Throwable que, como diz o próprio nome, representa algo que pode ser lançado, interrompendo a
.tr

execução de um método.
w

Veja a hierarquia simplificada das classes de exceção:


w
w

Diagrama 13.1 - Hierarquia das classes de erro

Trainning Education Services - Todos os direitos reservados 306


A classe Throwable pertence ao pacote java.lang e é a superclasse de todas as classes que podem ser
utilizadas para sinalização de erros em Java. Esta sinalização de erro é denominada lançamento, por isso é
comum utilizar a expressão lançamento de exceções para indicar a ocorrência e sinalização de uma exceção ou
erro.

As principais subclasses de Throwable, que definem a sua própria hierarquia são java.lang.Error e
java.lang.Exception.

r
.b
13.1.2 A classe Error
A classe Error representa condições anormais graves e geralmente irrecuperáveis. Geralmente, os aplicativos não

m
precisam se preocupar com o tratamento destes erros.

co
As principais subclasses de java.lang.Error encontradas no pacote java.lang são:
• ExceptionInInitializerError: lançado pela JVM para reportar falha de inicialização de variável


g.
static ou falha em um bloco de inicialização (não confundir com construtor);
StackOverflowError: lançado pela JVM para reportar o uso excessivo da pilha de métodos devido
a alguma recursividade muito profunda (normalmente infinita);
in
• NoClassDefFoundError: lançado pela JVM para reportar falha de localização de um arquivo .class
(normalmente trata-se de um problema na composição do classpath);
nn

• AssertionError: lançado pela JVM para reportar uma condição de assertiva falsa (veja detalhes
mais adiante).
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 307


13.1.3 A classe Exception
A classe Exception representa os erros que devem ser tratados pelo aplicativo. Estes erros podem ser
classificados em:
• checked exceptions: são exceções que devem ser tratadas no código. São denominadas checked
(verificadas) porque o compilador verifica se o desenvolvedor programou operações para tratar estes
erros, e,caso ele não tenha feito isso, é gerado um erro de compilação. Normalmente representam erros
que fogem ao controle do programador, não podendo ser evitados, mas apenas tratados quando ocorrem.
• runtime exceptions: são exceções que não são verificadas pelo compilador, ou seja, não possuem

r
tratamento obrigatório. Normalmente representam erros do próprio programador, que podem ser evitados

.b
com código robusto. São subclasses de RuntimeException.

m
co
g.
in
nn

Diagrama 13.2 - Algumas classes da hierarquia de Exception


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 308


13.1.4 RuntimeExceptions
São exceções que normalmente representam erros do programador e podem ser evitadas com códigos robustos.

Todas as exceções derivadas da classe RuntimeException são chamadas de unchecked exceptions, porque,
ao contrário das subclasses de Exception, o compilador não verifica se foi criado um código de tratamento para
elas.

Veja alguns exemplos no diagrama de classes a seguir:

r
.b
m
co
g.
in
nn

Diagrama 13.3 - Algumas classes da hierarquia de RuntimeException


ai

Alguns exemplos de RuntimeException são:


• NullPointerException: é lançado quando se tenta acessar um atributo ou chamar um método
.tr

através de uma variável que não aponta para nenhum objeto, isto é, tem o valor null;
• ArrayIndexOutOfBoundsException: ocorre quando se acessa uma posição que não existe em
w

um array;
• ArithmeticException: operações matemáticas podem gerar erros. Exemplo: dividir qualquer
w

número inteiro por zero;


• ClassCastException: exceção gerada na operação de cast de objetos. A operação pode estar
w

inválida não havendo como detectar em tempo de compilação;


• NumberFormatException: exceção gerada na conversão de String para qualquer outro tipo
numérico.

Trainning Education Services - Todos os direitos reservados 309


Veja um exemplo de código em que ocorre uma RuntimeException:

1. package br.com.trainning.exemplos;
2.
3. public class ExemploRuntimeException {
4. public static void main(String[] args) {
5. int i = 23;
6. int j = 0;
7. double res = i / j;

r
8. System.out.println(i + " / " + j + " = " + res);

.b
9.
10. }
11.}

m
Código 13.1 - ExemploRuntimeException.java

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 310


13.2 Tratamento de exceções
Antes de estudar as instruções utilizadas pelo Java para tratamento de exceções é importante entender a
estratégia criada na linguagem para isso. A figura a seguir ilustra esta estratégia:

r
.b
m
co
Diagrama 13.4 - arquitetura de exceptions
g.
A criação da exception é feita criando uma instância da classe desejada utilizando a instrução new.
in
Exception e = new Exception();
nn

A exceção criada é lançada através da instrução throw.


throw e;

O método avisa a possibilidade de lançamento de uma Exception utilizando a instrução throws em sua
ai

declaração.
public void metodoQueLançaException() throws Exception { }
.tr

Para capturar uma exceção, isto é, programar uma operação que seja executada caso a exceção ocorra, utiliza-se
w

as instruções try-catch.
try {
obj.metodoQueLancaException();
w

} catch (Exception ex) {


// codigo de tratamento da exceção
w

Trainning Education Services - Todos os direitos reservados 312


A seguir são apresentadas cada uma destas instruções.

13.2.1 A instrução throw


Para lançar uma exceção utiliza-se a instrução throw, seguida do objeto que a representa. Este objeto pode ser
instanciado no momento do lançamento ou pode ser utilizada uma variável já existente.

Sintaxe da instrução throw


throw new TipoException();

r
ou

.b
throw variavelDoTipoException;

m
Veja a seguir a criação e lançamento de uma exceção: a classe ExemploLancaRuntimeException lança uma
exceção se não receber nenhum parâmetro de entrada no método main, caso contrário, imprime o parâmetro
recebido.

co
1. package br.com.trainning.exemplos;
2.
3. public class ExemploLancaRuntimeException {
4.
5.
public static void main(String[] args) {
if(args.length > 0) {
g.
in
6. System.out.println("Valor do parametro recebido = " + args[0]);
7. } else {
8. throw new RuntimeException();
9. }
nn

10. }
11.}

Código 13.2 - ExemploLancaRuntimeException.java


ai
.tr
w
w

Perceba que foi lançada uma exceção do tipo java.lang.RuntimeException e uma mensagem de erro foi
w

impressa na console. Este formato de mensagem que foi impressa é denominado stackTrace.

Trainning Education Services - Todos os direitos reservados 313


Neste caso o código executou normalmente até o final.

r
.b
No exemplo utilizado foi lançada uma RuntimeException, que é uma unchecked exception, e isso significa que
o compilador ignora a exceção, sem verificar se existe um tratamento, ou mesmo se o método em que ela ocorre
sinaliza a possibilidade de lançamento da exceção ao código chamador. A seguir, a classe foi alterada para lançar

m
uma checked exception.

co
1. package br.com.trainning.exemplos.erros;
2.
3. public class ExemploLancaException {
4. public static void main(String[] args) {
5.
6.
7.
8.
if(args.length > 0) { g.
System.out.println("Valor do parametro recebido = " + args[0]);
} else {
throw new Exception();
in
9. }
10. }
11.}
nn

Código 13.3 - ExemploLancaException.java sem sinalização da possibilidade de lançamento da exceção


ai
.tr
w
w

Como neste exemplo a exceção é checked o compilador acusa um erro, porque não foi feita a sinalização no
w

método da possibilidade de lançamento da exceção. Esta sinalização é feita através da instrução throws na
declaração do método. Veja como isso é feito a seguir.

Trainning Education Services - Todos os direitos reservados 314


13.2.2 A instrução throws
Os erros que devem ser tratados são lançados em métodos ou construtores de classes, contudo é necessário
sinalizar tal possibilidade para que o desenvolvedor possa se precaver e tratá-los de acordo. A indicação que
estas falhas podem acontecer são definidas pela existência da instrução throws na assinatura do método,
conforme a sintaxe a seguir:

Sintaxe da instrução throws


<modificadores> <tipo de retorno> nomeDoMetodo(<parametros>) throws <lista de

r
exceptions> {

.b
// Instruções
}

m
Sintaxe para declaração da <lista de exceptions>
tipoException, ..., tipoException

co
No próximo exemplo é utilizada a classe File que faz parte do pacote java.io. Esta classe é utilizada para
manipulação de arquivos e diretórios. Seu construtor recebe uma String representando o nome de um arquivo,
e o método createNewFile() é utilizado para criá-lo. No entanto, analisando-se o javadoc da classe File e o
g.
método que será usado, percebe-se que uma IOException poderá ser lançada: esta é uma checked exception
e, como já foi visto, é preciso tratar o erro.
in
nn
ai
.tr
w
w
w

Figura 13.1 - javadoc do método createNewFile da classe java.io.File

Trainning Education Services - Todos os direitos reservados 315


Importante
Observe com cuidado a documentação do método. Além de IOException, a
documentação diz que SecurityException pode ser lançada, porém isto não está
sinalizado na declaração do método através da instrução throws. Isto ocorre porque
SecurityException é uma RuntimeException. Conforme foi visto no exemplo da
classe ExemploLancaRuntimeException (Código 13.2), não é necessário sinalizar o
lançamento de unchecked exceptions.

r
.b
Tente utilizar o método sem se preocupar em tratar o erro e compilar a classe para entender melhor o problema.

m
1. package br.com.trainning.util.erros;
2.

co
3. import java.io.File;
4.
5. public class CriadorArquivos {
6.
7. public void criarArquivo(String name) {
8.
9.
10.
// com o nome name
File f = new File(name);
g.
// Criação de um objeto da classe File representando o arquivo
in
11. // Tentativa de criar um arquivo em disco
12. f.createNewFile();
13. }
14 }
nn

Código 13.4 - CriadorArquivos.java


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 316


Este erro indica que a exceção IOException, que pode ser lançada na execução do método createNewFile,
deverá ser tratada (try-catch), ou então propagada (relançada) através da instrução throws.

Há duas alternativas para corrigir este problema:


• Declara-se na assinatura do método que, caso a exceção ocorra, ela deverá ser relançada para o
método que chamou o método criarArquivo;
• Coloca-se o pedaço do código que pode gerar erro dentro da estrutura de tratamento try-catch
apropriada.

r
.b
Veja, primeiramente, como indicar que a exceção deverá ser relançada com a utilização da instrução throws.

m
1. package br.com.trainning.util;
2.

co
3. import java.io.File;
4. import java.io.IOException;
5.
6. public class CriadorArquivos {
7.
8.
9.
10.
11.
g.
public void criarArquivo(String name) throws IOException {
// Criação de um objeto da classe File representando o arquivo
// com o nome name
File f = new File(name);
in
12. // Tentativa de criar um arquivo em disco
13. f.createNewFile();
14. }
nn

15.}

Código 13.5 - CriadorArquivos.java relançando IOException


ai

Neste caso, está se “jogando a batata quente” para o método que chamou, ou seja, se o erro acontecer, ele não
será tratado, mas simplesmente relançado para a classe que chama este método que, por sua vez, irá enfrentar o
.tr

mesmo problema. Veja abaixo:


w

1. package br.com.trainning.util;
2.
3. public class TesteCriadorArquivosSemTratamentoErro {
4.
w

5. public static void main(String[] args) {


6. CriadorArquivos ca = new CriadorArquivos();
7. ca.criarArquivo("teste.txt");
w

8. }
9.}

Código 13.6 - TesteCriadorArquivosSemTratamentoErro.java

Trainning Education Services - Todos os direitos reservados 317


r
.b
m
A mensagem é clara e, desta vez, não adiantará simplesmente relançar o erro para quem chamou o método main
(a JVM). Portanto, é preciso tratar o erro, como será visto a seguir.

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 318


13.2.3 A estrutura try / catch
Programar um código para tratamento de exceções consiste nos seguintes passos:
1) Delimitar o bloco de código em que pode ser lançada uma exceção. Este bloco é delimitado através da
instrução try.
2) Escrever um bloco de código que deve ser executado caso ocorra a exceção. Este bloco é delimitado através
da instrução catch, e é denominado bloco de tratamento de exceção. Como a instrução catch recebe um
tipo específico de exceção como parâmetro, diz-se que ela captura uma exceção.

r
Sintaxe para bloco de tratamento de exceções

.b
try {
// instruções que podem gerar/lançar exceções

m
} catch (TipoException e) {
// código que deverá ser executado caso uma Exception seja lançada
}

co
Qualquer tipo de Throwable pode ser capturado utilizando-se a instrução catch, incluindo todos os tipos de
Error, Exception e RuntimeException.
g.
Veja o que ocorre se qualquer parte do código dentro do bloco try lançar uma exceção da classe especificada,
in
ou derivada da classe especificada na instrução catch,:

• O programa para a execução do código na linha em que ocorreu o lançamento da exceção;


nn

• O programa executa o código de manipulação de exceções dentro do bloco da instrução catch.

Se o programa não lançar uma exceção dentro do bloco try, então o código dentro do bloco da instrução catch
ai

não será executado.


.tr

No entanto, se o código dentro do bloco try gerar uma exceção diferente da especificada na cláusula catch,
então o método é finalizado imediatamente. Com sorte, o chamador terá uma cláusula catch capaz de capturar o
w

tipo de exceção gerada.

Veja agora a correção do problema encontrado no exemplo da classe CriadorArquivos e


w

TesteCriadorArquivos, tratando a IOException na classe TesteCriadorArquivos.


w

Trainning Education Services - Todos os direitos reservados 319


1. package br.com.trainning.util;
2.
3. import java.io.IOException; 4.

5. public class TesteCriadorArquivos {


6.
7. public static void main(String[] args) {
8. try {
9. CriadorArquivos ca = new CriadorArquivos();
10. ca.criarArquivo("teste.txt");

r
11. } catch (IOException e) {

.b
12. System.out.println("---------- Tratamento do Erro ---------");
13. System.out
14. .println("Nao foi possível criar o arquivo! "+e.getMessage());
15. System.out.println("--------------------------------------");

m
16. }
17. }
18.}

co
Código 13.7 - TesteCriadorArquivos.java com tratamento de exceções

g.
Agora a compilação e execução da classe serão bem sucedidas, e caso aconteça uma IOException na criação
do arquivo, todas as mensagens do bloco catch serão impressas.
in
Voltando ao exemplo anterior ExemploRuntimeException (Código 13.1), observe como alterar o código
para que a mensagem de erro gerada pela JVM não seja impressa, e para que se apresente uma mensagem de
nn

erro adequada.

1. package br.com.trainning.exemplos.exceptions;
ai

2.
3. public class ExemploRuntimeException {
4.
5. public static void main(String[] args) {
.tr

6. int i = 23;
7. int j = 0;
8. try {
w

9. double res = i / j;
10. // Impressão do resultado da divisão
11. System.out.println(i + " / " + j + " = " + res);
w

12. } catch (ArithmeticException e) {


13. System.out.println("Divisao invalida! ");
14. }
15. }
w

16.}

Código 13.8 - ExemploRuntimeException.java com tratamento de exceptions

Trainning Education Services - Todos os direitos reservados 320


r
A classe Throwable define alguns métodos herdados pela classe Exception, que são úteis no tratamento de

.b
exceções.

m
Método printStackTrace( )
Este método é bastante útil para os desenvolvedores ou responsáveis pela manutenção do sistema porque dá

co
uma visão detalhada do erro, indicando qual o método que originou a exceção, assim como, cada um dos
métodos que a chamaram, além de mostrar a localização da linha responsável pelo lançamento da exceção. Essa
informação é impressa na console e é chamada de stack trace (histórico de passagens) da exceção.

Método getMessage( ) g.
Este método retorna apenas a mensagem da exceção que é definida no momento da construção da Exception,
in
utilizando o construtor que recebe uma String como parâmetro.

Normalmente a stack trace da exceção não é impressa para o usuário, porque esta informação é útil apenas para
nn

o desenvolvedor / administrador. O método getMessage, por sua vez, não é muito útil para fazer depuração de
aplicações.
ai

Veja a seguir um exemplo da utilização dos métodos getMessage() e printStackTrace().


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 321


1. package br.com.trainning.exemplos.exceptions;
2.
3. public class ExemploMetodosThrowable{
4.
5. public static void main(String[] args) {
6. int i = 23;
7. int j = 0;
8.
9. try {
10. double res = i / j;
11. // Impressão do resultado da divisão

r
12. System.out.println(i + " / " + j + " = " + res);
13. } catch (ArithmeticException e) {

.b
14. System.out.println("---------- Tratamento do Erro ---------");
15. System.out.println("Mensagem de erro para o usuario:");
16. System.out.println("Divisao invalida! " + e.getMessage());

m
17. System.out.println("\nSTACK TRACE:");
18. e.printStackTrace();
19. System.out.println("--------------------------------------");
20. }

co
21. }
22.}
Código 13.9 - ExemploMetodosThrowable.java

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 322


13.2.4 A instrução finally
Usualmente, este bloco é utilizado para códigos clean-up. Operações como fechar um arquivo ou uma conexão
com o servidor são exemplos de operações de clean-up.

Quando um código lança uma exceção, ele interrompe o fluxo de execução. Contudo, isso é um problema quando
o código utiliza recursos que precisam ser descartados, como por exemplo, conexões com o banco de dados.

Para evitar repetição de código na estrutura try / catch, existe a estrutura finally, que será executada

r
sempre, independentemente do método ter gerado ou não uma exceção.

.b
Sintaxe para utilização da instrução finally:

m
try {
// instruções que podem gerar/lançar exceções
} catch (TipoException e) {

co
// código que deverá ser executado caso uma exceção seja lançada
}
finally {

}
// liberação de recursos, log, etc.

A seguir é descrito o fluxo de execução para diversas situações.


g.
in
Quando o código declarado no bloco try não lança nenhuma exceção:
nn

• o bloco try é executado normalmente.;


• o bloco finally é executado em seguida.
ai

Quando o código lança uma exceção que é capturada na estrutura catch:


• código do bloco try é executado até que a exceção seja disparada;

.tr

execução do bloco try é interrompida;


• execução do código da instrução catch;
• código da instrução finally é executado.
w

Quando o código lança uma exceção que não é capturada por nenhuma estrutura catch:
w

• código do bloco try é executado até que a exceção seja disparada;


• execução do bloco try é interrompida;
w

• código da instrução finally é executado.

Trainning Education Services - Todos os direitos reservados 323


1. package br.com.trainning.exemplos.exceptions;
2.
3. public class ExemploFinally{
4.
5. public static void main(String[] args) {
6. int i = 23;
7. int j = 0;
8.
9. try {
10. double res = i / j;

r
11. // Impressão do resultado da divisão

.b
12. System.out.println(i + " / " + j + " = " + res);
13. }
14.
15. catch (ArithmeticException e) {

m
16. System.out.println("---------- Tratamento do Erro ---------");
17. System.out.println("Mensagem de erro para o usuario:");
18. System.out.println("Divisao invalida! " + e.getMessage());
19. System.out.println("\nSTACK TRACE:");

co
20. e.printStackTrace();
21. System.out.println("--------------------------------------");
22. }
23.
24.
25.
26.
27. }
finally {

}
System.out.println("Passou pelo finally");
g.
in
28.}

Código 13.10 - ExemploFinally.java


nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 324


r
Conclusão: O código do bloco finally é SEMPRE executado!

.b
Importante

m
A estrutura de tratamento de exceções pode ser constituída por uma instrução try e uma
instrução finally, sem a presença da instrução catch. Veja o exemplo de código a seguir:

co
1. public class ExemploTryFinally {
2.
3.
4.
public static void main(String[] args) {
int i = 23;
int j = 0;
g.
in
5.
6. try {
7. double res = i / j;
8. // Impressão do resultado da divisão
nn

9. System.out.println(i + " / " + j + " = " + res);


10. } finally {
11. System.out.println("Passou pelo finally");
12. }
13. }
ai

14.}

Código 13.11 - ExemploTryFinally.java


.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 325


13.2.5 Capturando múltiplas exceções
É comum haver trechos de código que podem gerar diferentes tipos de exceções.

Em muitos casos cada tipo de erro terá um tratamento diferente. Para conseguir este tratamento diferenciado são
utilizadas diversas instruções catch, uma para cada exceção.

Sintaxe para captura de múltiplas exceções


try {

r
// instruções que podem gerar/lançar exceptions

.b
}
catch (TipoDaExcecao1 e) {
// logs, codigo

m
}
catch (TipoDaExcecao e) {
// logs, codigo

co
}
finally { //opcional
// liberacao de recursos, log, etc...
} g.
Pode-se colocar quantas instruções catch forem necessárias, contudo existem duas condições para organizá-las:
in
• não é permitido colocar instruções catch para checked exceptions que não têm possibilidade de
nn

serem lançadas, ou seja, não foram declaradas por nenhum método;


• declaram-se primeiramente as exceções mais específicas, isto é, as classes filhas e, depois, as mais
genéricas.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 326


1. package br.com.trainning.exemplos.exceptions;
2.
3. public class ExemploMultiplasExceptions {
4.
5. public static void main(String[] args) {
6. try {
7. String num1 = args[0];
8. String num2 = args[1];
9. int i = Integer.parseInt(num1);
10. int j = Integer.parseInt(num2);

r
11. double res = i / j;

.b
12. System.out.println(i + " / " + j + " = " + res);
13. } catch (ArithmeticException e) {
14. System.out.println("---------- Tratamento do Erro ---------");
15. System.out.println("Mensagem de erro para o usuario:");

m
16. System.out.println("Divisao invalida! " + e.getMessage());
17. System.out.println("\nSTACK TRACE:");
18. e.printStackTrace();
19. System.out.println("--------------------------------------");

co
20. } catch (NumberFormatException e) {
21. System.out.println("---------- Tratamento do Erro ---------");
22. System.out.println("Mensagem de erro para o usuario:");
23. System.out.println("Dados invalidos! " + e.getMessage());
24.
25.
26.
27.
System.out.println("\nSTACK TRACE:");
e.printStackTrace();
g.
System.out.println("--------------------------------------");
} catch (ArrayIndexOutOfBoundsException e) {
in
28. System.out.println("----------Tratamento do Erro ---------");
29. System.out.println("Mensagem de erro para o usuario:");
30. System.out.println("Digite dois parametros no main! "+e.getMessage());
nn

31. System.out.println("\nSTACK TRACE:");


32. e.printStackTrace();
33. System.out.println("--------------------------------------");
34. } finally {
35. System.out.println("Passou pelo finally");
ai

36. }
37. }
38.}
.tr

Código 13.12 - ExemploMultiplasExceptions.java


w
w
w

Trainning Education Services - Todos os direitos reservados 327


r
.b
m
Todas as exceções podem ser tratadas de uma única vez, fazendo catch da classe Exception, que é a

co
superclasse de todas. Com isso, não haveria preocupação com o tipo de exceção que está sendo lançada por
cada método. No entanto, esta prática não é recomendada, porque qualquer que seja o erro, a mesma ação será
executada.
g.
Outra opção, disponível a partir do Java 7, quando o tratamento de várias exceções deve ser o mesmo, é utilizar o
recurso denominado multi-catch.
in
Sintaxe para multi-catch
nn

try {
// instruções que podem gerar/lançar exceptions
}
catch (TipoDaExcecao1 | TipoDaExcecao2 | TipoDaExcecao3 e) {
ai

// logs, codigo
}
.tr

finally { //opcional
// liberacao de recursos, log, etc...
}
w
w
w

Trainning Education Services - Todos os direitos reservados 329


1 package
br.com.trainning.exemplos.exceptions; 2
3 public class ExemploMultiCatch {
4 public static void main(String[] args) {
5 try {
6 String num1 = args[0];
7 String num2 = args[1];
8 int i = Integer.parseInt(num1);
9 int j = Integer.parseInt(num2);
10 double res = i / j;
11 System.out.println(i + " / " + j + " = " + res);

r
12 } catch (ArithmeticException | NumberFormatException |
13 ArrayIndexOutOfBoundsException e ) {

.b
14 System.out.println("---------- Tratamento do Erro ---------");
15 System.out.println("Ocorreu o seguinte erro:"
16 + e.getClass().getName());
17 System.out.println("Com a seguinte mensagem : " + e.getMessage());

m
18 System.out.println("\nSTACK TRACE:");
19 e.printStackTrace();
20 System.out.println("--------------------------------------");

co
21 } finally {
22 System.out.println("Passou pelo finally");
23 }
24 }
25 }
g.
Código 13.13 - ExemploMultiCatch.java
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 330


13.2.7 Criando suas próprias exceções
Existe uma grande quantidade de tipos de exceções disponíveis no Java, mas existem casos nos quais é
necessário criar classes de exceções para erros específicos do negócio para o qual se desenvolve um aplicativo.
Estas exceções são comumente denominadas exceções de aplicativo.

Por exemplo: espera-se que o usuário entre com uma idade válida, mas recebe-se o número 1000. Neste caso
pode ser criada uma exceção DadosInvalidosException que será lançada sempre que um usuário fornecer
dados inválidos.

r
.b
É uma boa prática tentar sempre reutilizar as próprias exceções fornecidas pela linguagem. Apenas em casos nos
quais nenhuma das exceções pré-existentes é aplicável deve ser criada uma exceção customizada.

m
Lembre sempre que a classe Exception é uma classe como outra qualquer, portanto filha de Object. Dessa

co
maneira, fica fácil entender que para criar uma nova classe de Exception basta apenas estendê-la, como seria
feito com qualquer outra.

1. package br.com.trainning.exceptions;
2.
g.
in
3. public class NumeroInvalidoException extends Exception {
4.
5. }
nn

Código 13.14 - NumeroInvalidoException.java

Uma funcionalidade útil na criação de exceções customizadas é permitir que o código de tratamento de erros
ai

recupere uma mensagem de erro descritiva da exceção. Isto pode ser feito através do método getMessage(),
herdado de Throwable, mas como inicializar a mensagem para o valor desejado? A única forma de fazer isso é
.tr

passar a mensagem por meio do construtor da superclasse, à classe Exception definindo um construtor na
classe que deriva Exception, e na primeira linha passar a mensagem de erro fazendo a chamada ao
w

super(String message). Veja como é possível fazer isso:


w
w

Trainning Education Services - Todos os direitos reservados 333


1. package br.com.trainning.exceptions;
2.
3. public class NumeroInvalidoException extends Exception {
4.
5. public NumeroInvalidoException(String mensagem) {
6. super(mensagem);
7. }
8.
9.}
Código 13.15 - NumeroInvalidoException com construtor para mensagem

r
.b
Veja que na classe Endereco apresentada a seguir, será validado o número da rua que deverá ser maior do que
zero, caso contrário o método lançará uma Exception chamada NumeroInvalidoException.

m
1. package br.com.trainning.model;

co
2.
3. import br.com.trainning.exceptions.NumeroInvalidoException;
4.
5. public class Endereco {
6. private String rua;
7.
8.
9.
10.
private int numero; g.
// Como o construtor chama o método setNumero é necessário indicar na
// assinatura que ele pode lançar uma exception NumeroInvalidoException
public Endereco(String rua, int numero) throws NumeroInvalidoException {
in
11. this.setRua(rua);
12. this.setNumero(numero);
13. }
nn

14. public void setNumero(int numero) throws NumeroInvalidoException {


15. if (numero > 0) {
16. this.numero = numero;
17. } else {
18. throw new NumeroInvalidoException(numero + " nao e valido! ");
ai

19. }
20. }
21. public void setRua(String rua) {
22. this.rua = rua;
.tr

23. }
24. public String getRua() {
25. return rua;
26. }
w

27. public int getNumero() {


28. return numero;
29. }
w

30.}

Código 13.16 - Endereco.java


w

Trainning Education Services - Todos os direitos reservados 334


Todos os métodos ou construtores que utilizarem o método setNumero (neste caso, o construtor da classe
Endereco) deverão tratar a exception NumeroInvalidoException ou então declará-la na assinatura do
método, para que, caso a exception aconteça, ela seja relançada.

1. package br.com.trainning.model;
2.
3. import br.com.trainning.exceptions.NumeroInvalidoException;
4.
5. public class TesteEnderecoRelancandoErro {

r
6.
7. public static void main(String[] args) throws NumeroInvalidoException {

.b
8. Endereco e = new Endereco("Av. Jabaquara", 0);
9. }
10.}

m
Código 13.17 - TesteEnderecoRelancandoErro.java

co
1. package br.com.trainning.model;
2.
3. import br.com.trainning.exceptions.NumeroInvalidoException;
4.
5. public class TesteEnderecoTratandoErro {
6.
7.
8.
public static void main(String[] args) {
try {
g.
in
9. Endereco e = new Endereco("Av. Jabaquara", 0);
10. } catch (NumeroInvalidoException e) {
11. e.printStackTrace();
nn

12. }
13. }
14.}

Código 13.18 - TesteEnderecoTratandoErro.java


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 335


13.2.8 Piores Práticas

Classes de exceção servem para modelar a representação de problemas que ocorrem na


execução de aplicações Java.

Não se deve incluir em uma classe de exceção nenhuma rotina de tratamento de erros pois:

• Durante o ciclo de vida de um projeto a política de tratamento de erros pode


mudar

r
• Uma mesma classe de exceção pode ser aproveitada em vários projetos, cada um

.b
com sua política de tratamento de erros

O tratamento de erros sempre deve ser programado em blocos try-catch.

m
1. package br.com.trainning.exceptions;
2.
3. public class GlobalcodeException extends Exception {

co
4.
5. public GlobalcodeException(String mensagem, Exception e) {
6. super(mensagem, e);
7. e.printStackTrace();
8.
9.
10.
11.
}
this.print();
// Envia e-mail para o responsável

public GlobalcodeException(String mensagem) {


g.
in
12. super(mensagem);
13. // Envia e-mail para o responsável
14. }
nn

15.
16. public void print() {
17. System.out.println("============== Tratando Erro ===============");
18. System.out.println(getMessage());
19. System.out.println("PrintStackTrace: ");
ai

20.
21. // Obtivemos a exceção causadora do problema passada como parametro
22. // no construtor
.tr

23. printStackTrace();
24. System.out.println("============ Fim do Tratamento =============");
25. }
26.}
w

Código 13.19 - GlobalcodeException.java com programação de tratamento de exceção embutido


w
w

Trainning Education Services - Todos os direitos reservados 336


13.2.9 Erros comuns

1. Capturar uma exceção que não pode ser lançada no bloco try

1. package br.com.trainning.exemplos.erros;
2.
3. import java.io.IOException;
4.
5. public class ExemploCatchInvalido {
6. public static void main(String[] args) {

r
7. try {
8. System.out.println("Dentro do bloco try");

.b
9. } catch (IOException e) {
10. e.printStackTrace();
11. }

m
12. }
13 }
Código 13.20 - ExemploCatchInvalido.java

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 337


2. Capturar múltiplas exceções sem seguir a ordem da mais específica para a mais
genérica.
Veja a seguir uma tentativa de captura de múltiplas exceções em que primeiro é feita a captura da
classe mais genérica (superclasse) em vez da mais específica (subclasse).

1. package br.com.trainning.exemplos.erros;
2.

r
3. public class ExemploMultiplasExceptions {
4. public static void main(String[] args) {

.b
5. int i = 23;
6. int j = 0;
7. try {
8. double res = i / j;

m
9. // Impressão do resultado da divisão
10. System.out.println(i + " / " + j + " = " + res);
11. } catch (RuntimeException e) {

co
12. System.out.println("Capturei uma RuntimeException");
13. } catch (ArithmeticException e) {
14. System.out.println("Divisao invalida! ");
15. }
16. }
17.} g.
Código 13.21 - ExemploMultiplasExceptions.java com captura de exceções inválida
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 338


13.3 Sobrescrita de métodos e lançamento de exceções
Quando se implementam métodos de interfaces, classes abstratas ou se faz sobrescrita de métodos é importante
lembrar das regras relativas à exceções. Na declaração do novo método, não podem ser lançadas exceções que
não existiam na declaração do método original. Assim, é possível:

• lançar as mesmas checked exceptions declaradas no método original;


• lançar uma parte das checked exceptions declaradas no método original, ou simplesmente não lançar
nenhuma exceção;

r
• lançar subclasses das checked exceptions declaradas no método original;

.b
• lançar quaisquer runtime exceptions

m
1. package br.com.trainning.teste;
2.
3. public interface Teste {

co
4.
5. public void metodoA() throws GlobalcodeException, java.text.ParseException;
6.}

g.
Código 13.22 - Teste.java

A seguinte implementação não é válida porque gera um erro de compilação: ela altera a assinatura do método
in
definido na interface Teste, lançando uma IOException em vez de GlobalcodeException, ou
ParseException.
nn

1. package br.com.trainning.teste;
2.
3. import java.io.*;
ai

4.
5. public class ClasseImplementadora implements Teste {
6.
.tr

7. public void metodoA() throws IOException {


8. System.out.println("metodoA");
9. }
10.}
w

Código 13.23 - ClasseImplementadora.java


w
w

Trainning Education Services - Todos os direitos reservados 339


r
.b
m
A seguinte implementação é válida, porque declara uma parte das exceções declaradas no método original, além
de declarar uma exceção unchecked.

co
1. package br.com.trainning.teste;
2.
3. public class OutraClasseImplementadora implements Teste {
4.
5.
6.
7. }
System.out.println("outro metodoA");
g.
public void metodoA() throws java.text.ParseException, NullPointerException {
in
8.}

Código 13.24 - OutraClasseImplementadora.java


nn

Veja outra implementação válida, porque lança uma subclasse de uma das exceções declaradas no método
original.
ai

1. package br.com.trainning.exceptions;
2.
.tr

3. public class AcademiaDoJavaException extends GlobalcodeException {


4. public AcademiaDoJavaException(String mensagem) {
5. super(mensagem);
w

6. }
7.}

Código 13.25 - AcademiaDoJavaException.java


w
w

Trainning Education Services - Todos os direitos reservados 340


1. package br.com.trainning.teste;
2.
3. public class MaisUmaClasseImplementadora implements Teste {
4.
5. public void metodoA() throws java.text.ParseException, AcademiaDoJavaException
6. {
7. System.out.println("mais um metodoA");
8. }
9.}
Código 13.26 - MaisUmaClasseImplementadora.java

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 341


13.5 Liberação automática de recursos
Um dos principais usos da cláusula finally é para liberar recursos alocados dentro do bloco try, como por exemplo,
fechar conexões com bancos de dados ou fluxos de escrita ou leitura de dados. Veja a seguir um exemplo de
código utilizando a classe java.io.FileWriter para escrever em um arquivo de texto. Não se preocupe com
os detalhes da classe, pois serão estudados em mais detalhes juntamente aos tópicos relacionados a I/O no
módulo AJ4.

1 package

r
br.com.trainning.exemplos.exceptions; 2

.b
3 import java.io.FileWriter;
4 import java.io.IOException;
5
6 public class ExemploTryTradicional {

m
7
8 public static void main(String[] args) {
9 String nomeArquivo = "arquivo1.txt";
10 FileWriter out = null;

co
11 try {
12 out = new FileWriter(nomeArquivo);
13 //escrita no arquivo
14 out.write("texto qualquer");
15 } catch (IOException ex) {
16
17
18
//tratamento do erro
} finally {
if (out != null) {
g.
in
19 try {
20 out.close();
21 } catch (IOException ex) {
22 //tratamento do erro ao fechar o fluxo
nn

23 }
24 }
25 }
26 }
27 }
ai

Código 13.27 - ExemploTryTradicional.java


.tr

O código apresenta alguns problemas:


• O desenvolvedor pode esquecer de adicionar uma cláusula finally para fechar a conexão;
• O método close lança IOException, sendo necessário chama-lo em um bloco try e fazer seu tratamento de
w

erro;
• Caso seja feito o relançamento da exceção dentro do bloco catch e dentro do bloco finally, a exceção
w

original vai ser “escondida” pela exceção do finally;


• A variável FileWriter deve ser declarada fora dos blocos try e finally, para poder ser manipulada em
w

ambos;

Trainning Education Services - Todos os direitos reservados 343


• O código é extremamente verboso, com a lógica de negócio escondida no meio do tratamento de erros e
fechamento de recursos.

A partir do Java 1.7 a instrução try foi aperfeiçoada com o suporte à liberação automática de recursos. Esse
recurso é denominado try-with-resources.

Sintaxe para try-with-resources


try (declaração de recursos) {
// instruções que podem gerar/lançar exceptions

r
}

.b
catch (TipoDaExcecao e) {
// tratamento de erros

m
}

A declaração de recursos consiste na declaração e inicialização dos objetos que devem ser fechados ao término

co
da execução do código. Vários objetos podem ser declarados, separados por ; (ponto e vírgula). Veja o mesmo
exemplo do código anterior utilizando a nova sintaxe:

1 package
br.com.trainning.exemplos.exceptions; 2
3 import java.io.FileWriter;
g.
in
4 import java.io.IOException;
5
6 public class ExemploTryWithResources {
nn

7 public static void main(String[] args)


{ 8 String nomeArquivo =
"arquivo1.txt";
9 try (FileWriter out = new FileWriter(nomeArquivo)){
10 //escrita no arquivo
11 out.write("texto qualquer");
ai

12 } catch (IOException ex) {


13 //tratamento do erro
14 }
15 }
.tr

16 }

Código 13.28 - ExemploTryWithResources.java


w

Nessa caso são resolvidos os problemas do código anterior:


• Não é necessário declarar o bloco finally, e o método close é chamado automaticamente pelo código,
w

eliminando a possibilidade de esquecimento do desenvolvedor;


• O mesmo bloco catch será executado caso ocorra uma exceção no bloco try ou ao fechar o canal de
w

escrita (método close());


• Não é necessário declarar a variável out fora do bloco try.

Trainning Education Services - Todos os direitos reservados 344


• O código é muito menor;
• Caso sejam lançadas exceções IOException no bloco try e no fechamento do canal de escrita, a exceção
de fechamento será suprimida e a exceção principal será lançada ao bloco catch. Caso seja necessário
recuperar a exceção suprimida basta utilizar o método getSuppressed() , adicionado à classe
Throwable no Java 1.7

Importante
Todas as classes que representam recursos que podem ser “fechados” automaticamente pelo

r
try-with-resources apresentam uma característica em comum. Todos implementam a interface

.b
java.lang.AutoCloseable, criada no Java 1.7. Um objeto que implementa essa interface
tem seu método close chamado ao final do bloco try, independente do lançamento de exceção,

m
eliminando a necessidade da chamada no bloco finally. Ou seja, o método close() é sempre chamado antes de
entrar nos blocos de tratamento de exceção.

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 345


13.6 Assertivas
O mecanismo de assertivas foi introduzido na plataforma Java a partir da versão 1.4. Por meio desse mecanismo
é possivel incluir testes no código durante as fases de desenvolvimento e testes, sem que seja necessário
removê-los no código final.

Uma assertiva é uma expressão booleana que deve retornar true somente se o seu código estiver funcionando
corretamente. Se a expressão retornar false um AssertionError é gerado, interrompendo o programa.

r
.b
As expressões de assertivas podem ser habilitadas ou desabilitadas via linha de comando, por isso não devem ser
utilizadas expressões envolvendo métodos que modificam o estado dos objetos.

m
Sintaxe para o uso de assertivas:

co
assert exprCondicional;
ou
assert exprCondicional : mensagem;
g.
Na segunda opção, caso a expressão condicional seja falsa, é gerado um AssertionError contendo a
in
mensagem de erro definida em mensagem. A mensagem não necessita ser uma String podendo ter qualquer
valor primitivo ou de objetos.
nn

Para exemplificar o uso de assertivas imagine um cenário bancário com as classes apresentadas no diagrama a
seguir:
ai
.tr
w
w
w

Diagrama 13.5 - cenário bancário para exemplo de assertions

Trainning Education Services - Todos os direitos reservados 346


A classe Conta é abstrata e possui duas subclasses: ContaCorrente e ContaPoupanca. O método
abrirConta, da classe Banco, é utilizado para criar instâncias de ContaCorrente e ContaPoupanca, de
acordo com o parâmetro tipo recebido e esse parâmetro é uma enumeração de nome TipoConta.

Veja a seguir o código para a enumeração TipoConta e a classe Banco. Observe que esta primeira versão da
classe Banco apresenta um erro no código, pois faltou a criação da instância de ContaPoupanca. Este erro será
percebido ao executar um código de teste com assertivas habilitadas.

r
.b
1. package br.com.trainning.teste;
2.
3. public enum TipoConta {
4. CONTA_CORRENTE, CONTA_POUPANCA

m
5. }

Código 13.29 - TipoConta.java

co
1. package br.com.trainning.teste;
2.
3. public class Banco {
4.
5.
6.
public Conta abrirConta(TipoConta tipo) {
Conta conta = null;
if(tipo==TipoConta.CONTA_CORRENTE) {
g.
in
7. conta = new ContaCorrente();
8. }
9. assert conta != null : "a conta nao foi criada!!";
10. return conta;
nn

11. }
12.}

Código 13.30 - Banco.java com erro de implementação


ai

1. package br.com.trainning.teste;
2.
.tr

3. public class TesteBanco {


4. public static void main(String[] args) {
5. Banco banco = new Banco();
6. Conta conta1 = banco.abrirConta(TipoConta.CONTA_POUPANCA);
w

7. System.out.println("Conta poupanca criada com sucesso");


8. Conta conta2 = banco.abrirConta(TipoConta.CONTA_CORRENTE);
9. System.out.println("Conta corrente criada com sucesso");
w

10. }
11.}
w

Código 13.31 - TesteBanco.java

Trainning Education Services - Todos os direitos reservados 347


Antes de observar a saída gerada pela execução do código é importante observar algumas características da
compilação e execução de código com assertivas, apresentadas nos próximos itens.

13.6.1 Compilação com assertivas


Um compilador java 1.5 considera por padrão assert como palavra reservada.
Um compilador java 1.4 por padrão não considera assert como palavra reservada (ou seja, é um identificador
válido). Neste caso, para habilitar o uso de assertivas é necessário compilar as classes utilizando a diretiva de
compilação –source 1.4:

r
javac –source 1.4 br/com/trainning/*.java

.b
Para ignorar assertivas, compilar com a diretiva de compilação –source 1.3:
• javac –source 1.3 br/com/trainning/*.java

m
13.6.2 Execução com assertivas
Para executar uma classe com assertivas utiliza-se as diretivas apresentadas na Tabela 13.1:

co
Tabela 13.1 - diretivas de linha de comando para assertivas

g.
in
nn
ai

As diretivas –ea e –da - são na verdade uma abreviação para –enableassertions e –disableassertions- ,
sendo que as duas formas são válidas. As diretivas de execução podem ser usadas em combinação
.tr

Exemplo: combinação de diretivas para assertivas


java –ea –da:br.com... br.com.trainning.teste.TesteBanco
w

Neste exemplo habilita-se assertivas em geral, mas elas são desabilitadas para o pacote br.com e seus
subpacotes.
w

13.6.3 Execução do código de exemplo


w

Após entender como habilitar a compilação e execução de códigos com assertivas é possivel executar e avaliar o
código de exemplo da classe TesteBanco.

Trainning Education Services - Todos os direitos reservados 348


r
.b
Ocorreu um AssertionError indicando que a conta não foi criada no código do método abrirConta. A seguir

m
é apresentado o código da classe Banco, com o erro corrigido.

co
1. package br.com.trainning.teste;
2.
3. public class Banco {
4. public Conta abrirConta(TipoConta tipo) {
5. Conta conta = null;
6.
7.
8.
9.
if(tipo==TipoConta.CONTA_CORRENTE) {
conta = new ContaCorrente();
} else {
conta = new ContaPoupanca();
g.
in
10. }
11. assert conta != null : "a conta nao foi criada!!";
12. return conta;
nn

13. }
14.}

Código 13.32 - Banco.java corrigido


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 349


13.7 Certificação Oracle Certified Java Programmer
(OCJP)
1. What is the output of the following code when compiled and run? Select one correct
answer.

1. import java.io.IOException;

r
2.

.b
3. public class Super {
4.
5. void method() throws IOException {
6. System.out.println("Inside Super");

m
7. throw new IOException();
8. }
9.
10. public static void main(String[] args) {

co
11. Base base = new Base();
12. try {
13. base.method();
14. } catch (IOException e) {
15.
16.
17.
18.}
}
}
System.out.println("Inside catch"); g.
in
19.
20. class Base extends Super {
21. void method() {
22. System.out.println("Inside Base");
nn

23. }
24. }
ai

A) Prints:
Inside Base
.tr

B) Prints:
Inside Super
C) Prints:
w

Inside Super
Inside catch
w

D) The code does not compile.


w

Trainning Education Services - Todos os direitos reservados 350


2. Consider the classes defined below:

1. import java.io.IOException;
2.
3. public class SuperFoo {
4.
5. public void methodOne(int a, int b) throws IOException{
6. //method implementation
7. }
8.
9. public void methodTwo(float a, float b) {

r
10. //method implementation

.b
11. }
12. }
13.
14. public class Foo extends SuperFoo{

m
15.
16. }

co
Which of the following are legal method declarations to add to the class Foo? Assume that each method is the only
one being added, and all the necessary imports and return statements are done.

A) void methodTwo(float a, float b) {}


g.
in
B) public float methodTwo() throws IOException{}
C) public long methodOne( int c, int d ){}
D) public void methodOne( int c, int d ) throws ArithmeticException{}
nn

E) public void methodOne( int c, int d ) throws FileNotFoundException{}


ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 351


3. Given the following incomplete method.

1. public void fooMethod() {


2.
3. if(!everythingOk()) {
4.
5. }
6.

r
7.}

.b
m
You want to make this method throw an IOException if the method everythinkOk() returns a value of
false. Which changes achieve this? (Choose 2 answers)

co
A) Add at line 2: IOException exception;
B) Add at line 4: throw exception;
C) Add at line 4: throw new IOException();
D) Add at line 6: throw new IOException();
g.
E) Modify the method declaration to indicate that IOException might be thrown.
in
4. Which of the following statements are true? (Choose 3 answers)
nn

A) An abstract method cannot be final


B) An abstract method cannot be static
C) An abstract method cannot be private
ai

D) An abstract method cannot be specified inside an interface


E) An abstract method cannot throw exceptions
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 352


CAPÍTULO

r
14

.b
m
co
g.
in
nn
ai
.tr

Diagramas de Seqüência
w

Elementos de um Diagrama de Seqüência


Estudo de Caso
w
w

Trainning Education Services - Todos os direitos reservados 353


14 Diagramas de Seqüência
O diagrama de classes representa informações estáticas. No funcionamento de um sistema, os
objetos interagem entre si o tempo todo, e o diagrama de seqüência mostra a interação entre
objetos em ordem seqüencial no tempo.

Utiliza-se diagramas de seqüência para:

r
• ilustrar e validar a lógica que está sendo implementada relativa à determinada funcionalidade;

.b
• identificar a necessidade da criação de novos métodos nas classes, que não foram previstos no
diagrama de classes original;

m
identificar quais classes serão as mais complexas;
• documentar fluxos de negócios de uma empresa;
• documentar fluxos de operações em sistemas legados;

co
• Identificar gargalos na modelagem de um aplicativo.

Diagramas de seqüência podem ser utilizados por:


g.
desenvolvedores , como base para a implementação do código;
in
• analistas e arquitetos,para melhoria da modelagem;
• analistas de processo, para um melhor entendimento do negócio.
nn

.
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 355


14.1 Elementos de um Diagrama de Seqüência

14.1.1 Objetos

Nos diagramas de seqüência, objetos são representados por caixas contendo o nome (opcional) e a classe do
objeto.

r
.b
m
co
Diagrama 14.1 - representação de objetos no diagrama de seqüência

g.
Os objetos são mostrados no topo do diagrama e o tempo é representado de cima para baixo, através de uma
linha tracejada chamada linha de vida do objeto.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 356


14.1.2 Mensagens

Mensagens são representadas por setas que conectam uma linha de vida a outra. As mensagens representam as
interações entre os objetos, ou seja, métodos que um objeto chama em outro. Acima da seta escreve-se o nome
da mensagem que (em nível de projeto ou implementação) será o nome do método implementado pelo objeto
receptor da mensagem, e opcionalmente, é possível numerar as mensagens.

r
A localização da mensagem na linha de vida, representa o momento em que ela ocorre dentro da seqüência.

.b
Mensagens que se localizam mais acima do diagrama são chamadas mais cedo do que as que se localizam mais
abaixo no diagrama. Alem disso, durante o processamento da mensagem representa-se uma caixa de ativação na

m
linha de vida do objeto.

Os principais tipos de mensagens são:

co
• mensagem de criação de objetos (estereótipo <<create>>);
• mensagem de invocação de método
• mensagem de valor retornado por uma invocação a método.
g.
in
nn
ai

Diagrama 14.2 - mensagem de criação de objetos


.tr

O diagrama acima corresponde ao seguinte código:


w

Conta conta = new Conta();


w
w

Trainning Education Services - Todos os direitos reservados 357


r
.b
Diagrama 14.3 - mensagem de invocação síncrona a métodos

m
Mensagens síncronas são aquelas nas quais o objeto que envia a mensagem aguarda o término do seu
processamento. O diagrama acima corresponde ao seguinte código:

co
conta.imprimeExtrato();

Também é possível representar a passagem de parâmetros nas mensagens como se vê no seguinte diagrama:
g.
in
nn

Diagrama 14.4 - representando passagem de parâmetros


ai
.tr
w
w

Diagrama 14.5 - mensagem de invocação assíncrona a métodos


w

Mensagens assíncronas são aquelas nas quais o objeto que envia a mensagem não aguarda o término do seu
processamento. Observe acima que a seta é representada aberta.

Trainning Education Services - Todos os direitos reservados 358


r
.b
Diagrama 14.6 - mensagem de retorno de métodos

m
Mensagens de retorno representam os valores retornados pelos métodos em seu processamento. São
representadas por setas pontilhadas. Acima da seta é indicado o nome de um elemento que representa o valor de
retorno do método. Mensagens de retorno são elementos opcionais do diagrama de seqüência e seu uso vai

co
depender do nível de detalhe desejado para o diagrama. Algumas boas práticas relacionadas ao uso de
mensagens de retorno são:
• não modelar um valor de retorno quando é óbvio o que está sendo retornado;
• g.
modelar um valor de retorno quando precisar referenciá-lo em outro lugar.
in
nn
ai
.tr

Diagrama 14.7 - representando o retorno de um método sem utilizar mensagens de retorno


w
w
w

Trainning Education Services - Todos os direitos reservados 359


r
.b
m
Diagrama 14.8 - chamada de um método na própria classe

co
Na modelagem da troca de mensagens entre objetos, existem situações nas quais uma mensagem pode precisar
que uma determinada condição seja atendida para ser enviada. Em UML 1.4 estas condições são chamadas
g.
condições de guarda, sendo representadas por uma expressão booleana entre colchetes antes da mensagem.
in
nn
ai
.tr

Diagrama 14.9 - chamadas condicionais if em UML 1.4

O diagrama acima corresponde ao seguinte código:


w

if ( carrinho != null) {
w

carrinho.addItem(item);
}
w

Trainning Education Services - Todos os direitos reservados 360


r
.b
Diagrama 14.10 - chamadas condicionais if/else em UML 1.4

m
O diagrama acima corresponde ao seguinte código:

co
if ( carrinho == null) {
carrinho = new CarrinhoCompras();
} else {
carrinho.addItem(item);
}
g.
in
14.1.3 Fragmentos
nn

A partir da versão 2.0 foram criados novos elementos na UML, que permitem o agrupamento de diversas
mensagens em fluxos mais complexos. Estes elementos são denominados fragmentos e consistem em uma caixa
que engloba as mensagens desejadas. Existem diversos tipos de fragmentos, de acordo com a operação que se
ai

deseja representar.
.tr

O diagrama a seguir representa uma chamada condicional if utilizando fragmentos.


w
w
w

Trainning Education Services - Todos os direitos reservados 361


r
.b
m
Diagrama 14.11 - chamadas condicionais if

co
O diagrama a seguir representa uma chamada condicional if/else utilizando fragmentos.

g.
in
nn
ai
.tr
w

Diagrama 14.12 - chamada condicional if/else


w
w

Trainning Education Services - Todos os direitos reservados 362


O diagrama a seguir representa chamadas dentro de um laço

r
.b
m
Diagrama 14.13 - chamadas dentro de um laço

co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 363


14.2 Estudo de caso

Para complementar o estudo de UML, acompanhe a seguir, um estudo de caso para um sistema de reservas de
passagens aéreas e os respectivos diagramas.

Sistema de reservas de passagens aéreas


O sistema apresenta as seguintes características:

r
• o sistema permite a um passageiro a compra de passagens aéreas;

.b
• o processo de compras é dividido em duas etapas: na primeira, é criada uma reserva para um
determinado vôo que tem um prazo de validade; na segunda etapa é feita a confirmação da reserva e é
gerado um bilhete para o passageiro;

m
• o sistema aceita três formas de pagamento: cartão de crédito, desconto em carteira ( para funcionários da
empresa aérea) e programa de milhagem;

co
• o passageiro pode acumular milhas voadas se fizer parte do programa de milhagem e neste caso ele
possui um cartão fidelidade;
• os assentos em uma aeronave possuem preços diferenciados de acordo com a categoria a que
pertençam: primeira classe, classe econômica ou outras. g.
Interpretando essas definições será modelado um diagrama de classes (estático) e os principais diagramas de
in
seqüência (dinâmico).
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 364


r
.b
m
co
g.
in
nn
ai
.tr

Diagrama 14.14 - Diagrama de classes para o estudo de caso


w
w
w

Trainning Education Services - Todos os direitos reservados 365


r
.b
m
co
Diagrama 14.15 - diagrama de seqüência para consulta de reserva
g.
É comum, na elaboração dos diagramas de seqüência, perceber-se a necessidade da criação de novas classes,
in
que não estavam presentes no diagrama de classes inicial. Na versão inicial do diagrama de classes, a principal
preocupação foi a de montar um modelo do domínio, identificando as principais entidades do sistema a ser
modelado.
nn

Ao se aproximar da implementação, foram criadas classes auxiliares tais como controladores do fluxo do
aplicativo e telas e classes de integração com outros sistemas ou com banco de dados. Nesse exemplo também
ai

foram criadas classes para interface com o usuário (ReservasView) e para acesso ao banco de dados
(ReservasDAO).
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 366


r
.b
m
co
g.
Diagrama 14.16 - diagrama de seqüência para confirmação de reserva
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 367


14.2.1 Laboratório Opcional

Objetivo:
Praticar o desenvolvimento de diagramas de seqüência.

Tabela de atividades:
Atividade OK

r
1. Criar um diagrama de seqüência para o seguinte fluxo:

.b
• O usuário entra na página e com isso aciona a classe CatalogoProdutosView.jsp
• O usuário seleciona um produto para adicionar no carrinho de compras.

m
co
g.
in
nn
ai
.tr


w

É apresentada a tela com o carrinho de compras, através da classe


CarrinhoComprasView.jsp
w
w

Trainning Education Services - Todos os direitos reservados 368


Continuação...

r
.b
m
• Quando o usuário clica no botão recalcular o valor é recalculado.

co
Imagine que as classes CatalogoProdutosView.jsp e CarrinhoComprasView.jsp são classes
como outras quaisquer, por exemplo CatalogoProdutoGUI e CarrinhoComprasGUI.
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 369


Apêndice

r
.b
m
co
g.
in
nn
ai
.tr

Solução das questões


w

Solução das questões preparatórias para certificação


Solução dos laboratórios opcionais de modelagem
w
w

Trainning Education Services - Todos os direitos reservados 371


15 Apêndice

15.1 Solução das questões preparatórias para certificação


CAPÍTULO 1 - Introdução à criação de classes
Questão 1
Resposta: C

r
Explicação:

.b
Lembrar que, nas classes, os atributos são inicializados automaticamente, entretanto, nos blocos de códigos a
inicialização deve ser explícita. Neste caso, b é um atributo local do método method, que não foi inicializado.

m
A letra D está incorreta porque pode se atribuir um valor literal inteiro positivo a uma variável char, desde que

co
tenha um tamanho compatível (valor menor que 16 bits, ou seja, menor que 65535).

A letra E refere-se ao fato de terem sido utilizados varargs na assinatura do método main. Tanto um array de

g.
Strings ( String[] ) como varargs ( String... ) poderiam ser utilizados.
in
CAPÍTULO 4 - Sobrecarga de métodos
Questão 1
nn

Resposta: B
Explicação:
A chamada ao método method é feita passando-se duas variáveis short como parâmetros. Como não existe
ai

nenhum método com a assinatura exatamente igual aos tipos de parâmetros passados, ocorre a promoção dos
tipos até encontrar-se um método que seja aplicável. Os tipos são promovidos para int e encontra-se o método
desejado.
.tr

Caso não existisse o método method(int,int), ocorreria um erro de compilação reclamando que os métodos
method(int, long) e method (long, int) são ambígüos.
w

CAPÍTULO 5 - Construtores
w

Questão 1
w

Resposta: D, E
Explicação:
Qual dos construtores é escolhido?

Trainning Education Services - Todos os direitos reservados 373


O mais específico! Desta maneira, como as literais de números inteiros são inicializadas como int, o construtor
escolhido será aquele que recebe um int como parâmetro (letra D). Além disso, o bloco de inicialização de
instância sempre é executado na chamada ao construtor, por isso a letra E também é correta.

CAPÍTULO 6 - Modificador Static


Questão 1
Resposta: C,D,E
Explicação:

r
Métodos estáticos não conseguem acessar atributos não estáticos.

.b
CAPÍTULO 8 Herança

m
Questão 1
Resposta: D

co
Explicação:
Não é possível acessar métodos sobrescritos que estejam em uma hierarquia superior a da superclasse.

Questão 2
Resposta: C
g.
in
Explicação:
Basta lembrar a seqüência de inicialização de objetos em Java: ao chamar-se o construtor de Sub, é alocado
nn

espaço em memória e são criados os atributos da classe; em seguida estes atributos são inicializados para seu
valor padrão.
No exemplo é criado o atributo value e inicializado para 0 e na seqüência é chamado o construtor da superclasse
que invoca o método getValue. Como este método foi sobrescrito, o método da subclasse é invocado retornando
ai

o valor atual do atributo value (0). Ao retornar da chamada ao construtor o atributo é inicializado de acordo com
sua declaração, para o valor 15.
.tr

Questão 3
w

Resposta: E
Explicação:
w

Lembre-se que parâmetros são passados por cópia da referência!


w

Ao chamar o método amethod(d1,d2), passa-se as referências de d1 e d2, e não os valores propriamente


ditos. Estas referências são nomeadas como p1 e p2,respectivamente.

Trainning Education Services - Todos os direitos reservados 374


Desta maneira, quando se altera os dados de p1, também estarão sendo alterados os dados da estrutura do d1
(têm a mesma referência).

Por outro lado, quando se atribui que p2=p1, a variável p2, que foi criada apenas para o método, tem sua
referência alterada. Ela não aponta mais para a variável d2, mas para a referência de d1!

Ora, ao sair do método a variável p2 deixa de existir, mostrando que a alteração de referência executada em
amethod de p2 não tem mais validade. Contudo, como a variável p1 foi alterada, conseqüentemente a variável

r
d1 também o será. As referências permaneceram as mesmas, mas a estrutura foi modificada!

.b
Questão 4

m
Resposta: B
Explicação:

co
Métodos estáticos não podem sobrescrever métodos não estáticos e vice-versa.

Questão 5
Resposta: D
g.
in
Explicação:
Variáveis e atributos finais são constantes. Entretanto, neste caso, os elementos internos do objeto
primeNumbers (array é um objeto) estão sendo modificados. Ora, essa alteração não modifica nenhuma
nn

referência do objeto primeNumbers em si, mas apenas os dados internos do objeto.


ai

Questão 6
.tr

Resposta: C
Explicação:
w

Os métodos finais não podem ser sobrescritos, mas podem ser utilizados normalmente em quaisquer outras
classes em que sejam visiveis. O final também não tem função de limitador de acesso.
w
w

Questão 7
Resposta: C, E
Explicação:

Trainning Education Services - Todos os direitos reservados 375


Apenas a classe Case extends Ace, o que denota que Case é um Ace.
De acordo com os conceitos de associação, analise os atributos que compõem cada uma das classes: a classe
Ace tem como atributo uma classe Case e isso significa que a classe Ace TEM UM Case; já a classe Case
possui o atributo da classe Base, implicando que o Case TEM UM Base.

Questão 8
Resposta: C
Explicação:

r
Lembrar que :

.b
1. Construtores padrão (sem argumentos) são construídos apenas quando não existem construtores dentro da
classe, caso contrário, não são implementados.

m
2. Todos os construtores fazem chamada, de maneira implícita, ao construtor da superclasse, na 1a linha
super().

co
CAPÍTULO 9 - Enumerações
Questão 1
Resposta: A
Explicação:
g.
in
Compila e executa normalmente imprimindo os valores “walk swim”.
nn

Enumerações podem ter atributos, métodos e construtores, por isso as alternativas B, D e E são falsas.

Quando uma enumeração possui um construtor, ele deve ser invocado na declaração dos tipos conforme é feito
na linha 2 do código. Por isso a opção C é falsa.
ai

Os valores de uma enumeração são acessados como atributos estáticos. Estes atributos podem ser acessados a
.tr

partir do nome da classe ou de uma instância da classe. Por isso é possivel acessar os valores de uma
enumeração a partir de uma variável como é feito no código com a variável animal e a alternativa F é falsa.
w

Questão 2
w

Resposta: D
Explicação:
w

Enumerações são um tipo especial de classe e classes não podem ser declaradas internamente em um método,
portanto a linha 5 gera um erro na compilação.

Trainning Education Services - Todos os direitos reservados 376


CAPÍTULO 10 - Classes abstratas e interfaces
Questão 1
Resposta: B,D
Explicação:

r
A alternativa A é incorreta pois variáveis são consideradas como static, final e public quando criadas em

.b
interfaces
A alternativa C é incorreta pois uma classe pode estender outra classe e implementar interfaces ao mesmo tempo.

m
Questão 2
Resposta: D
Explicação:

co
Classes abstratas não podem ser instanciadas e são criadas para serem herdadas. Não existe nenhuma restrição
de herança para classes abstratas, nem é necessário que elas possuam métodos abstratos.

CAPÍTULO 11 - Polimorfismo
Questão 1
g.
in
Resposta: A
Explicação:
Lembrar das regras de cast de objetos:
nn

1. Toda subclasse pode ser atribuida para a superclasse sem a necessidade de cast explícito. (todo
Triangle é um Shape).
2. Uma referência de superclasse pode ser atribuída para uma referência de subclasse, porém é necessário
ai

o cast explícito (um Shape pode ser um Triangle).


3. Em tempo de execução é gerado um erro caso a referência de subclasse aponte para uma referência
inválida.
.tr

No exemplo é feita uma atribuição de referência de subclasse para referência de superclasse, o que é sempre
válido de acordo com a regra número 1.
w
w

Questão 2
Resposta: A, C e D
w

Explicação:
As alternativas A, C e D estão corretas. A e D são exemplos de retorno covariante, porque as classes Mammal e
Dog são subclasses da classe Animal.

Trainning Education Services - Todos os direitos reservados 377


A alternativa B está incorreta porque, String não é subclasse de Animal.

CAPÍTULO 12 - Pacotes
Questão 1
Resposta: B
Explicação:

r
Métodos sem nenhum modificador de acesso são do tipo padrão, acessiveis apenas dentro do mesmo pacote.

.b
Lembre-se que classes declaradas no mesmo arquivo pertencem ao mesmo pacote, mas esta não é a resposta
mais apropriada. Outras classes e subclasses só terão acesso aos membros padrão se estiverem no mesmo
pacote.

m
Questão 2

co
Resposta: A,C
Explicação:
Membros private são invisíveis aos elementos externo e membros sem modificador (padrão) são visiveis apenas
g.
aos elementos do mesmo pacote, portanto as alternativas B e D estão incorretas.
in
Questão 3
Resposta: D
nn

Explicação:
Para utilizar membros estáticos diretamente em uma classe a declaração de import deve iniciar com “import
static”
ai

CAPÍTULO 13 - Tratamento de erros


.tr

Questão 1
Resposta: D
w

Explicação:
No método main é chamado o método method da classe Base. Este método é uma sobrescrita válida do método
w

herdado de Super. Lembre-se que na sobrescrita não é obrigatório o lançamento das exceções declaradas pelo
método original. Ocorre um erro de compilação na instrução catch (IOException e) porque a exceção
w

IOException não é lançada pelo método method da subclasse. Lembre-se que o compilador não permite a
presença de uma instrução de captura de uma checked exception que nunca é lançada no bloco try.

Trainning Education Services - Todos os direitos reservados 378


Questão 2
Resposta: B,D,E
Explicação:
A alternativa A é uma sobrescrita inválida porque torna o modificador de acesso do método mais restritivo do que
o original. O método original tinha o modificador public e o sobrescrito utiliza o modificador padrão.
Métodos sobrecarregados não possuem regras sobre o lançamento de exceções, nem sobre alterações nos tipos
retornados. Por isso a alternativa B está correta.

r
A alternativa C é uma sobrescrita inválida pois altera o tipo de retorno do método original.

.b
Métodos sobrescritos podem lançar as mesmas exceções, ou subclasses das exceções declaradas no método
original ou subconjuntos delas, ou ainda exceções do tipo RuntimeException. Desta maneira as alternativas D

m
e E estão corretas, porque ArithmeticException é uma RuntimeException e FileNotFoundException é
uma subclasse de IOException.

co
Questão 3
Resposta: C,E
g.
in
Explicação:
Quando o método everythingOk retorna false é executado o bloco de código dentro da condicional if. Para
nn

lançar IOException é necessário utilizar a instrução throw passando uma instância da exceção (alternativa C) e
sinalizar na assinatura do método que existe a possibilidade de lançamento desta exceção (alternativa E).
ai

Outra opção seria declarar e criar uma IOException para depois lançá-la na linha desejada. Perceba que a
alternativa A declara a variável exception, mas não cria uma instância de IOException. Por isso não é
possível lançar a variável não inicializada (alternativa D).
.tr

Questão 4
w

Resposta: A,B,C
Explicação:
w

Segundo a especificação de Java, métodos abstratos só podem ter os modificadores de acesso public e
protected. Note que ausência de modificadores de acesso é permitida, portanto também é possivel criar
w

métodos abstratos com acesso padrão.

Trainning Education Services - Todos os direitos reservados 379


Métodos abstratos devem estar dentro de classes abstratas ou interfaces. As subclasses devem implementar
esses métodos, o que seria impossível se o método fosse final. Por isso, a alternativa A está correta e a D
incorreta.

Classes abstratas podem ter métodos estáticos, mas um método não pode ser ao mesmo tempo abstrato e
estático. Por isso a alternativa B está correta.
Métodos private ficam invisíveis para as subclasses que tecnicamente não são capazes de sobrescrevê-los. Um
método abstrato deve ficar visível (protected, public) para as subclasses que irão sobrescrevê-los. Logo, a

r
alternativa C também está correta.

.b
Adicionalmente, os métodos abstratos podem lançar exceções, como qualquer método.

15.2 Solução dos laboratórios opcionais de UML

m
co
15.2.1 Modelagem de Classes e Relacionamentos

Conforme o laboratório de modelagem proposto no capítulo 7:


g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 380


15.2.2 Diagramas de Seqüência

Conforme o laboratório proposto no capítulo 13:

Consultar Catálogo

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 381


Selecionar Produto

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 382


Recalcular Total

r
.b
m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 383


Apêndice II

r
.b
m
co
g.
in
nn
ai

Javadoc
.tr

Doclets
Tags padrão do Javadoc
w

Executando o utilitário Javadoc


w
w

Trainning Education Services - Todos os direitos reservados 385


16 Apêndice II - Javadoc
Javadoc é um utilitário presente no JDK, que gera um conjunto de páginas HTML descrevendo as classes,
interfaces, métodos e atributos, a partir das declarações e comentários feitos no código. Veja o exemplo da
documentação gerada para as APIs padrão do JAVA SE, a partir deste utilitário:

r
.b
m
co
g.
in
nn
ai
.tr

Figura 16.1 - Javadoc padrão do Java


w

Os comentários cujo conteúdo é processado pelo utilitário são aqueles contidos na notação especial /** e */,
denominados comentários para javadoc. Este tipo de comentário pode conter qualquer texto desejado para a
descrição das classes, métodos e atributos. Além disso, podem ser utilizados elementos denominados tags, que
w

terão um processamento especial pelo utilitário Javadoc, e que são precedidos pelo símbolo @.
w

Trainning Education Services - Todos os direitos reservados 387


16.1 Doclets

Um Doclet é um programa escrito em Java utilizando a API Doclet, que especifica o conteúdo e a formatação que
deve ser gerada na utilização do utilitário Javadoc. Doclets podem ser escritos para gerar qualquer tipo de saída:
HTML,XML, RTF, PDF, e vários outros formatos.

A Sun provê um Doclet padrão para geração de documentação de APIs em formato HTML.

r
.b
Doclets também podem ser utilizados para executar tarefas especiais não relacionadas a produção de
documentação de APIs como por exemplo: é possível criar um Doclet que checa se todos os membros de uma
classe têm comentários.

m
co
16.2 Tags padrão do Javadoc
Cada tag a ser processado por um doclet tem sua funcionalidade implementada em um tipo de classe Java
especial. Cada uma destas classes é denominada taglet. Podem ser criados tags customizados escrevendo
g.
taglets, mas comumente são utilizados os próprios tags padrão do utilitário Javadoc.
in
Veja a descrição dos tags mais utilizados:
nn

@author nome
Adiciona uma seção "Author" com o nome especificado.
Cada comentário javadoc pode conter mais do que um autor em cada comentário.
ai

@deprecated textoExplicativo
.tr

Adiciona um comentário indicando que esta API não deverá mais ser utilizada, mas continuará funcionando.
Esta tag é válida para comentários : overview, pacotes, classes, interfaces, construtores, métodos e atributos.
w

O texto colocado nesta tag deve conter, pelo menos, a indicação de a partir de qual versão esta API foi
considerada deprecated, e o que deve ser utilizado em substituição ao que está deprecated.
w

Nesse caso, utiliza-se a tag {@link} que apontará para a API que substitui a que está deprecated.
w

Exemplo:

Trainning Education Services - Todos os direitos reservados 388


/**
* @deprecated As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)}
*/

@param nomeParametro descrição


Adiciona um parâmetro a lista de parâmetros no javadoc gerado. Esta tag é válida apenas para métodos ou
construtores.

r
.b
@return descrição
Adiciona uma seção "Returns" no javadoc gerado. Este texto deve ser utilizado para descrever o valor de retorno

m
de um método.
Esta tag pode ser utilizada apenas em comentários de métodos.

co
@see referência
Adiciona uma seção "See Also" com um link ou texto. Um comentário javadoc pode conter um ou mais @see tags.
g.
Esta tag pode ser utilizada em overview, pacotes, classes, interfaces, construtores, métodos e atributos.
Se for colocado apenas um texto e não um link, coloca-se a referência entre aspas duplas.
in
Fazendo referência a atributos da mesma classe:
nn

• @see #atributo
• @see #metodo(Tipo, Tipo,...)
• @see #metodo(Tipo param1, Tipo param2,...)
ai

Fazendo referência a classes cujos pacotes estão sendo importados:


.tr

• @see Class#atributo
• @see Class#metodo(Type, Type,...)
w

• @see Class#metodo(Tipo param1, Tipo param2,...)


• @see Class
w

Fazendo referência a outros pacotes:


w

• @see package.Class#atributo
• @see package.Class#metodo(Tipo, Tipo,...)

Trainning Education Services - Todos os direitos reservados 389


• @see package.Class#metodo(Tipo param1, Tipo param2,...)
• @see package.Class
• @see package

@since textoExplicativo
Esta tag serve para indicar desde qual versão da API este método, atributo ou classe está disponível.
Esta tag é válida em qualquer comentário: overview, pacote, classe, interface, construtor, método ou atributo.

r
.b
@throws nomeClasse descrição
Esta tag é sinônima da tag @exception.
nomeClasse indica o nome da exceção que pode ser lançada por este método.

m
Esta tag é válida apenas para métodos ou construtores.

co
Esta tag é copiada para métodos sobrescritos em subclasses somente quando a exceção está explicitamente
declarada no método sobrescrito.

g.
Veja algumas utilizações de tags para a classe Livro e a exceção CategoriaInvalidaException:
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 390


package br.com.trainning.model;

import

br.com.trainning.exception.CategoriaInvalidaException; /**
* Esta classe representa um Livro. Exemplo:
*
* <pre>
* Livro l = new Livro();
* l.setNome(&quot;A História da trainning&quot;);
* </pre>

r
*
*@author trainning

.b
* @version 1.0
* @see www.trainning.com.br
*/

m
public class Livro {

private String nome;

co
private int categoria;
private String ISBN;
private String autor;
private String editora;
public static final int ROMANCE = 1;
public static final int HISTORIA = 2;
public static final int INFORMATICA = 3;
g.
in
/**
* @param nome
* Nome do livro
* @param autor
nn

* Autor do livro
* @param editora
* Editora do livro
* @param ISBN
* ISBN do livro
ai

*/
public Livro(String nome, String autor, String editora, String ISBN) {
this.nome = nome;
.tr

this.autor = autor;
this.editora = editora;
this.ISBN = ISBN;
}
w

/**
* @param nome
* Nome do livro
w

*/
public void setNome(String nome) {
this.nome = nome;
w

/**
* @param categoria

Trainning Education Services - Todos os direitos reservados 391


* Categoria do livro
* @throws CategoriaInvalidaException
*/
public void setCategoria(int categoria) throws CategoriaInvalidaException {
if (categoria == ROMANCE || categoria == HISTORIA
|| categoria == INFORMATICA) {
this.categoria = categoria;
} else
throw new CategoriaInvalidaException("Categoria inválida");
}

/**

r
* @param ISBN
* ISBN do livro

.b
*/
public void setISBN(String ISBN) {
this.ISBN = ISBN;
}

m
/**
* @param autor

co
* Autor do livro
*/
public void setAutor(String autor) {
this.autor = autor;
}

/**
* @param editora
* Editora do livro
g.
in
*/
public void setEditora(String editora) {
this.editora = editora;
nn

/**
* @return nome do livro
*/
ai

public String getNome() {


return nome;
}
.tr

/**
* @return categoria do livro
*/
public int getCategoria() {
w

return categoria;
}
w

/**
* @return ISBN do livro
*/
w

public String getISBN() {


return ISBN;
}

/**

Trainning Education Services - Todos os direitos reservados 392


* @return autor do livro
*/
public String getAutor() {
return autor;
}

/**
* @return editora do livro
*/
public String getEditora() {
return editora;
}

r
}

.b
Codigo 16.1 - Livro.java

m
co
g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 393


package br.com.trainning.exception;

/**
* Esta classe representa a exceção gerada quando se tenta designar uma
* categoria inválida a um objeto.
*
* Exemplo:
*
* <pre>
* Livro l = new Livro();
* l.setCategoria(0125);

r
* </pre>

.b
*
* Caso não exista a categoria 0125 será lançada a exceção
* CategoriaInvalidaException
*

m
*@author trainning
* @version 1.0
* @see www.trainning.com.br
*/

co
public class CategoriaInvalidaException extends Exception {

public CategoriaInvalidaException(String mensagem) {


super(mensagem);

}
} g.
Código 16.2 - CategoriaInvalidaException.java
in
package br.com.trainning.teste;
nn

import

br.com.trainning.model.Livro; /**
* Esta é a classe criada para testar o funcionamento
* da classe Livro.
ai

*
*
* @author trainning
.tr

* @version 1.0
*
*/
public class TesteLivro {
w

public static void main(String args[]) {


String titulo = "A Historia da trainning";
Livro l = new Livro(titulo, "trainning", "Globalpress",
w

"1234-56789"); System.out.println(l.getNome());
}
}
w

Código 16.3 - TesteLivro

Trainning Education Services - Todos os direitos reservados 394


16.3 Executando o utilitário Javadoc
O utilitário Javadoc pode ser executado simplesmente indicando o nome do pacote para o qual se quer gerar os
javadocs:

• javadoc br.com.trainning.model

r
É possível também indicar onde se deseja que o javadoc seja gerado:

.b
• javadoc -d docs br.com.trainning.model

m
Desta maneira os htmls serão colocados no diretório docs.

co
E ainda é possível gerar documentação para um conjunto de subpacotes.
Veja como gerar os documentos javadoc para todos os subpacotes do pacote br.com.trainning, que são
br.com.trainning.model , br.com.trainning.test e br.com.trainning.exception e salvá-los
no diretório docs: g.
• javadoc -d docs -subpackages br.com.trainning
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 395


r
.b
m
co
g.
Figura 16.2 - métodos da classe Livro
in
nn
ai
.tr

Figura 16.3 - atributos públicos da classe Livro


w
w
w

Trainning Education Services - Todos os direitos reservados 396


r
.b
m
co
Figura 16.4 - Javadoc da classe Livro

g.
in
nn
ai
.tr
w
w
w

Trainning Education Services - Todos os direitos reservados 397

Você também pode gostar