Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Escolha uma das opções e acesse esse e outros materiais sem bloqueio. 🤩

Cadastre-se ou realize login

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Prévia do material em texto

Java Fundamentals 
 
 
 
 
 
 
 
 
 
 
Java Fundamentals 
 
 I 
 
SumárioSumárioSumárioSumário 
1.1.1.1. A tecnologia Java e configuração do ambieA tecnologia Java e configuração do ambieA tecnologia Java e configuração do ambieA tecnologia Java e configuração do ambientententente........................................................ 1111----1111 
Objetivos .......................................................................................................................1-2 
O que é Java? .............................................................................................................1-3 
Simples e orientada a objetos ...................................................................................1-5 
Uma linguagem robusta.............................................................................................1-7 
Multiplataforma e interpretada ................................................................................1-9 
A Java Virtual Machine - JVM .................................................................................1-11 
Uma Linguagem Segura e Dinâmica.....................................................................1-14 
Aspectos de segurança ...........................................................................................1-16 
O Just in Time Compiler - JIT .....................................................................................1-18 
O Java Standard Development Kit – J2SDK..........................................................1-19 
Configurando o ambiente.......................................................................................1-22 
API’s da linguagem ...................................................................................................1-23 
2.2.2.2. Tipos e OTipos e OTipos e OTipos e Operadoresperadoresperadoresperadores ................................................................................................................................................................................................................ 2222----1111 
Objetivos .......................................................................................................................2-2 
Variáveis ........................................................................................................................2-3 
Tipos primitivos e tipos compostos ............................................................................2-4 
Tipos Primitivos ..............................................................................................................2-6 
Declarando um tipo primitivo..................................................................................2-10 
Tipo caracter – char..................................................................................................2-12 
Tipo booleano – boolean.........................................................................................2-14 
Tipos inteiros - byte, short, int e long .......................................................................2-15 
Tipos de ponto flutuante - float e double..............................................................2-17 
Tipo composto – String..............................................................................................2-19 
Conversões de tipos – casting.................................................................................2-20 
Tipos de referência....................................................................................................2-22 
Expressões e operadores..........................................................................................2-23 
Sumário de operadores............................................................................................2-25 
Precedência...............................................................................................................2-27 
Associatividade..........................................................................................................2-28 
Tipos de operadores: unários e binários ................................................................2-29 
3.3.3.3. Criando classes e objetosCriando classes e objetosCriando classes e objetosCriando classes e objetos ............................................................................................................................................................................ 3333----1111 
Objetivos .......................................................................................................................3-2 
Classes e Objetos.........................................................................................................3-3 
Criando uma classe ....................................................................................................3-4 
Padrões..........................................................................................................................3-6 
Java Fundamentals 
 II 
Criando e importando pacotes................................................................................3-9 
Static import................................................................................................................3-11 
Criando objetos .........................................................................................................3-12 
O que é a referência null? .......................................................................................3-13 
Atribuindo referências...............................................................................................3-15 
Visibilidade aplicada a classes ...............................................................................3-16 
Definindo operações ................................................................................................3-18 
Comando return ........................................................................................................3-21 
Visibilidade para operações ...................................................................................3-22 
Definindo atributos ....................................................................................................3-25 
Visibilidade aplicada a atributos ............................................................................3-26 
Acessando atributos .................................................................................................3-32 
Comentários no código fonte.................................................................................3-33 
Escopo das variáveis.................................................................................................3-36 
Passando Tipos Primitivos para Métodos ...............................................................3-39 
Passando Referências para Métodos ....................................................................3-40 
Exercícios.....................................................................................................................3-42 
4.4.4.4. Comandos da LinguagemComandos da LinguagemComandos da LinguagemComandos da Linguagem ............................................................................................................................................................................ 4444----1111 
Objetivos .......................................................................................................................4-2 
Comandos ....................................................................................................................4-3 
Comando if / else / else if ..........................................................................................4-4 
Seqüência de Cláusulas else if ..................................................................................4-7 
Operador ternário .......................................................................................................4-9Comando switch .......................................................................................................4-10 
Comando while .........................................................................................................4-13 
Comando do .............................................................................................................4-14 
Comando for..............................................................................................................4-15 
Comando “for-each” ...............................................................................................4-18 
Comando break ........................................................................................................4-19 
Comando continue ..................................................................................................4-21 
Exercícios.....................................................................................................................4-24 
5.5.5.5. Aprofundando o estudo sobre ClassesAprofundando o estudo sobre ClassesAprofundando o estudo sobre ClassesAprofundando o estudo sobre Classes.................................................................................................... 5555----1111 
Objetivos .......................................................................................................................5-2 
Visão Geral ...................................................................................................................5-3 
Overloading – sobrecarga de operação ...............................................................5-4 
Métodos construtores .................................................................................................5-6 
Referência this..............................................................................................................5-9 
Compartilhando código entre Construtores ........................................................5-11 
Método destrutor – finalize() ....................................................................................5-12 
Variáveis de instância...............................................................................................5-13 
Métodos de instância ...............................................................................................5-15 
Variáveis de classe ....................................................................................................5-16 
Inicializando Variáveis de Classe ............................................................................5-19 
Métodos de classe ....................................................................................................5-20 
Java Fundamentals 
 III 
Exemplos de variáveis e métodos estáticos .........................................................5-22 
O mecanismo de herança entre classes ..............................................................5-23 
Herdando estrutura e comportamento.................................................................5-24 
Especificando herança em Java ...........................................................................5-25 
Objetos de subclasses...............................................................................................5-26 
Chamando construtores da superclasse...............................................................5-27 
Overloading e Overriding de métodos..................................................................5-29 
Redefinindo métodos – overriding..........................................................................5-30 
Referência super........................................................................................................5-33 
Invocando métodos da superclasse......................................................................5-35 
Visibilidade protected ..............................................................................................5-36 
Varargs ........................................................................................................................5-37 
Polimorfismo................................................................................................................5-39 
Modificador final........................................................................................................5-41 
Enums...........................................................................................................................5-43 
Exercícios.....................................................................................................................5-46 
6.6.6.6. Coleções, Arrays, Strings, e Wrapper ClassesColeções, Arrays, Strings, e Wrapper ClassesColeções, Arrays, Strings, e Wrapper ClassesColeções, Arrays, Strings, e Wrapper Classes ............................................................ 6666----1111 
Objetivos .......................................................................................................................6-2 
Strings .............................................................................................................................6-3 
Criando Strings .............................................................................................................6-4 
Concatenando Strings................................................................................................6-5 
Executando operações em objetos String..............................................................6-6 
Comparando duas Strings .........................................................................................6-8 
Obtendo strings a partir de objetos..........................................................................6-9 
Convertendo tipos primitivos em strings ................................................................6-10 
Wrapper Classes ........................................................................................................6-11 
Conversões com Wrapper Classes .........................................................................6-12 
StringBuffer e StringBuilder ........................................................................................6-13 
Arrays ...........................................................................................................................6-14 
Arrays de tipos primitivos ..........................................................................................6-15 
Declarando arrays de tipos primitivos....................................................................6-16 
Criando arrays............................................................................................................6-17 
Inicializando arrays ....................................................................................................6-18 
Arrays de objetos .......................................................................................................6-20 
Declarando arrays de objetos ................................................................................6-21 
Inicializando arrays de objetos................................................................................6-22 
Utilizando arrays de objetos .....................................................................................6-23 
Arrays e Exceções......................................................................................................6-24 
Arrays multidimensionais...........................................................................................6-25 
O método main(String[] args) ........................................................................6-26 
API Colletion ...............................................................................................................6-27 
A interface Iterator ....................................................................................................6-28 
A interface Enumeration ..........................................................................................6-29Interfaces do framework ..........................................................................................6-30 
A classe ArrayList........................................................................................................6-31 
A classe Vector ..........................................................................................................6-32 
Java Fundamentals 
 IV 
A classe Hashtable ....................................................................................................6-34 
A classe LinkedList......................................................................................................6-35 
Generics ......................................................................................................................6-36 
Autoboxing .................................................................................................................6-39 
Exercícios.....................................................................................................................6-43 
7.7.7.7. Tratamento de ExceçõesTratamento de ExceçõesTratamento de ExceçõesTratamento de Exceções.................................................................................................................................................................................... 7777----1111 
Objetivos .......................................................................................................................7-2 
Introdução ....................................................................................................................7-3 
1a Vantagem: Separação de Código.....................................................................7-4 
2a Vantagem: Propagação de Erros........................................................................7-6 
3a Vantagem: Agrupar Tipos de Erros ......................................................................7-8 
4a Vantagem: Exceções não são Ignoradas........................................................7-10 
Manipulando Exceções............................................................................................7-11 
Tratando Exceções....................................................................................................7-13 
Manipulando Exceções............................................................................................7-14 
Manipulando Exceções: Exemplo Prático.............................................................7-16 
Propagando Exceções.............................................................................................7-17 
Lançando Exceções .................................................................................................7-18 
Criando Exceções .....................................................................................................7-19 
Capturando Exceções e Levantando Exceções Diferentes..............................7-20 
Exercícios.....................................................................................................................7-22 
8.8.8.8. Classes abstratas e InterfacesClasses abstratas e InterfacesClasses abstratas e InterfacesClasses abstratas e Interfaces .................................................................................................................................................... 8888----1111 
Objetivos .......................................................................................................................8-2 
Abstração .....................................................................................................................8-3 
Definindo classes abstratas........................................................................................8-4 
Métodos Abstratos.......................................................................................................8-6 
Definindo métodos abstratos ....................................................................................8-7 
Interfaces ......................................................................................................................8-8 
Exemplos de interfaces...............................................................................................8-9 
Definindo Interfaces ..................................................................................................8-10 
Implementando Interfaces ......................................................................................8-11 
Exercícios.....................................................................................................................8-13 
Java Fundamentals 
 
 1-1 
11.. AA tteeccnnoollooggiiaa JJaavvaa ee 
ccoonnffiigguurraaççããoo ddoo aammbbiieennttee 
A tecnologia java e configuração do ambiente 
 1-2 
Objetivos 
• Compreender os fundamentos da tecnologia Java 
• Discutir vantagens da tecnologia 
• Entender o funcionamento da JVM (Java Virtual Machine) 
• Configurar o ambiente de desenvolvimento para o programador 
 
 
A tecnologia java e configuração do ambiente 
 1-3 
O que é Java? 
 
• Linguagem orientada a objetos, simples, portável, interpretada, 
distribuída, robusta, segura, dinâmica, de alto desempenho, multi-thread e 
independente de plataforma 
• Projetada pela Sun Microsystems inicialmente para dispositivos eletrônicos 
• Utilizada posteriormente em navegadores web, para permitir que uma 
aplicação pudesse ser desenvolvida e “executada na web”. Aqui é o 
nascimento da tecnologia applet 
• Uma linguagem muito utilizada atualmente para desenvolvimento de 
sistemas que precisam rodar na web bem como sistemas desktop 
 
Breve Histórico 
 
Java começou em 1991, quando um grupo de analistas da Sun, liderados 
por Patrick Naughton e James Gosling, procurou desenvolver uma linguagem de 
computador que fosse usada em equipamentos domésticos, tais como 
comutadores de canais para TV a cabo, videocassetes e outros. 
Como estes equipamentos não dispõem de muita memória ou velocidade, 
a linguagem tinha de ser reduzida e gerar código eficiente. Além disto, como 
diferentes fabricantes poderiam escolher diferentes CPUs, tal linguagem não 
poderia se restringir a uma única arquitetura. 
O projeto ficou conhecido como Green Project. 
 
 
 DUKE, um dos símbolos do Java 
 
Visando satisfazer todas estas exigências, a equipe de analistas optou por 
uma linguagem que gerasse código intermediário (os famosos bytecodes Java), 
e que a interpretação deste código não fosse feita diretamente pelo hardware e 
sim por uma máquina virtual disposta sobre ele (conhecida hoje como JVM – 
Java Virtual Machine). 
Esta linguagem foi batizada inicialmente com o nome Oak (que, em 
português significa carvalho). Possivelmente o nome escolhido por Gosling se 
deve a um carvalho que existia em frente a sua janela na Sun MicroSystems. 
A tecnologia java e configuração do ambiente 
 1-4 
Posteriormente se descobriu que Oak já era o nome de uma outra 
linguagem, e o nome foi então trocado para Java. 
Java não obteve muito sucesso como linguagem de controle de 
eletrodomésticos (e isto nós podemos muito bem atestar :-). Em vão, a equipe do 
Green Project tentou vender a idéia para fabricantes de tais dispositivos. 
Dissolvida a equipe, por absoluta falta de êxito econômico, alguns dos antigos 
componentes perceberam que uma das possíveis utilidades para tal linguagem 
seria embuti-la em navegadores, como os encontrados no mercado. 
Tais aplicativos exigiam justamente uma linguagem independente de 
plataforma, confiável, segura e em tempo real: todas as características 
“estranhas” que Java possuía. 
A tecnologia java e configuração do ambiente 
 1-5 
Simples e orientada a objetos 
 
• Uma linguagem simples e orientada a objetos 
• Baseada em Smalltalk e C++ 
• A tecnologia de objetospara esta linguagem foi baseada em Smalltalk 
• Reaproveitou grande parte da sintaxe utilizada pelo C e C++ 
• Eliminou construções de C++ consideradas complexas ou desnecessárias 
• Reduzido conjunto de palavras reservadas e um grande poder de 
expressão 
 
Uma Linguagem Orientada a Objetos 
 
Problemas surgidos na área de engenharia de software, tais como aumento 
explosivo da complexidade dos sistemas, dificuldades na manutenção e 
evolução dos softwares existentes, fraca robustez apresentada pelos aplicativos e 
outros, fizeram com que os paradigmas de análise e desenvolvimento de 
software fossem alterados. 
Java surge junto com o “boom” da orientação por objetos, à ampla 
aceitação deste paradigma pelos técnicos de informática como o mais 
adequado a enfrentar os problemas encontrados. 
A cultura dos técnicos da equipe de desenvolvimento da Sun Microsystems 
fez com que, entre as linguagens orientadas por objetos conhecidas, 
escolhessem C++ como modelo para o desenvolvimento de Java. C++ era então 
uma das mais difundidas linguagens de programação orientada por objetos em 
voga no mundo UNIX. 
Mas C++ era complexa demais. Várias construções em C++ eram de 
questionável utilidade e de difícil implementação por parte dos construtores de 
compiladores. 
Herança múltipla e sobrecarga de operadores, por exemplo, eram 
construções que demandavam grande esforço por parte dos implementadores e 
que não fazem parte do núcleo mínimo exigido pelo paradigma. Desta forma 
alguns recursos ficaram de fora e decidiu-se manter inicialmente uma gama 
menor de recursos para viabilizar o projeto e manter o mesmo mais somples. 
Atualmente alguns recuros mais sofisticados como “Generics” foram incluídos. Os 
recursos básicos que foram atendidos na época são: 
• Abstração 
A tecnologia java e configuração do ambiente 
 1-6 
• Encapsulamento 
• Herança 
• Polimorfismo 
Decidiram então simplificar: 
• A linguagem não seria compilada para uma plataforma nativa e sim 
para uma máquina virtual. Esta técnica que dá ao java a possibilidade 
de rodar em múltiplas plataformas foi baseada no Smalltalk 
• Não haveria programação genérica (na época, mas a partir da versão 
1.5 este recurso já é suportado) 
• Não haveria sobrecarga de operadores 
• Herança múltipla seria substituída pelo mecanismo de interfaces, mais 
simples e com poder de expressão equivalente 
• A velha sintaxe, tomada de empréstimo da linguagem C, seria 
enxugada, de modo a conter somente as palavras reservadas 
necessárias 
 
Destas idéias iniciais surge então a tecnologia Java. Claro que há muito mais 
coisas presentes no java do que as listadas acima. Atualmente o java é uma 
tecnologia tão completa que permite você desenvolver aplicações para rodar 
na Web, em máquinas cliente, Celulares, Palm Tops e muito mais. 
A tecnologia java e configuração do ambiente 
 1-7 
Uma linguagem robusta 
 
• Java é uma linguagem fortemente tipada 
• Ampla verificação de erros e checagem de tipos em tempo de 
compilação 
• Não existem apontadores na linguagem 
• Linguagem multiplataforma 
• Gerência automática da memória (garbage collection) 
 
Erro de Ponteiro? 
 
Um dos principais objetivos dos projetistas da linguagem era conseguir 
conciliar a flexibilidade e o poder da orientação por objetos com a segurança e 
a robustez da checagem de tipos e erros em tempo de compilação. 
Java é uma linguagem fortemente tipada. 
E o que queremos dizer com isto? 
Que, em tempo de compilação, são checados todos os problemas 
referentes à passagem de parâmetros e atribuições de variáveis no que diz 
respeito à compatibilidade de tipos entre a variável que recebe o valor e a 
variável atribuída. 
Outra importante característica da linguagem Java é fato de não possuir 
apontadores, com o sentido que tal termo possui em C ou em C++. 
Em C ou C++ é perfeitamente possível navegarmos despreocupadamente 
pela memória do processo: basta, para tal, declararmos um apontador para 
uma região de memória e sairmos a incrementá-lo ou decrementá-lo. 
Toda a aritmética com apontadores não só é permitida pela linguagem, 
como também incentivada. 
Em Java não há apontadores explícitos, nem tampouco aritmética de 
apontadores, mas sim referências feitas a objetos criados. 
Objetos são criados através do operador new e o espaço de memória que 
ocupam é automaticamente gerenciado por um sistema de coleta de lixo 
(garbage collection) , que o libera tão logo não haja mais referências a um 
objeto. 
A tecnologia java e configuração do ambiente 
 1-8 
Com isto, não existem em Java os erros de ponteiro (dangling pointers, 
memory leak e outros) tão conhecidos de linguagens como C e C++. 
A tecnologia java e configuração do ambiente 
 1-9 
Multiplataforma e interpretada 
 
Ao contrário das outras tecnologias onde os programas são compilados 
para um sistema operacional específico, os fontes Java são compilados para 
uma máquina virtual. Isto significa que após a compilação os mesmos, são 
executados por uma máquina virtual (JVM) e não diretamente pelo sistema 
operacional. Abaixo veja a forma tradicional de compilação dos programas e 
mais abaixo a forma como funciona o Java. 
 
 Figura 1-1: Compilação em C++. 
Em linguagens tradicionais como C, C++ ou pascal, o código fonte é 
convertido para um conjunto de instruções de máquina da plataforma de 
hardware onde a compilação teve lugar. Este programa é executado 
diretamente pela CPU da máquina e está vinculado à plataforma em que foi 
compilado: só poderá ser executado por CPUs que compartilhem o mesmo 
conjunto de instruções, o que geralmente significa ficar limitado a um 
determinado fabricante de hardware ou a uma família de produtos. 
 
 
Figura 1-2: Compilação em Java. 
A tecnologia java e configuração do ambiente 
 1-10 
Java adota uma filosofia diferente. Os fontes Java não são convertidos 
diretamente para instruções de máquina. Ao contrário, a partir da compilação 
dos fontes são gerados arquivos contendo código intermediário que independe 
de plataforma. 
O código intermediário Java, conhecido como “bytecode” Java, foi 
projetado para uma máquina hipotética. Contém instruções similares a de uma 
máquina real (operações aritméticas, controle de fluxo, etc.), mas não tem em 
vista, e nem se limita, a uma determinada arquitetura de computador. 
Em vez de ser executado diretamente pelo hardware, este código é 
interpretado por uma JVM (Máquina Virtual Java  Java Virtual Machine). Desta 
forma, em qualquer arquitetura onde exista uma JVM será possível executar um 
programa Java sem a necessidade de se re-compilar os fontes. 
Os binários Java (código intermediário ou Java bytecode) são 
independentes de plataforma ou, dito de outra maneira, neutros quanto à 
arquitetura da máquina. 
Os fontes Java são armazenados em arquivos com a extensão .java. A 
compilação dos arquivos .java trará como resultado arquivos com a extensão 
.class. 
Arquivos com a extensão .class contém somente Java bytecodes e são 
também conhecidos como binários Java. Cabe novamente ressaltar que os 
binários Java (arquivos .class) não são executados diretamente pelo hardware 
e sim interpretados pela JVM. 
Sem a JVM não há como executar nenhum programa Java. 
 
 
A tecnologia java e configuração do ambiente 
 1-11 
A Java Virtual Machine - JVM 
 
• Camada intermediária e isolante entre o sistema operacional e as 
aplicações Java. 
• Elimina a dependência do código quanto à arquitetura e quanto às 
facilidades do SO. 
• Responsável pela interpretação dos bytecodes Java. 
• Traduz os bytecodes em instruções de máquina e em chamadas de 
sistema (API do SO). 
• Pode ser implementada através de um programa avulso ou estar 
embutida em um navegador(Browser). 
A máquina virtual Java (ou, como é comumente chamada, JVM, Java 
Virtual Machine) integra o ambiente de programação e execução Java. Ela é 
responsável por interpretar os bytecodes Java e traduzi-los em instruções reais de 
máquina e em chamadas de sistema (syscalls). 
 
 Figura 1-3: Esquema de independência da JVM. 
Desta forma, as requisições feitas por um programa Java a recursos do 
sistema são mapeadas pela JVM em requisições feita ao SO sobre o qual a JVM 
executa. O SO responde a tais requisições e estas respostas são encaminhadas 
ao código Java em execução. 
Uma vez compilado um programa Java, os binários (bytecodes Java) 
podem ser executados em toda a plataforma para a qual já a JVM já tenha sido 
portada. Atualmente, a grande maioria dos sistemas operacionais conhecidos 
possui uma implementação da JVM (Solaris, Windows98, WindowsNT, Linux, 
MacOS, HP-UX, AIX, etc.). 
A tecnologia java e configuração do ambiente 
 1-12 
A JVM pode ser implementada através de um programa avulso, pode estar 
embutida em um navegador, fazer parte do núcleo de um banco de dados, ou 
mesmo integrar o kernel de um SO. 
A única exigência que se faz à execução de um aplicativo Java é a 
existência da JVM para aquele ambiente. 
 Como executam os programas java 
 
A linguagem Java é orientada a objetos, com linhas de execução (threads) 
dinâmicas e muitos outros recursos. Mas o que faz a diferença é o modo como os 
programas Java são executados. Eles rodam dentro de máquinas virtuais (virtual 
machines), que ficam dentro do computador. Por isso, um programa Java não 
tem contato com o computador real, ele conhece apenas a máquina virtual. 
Logo, os programas Java são independentes de plataforma. Se você já precisou 
desenvolver programas para vários sistemas operacionais, sabe que isso é uma 
grande vantagem. 
Quando você escreve um programa Java e o compila, ele está pronto para 
ser executado em qualquer PC que contenha a máquina virtual Java. De certa 
forma, você está escrevendo para apenas uma plataforma: a máquina virtual. 
A virtual machine determina o que os programas Java podem ou não fazer. 
Os programas escritos em linguagens compiladas, como C ou C++, são 
executados diretamente pelo sistema operacional. Assim sendo, eles têm acesso 
direto a todos os recursos do sistema, incluindo memória e sistema de arquivos. 
Como os programas Java são executados de dentro da máquina virtual, as 
pessoas (programadores e desenvolvedores) que criam a máquina virtual podem 
decidir o que um programa pode ou não fazer no computador. O ambiente 
criado para os programas Java chama-se ambiente de runtime. A máquina 
virtual age como um firewall (barreira) entre o computador e o programa Java. 
Um programa nunca acessa os dispositivos de entrada e saída, o sistema de 
arquivos ou mesmo a memória do seu computador. Em vez disso, ele pede que a 
máquina virtual faça isso. 
Quando rodamos as applets, elas são descarregadas para uma máquina 
virtual que proíbe o acesso ao sistema de arquivos. Assim, ela só permite acesso 
indireto aos recursos do sistema. 
Por ser uma linguagem interpretada, isso explica a independência de 
plataforma Java. 
A tecnologia java e configuração do ambiente 
 1-13 
 
Por que interpretada? 
Porque o compilador Java gera o bytecode (código especial Java), que 
será executado por uma máquina virtual implementada em software, chamada 
de JVM – Java Virtual Machine (Máquina Virtual Java). 
A diferença entre o Java que é uma linguagem interpretada, comparada 
com uma linguagem compilada, como o caso do C ou C++ é que enquanto 
nessas linguagens tradicionais, para cada plataforma precisamos que o 
compilador gere um código especifico, como por exemplo, para um PC. Se 
quisermos que o mesmo programa rode em um Macintosh, precisaremos 
compilá-lo para rodar em Macintosh e assim por diante. Já com o Java isso não 
aconteceria, pois para rodarmos um programa feito em Java, usamos o 
interpretador Java (contido na JVM) para executar o bytecode resultante da 
compilação. Como o bytecode Java é independente de plataforma, os 
programas Java podem rodar em qualquer plataforma para a qual a JVM tenha 
sido portada. A JVM inclui o interpretador mais o sistema de runtime. 
Em um ambiente interpretado, a fase de linkagem que existem no 
desenvolvimento de programas tradicionais compilados praticamente 
desaparece. O equivalente em Java à fase de linkagem consiste apenas do 
processo de carregar novas classes no ambiente de execução da JVM. 
Esse é um processo leve e incremental, que ocorre em tempo de execução. 
Isso é diferente do ciclo compilar-linkar-rodar, mais trabalhoso, comum em 
linguagens como C e C++. O resultado é uma redução no tempo de 
desenvolvimento dos programas. 
Agora, depois dessa explicação, fica claro o que eles quiseram dizer com a 
frase "Write once, Compile once and Run anywhere" – ("Escreva uma vez, compile 
uma vez e rode em qualquer lugar"), frase esta que se tornou uma das marcas 
registradas de Java. 
 
 
 
A tecnologia java e configuração do ambiente 
 1-14 
Uma Linguagem Segura e Dinâmica 
 
• Os bytecodes de Java são constantemente policiados pela JVM 
• Instruções não autorizadas levantam exceções de segurança 
• A carga das classes é feita de maneira dinâmica 
• Uma classe pode ser carregada através da rede ou do disco local da 
máquina 
Figura 1-4: Fluxo de compilação e execução de uma classe Java 
Durante a execução de um programa Java, a JVM pode importar código 
de qualquer lugar. A fim de tornar, a linguagem segura, é necessário ou nos 
certificarmos de que o local de onde o código se origina é seguro, ou policiarmos 
constantemente o código inseguro contra eventuais violações de segurança. 
A primeira opção é implementada através de sistemas de assinatura digital 
de código. 
A segunda opção, por sua vez, é de responsabilidade do sistema de 
runtime. Cabe a este policiar a execução dos bytecodes Java, verificando se 
não há, entre eles, nenhuma instrução não autorizada, que viole as regras de 
segurança estabelecidas pela linguagem. 
A tecnologia java e configuração do ambiente 
 1-15 
O carregador de classes do sistema de runtime assegura que classes com 
origem em uma fonte local (classes Built-in) e classes provenientes da rede sejam 
armazenadas separadamente. 
Durante a execução, o sistema de runtime sempre procura resolver primeiro 
uma referência nas classes locais. Isto garante que classes locais não sejam 
substituídas por classes carregadas a partir da rede (fonte insegura). 
Elimina a possibilidade de sobrescrita de classes seguras (spoofing) por 
classes não confiáveis. O acesso ao sistema de arquivos locais e aos recursos de 
rede é controlado por classes da linguagem (Built-in classes). Estas classes são 
restritivas por default. Se código importado e classificado como inseguro tenta 
acessar o sistema de arquivos, os mecanismos de segurança avisam 
imediatamente ao usuário. 
A tecnologia java e configuração do ambiente 
 1-16 
Aspectos de segurança 
 
Talvez pelo fato de Java estar fortemente associado à Internet, um dos 
aspectos mais divulgados da linguagem é sua segurança. Isso é natural: sem a 
certeza da segurança, provavelmente ninguém iria querer baixar código de um 
site desconhecido na Internet e deixar que ele rodasse em seu computador.E no 
entanto, isso já está sendo feito todos os dias com os applets Java. 
Java foi projetado com a segurança em mente. Por isso, oferece várias 
camadas de controles de segurança que protegem contra código malicioso, 
permitindo que os usuários rodem tranqüilamente programas de origem 
desconhecida, como os applets. 
No nível mais baixo, a segurança é uma conseqüência da robustez de Java. 
Como já vimos, os programas Java não podem forjar ponteirospara a memória, 
nem estourar arrays, nem ler memória que esteja fora das fronteiras de um array 
ou string. Esses recursos são uma das principais defesas de Java contra código 
malicioso. Ao impedir totalmente qualquer acesso direto à memória, toda uma 
enorme classe de ataques à segurança é evitada. 
A segunda barreira contra código malicioso é o processo de verificação do 
bytecode que é executado pelo interpretador Java sobre qualquer código de 
origem desconhecida que é carregado. Essa verificação assegura que o código 
seja bem formado – isto é, que ele não avance na memória que fica acima ou 
abaixo dos limites da pilha (stack overflow ou underflow), nem implemente 
bytecode ilegal. Se esse passo de verificação do bytecode não existisse, código 
corrompido por incompetência ou má fé poderia tirar partido de pontos fracos 
na implementação de um interpretador Java. 
Outra camada de proteção para segurança é comumente chamada de 
modelo de caixa de areia (sandbox): o código de origem desconhecida pode 
rodar, mas é mantido isolado dentro de uma caixa de areia, onde pode rodar 
em segurança sem causar qualquer dano ao "mundo real", que é o ambiente 
Java como um todo. 
Quando um applet, ou outro código de origem desconhecida está rodando 
dentro da caixa de areia, ele fica submetido a diversas restrições sobre o que 
pode fazer. A mais óbvia dessas restrições é que ele não tem acesso de nenhum 
tipo ao sistema de arquivos local. Existem ainda várias outras restrições à caixa de 
areia. Na verdade, existe uma classe, chamada SecurityManager, especialmente 
para cuidar da implementação dessas restrições. Para assegurar o 
funcionamento do modelo de segurança, todas as classes do núcleo Java que 
executam operações de risco, como acesso ao sistema de arquivos, primeiro 
pedem permissão ao SecurityManager atualmente instalado. Se a chamada está 
sendo feita, direta ou indiretamente, por código de origem desconhecida, o 
gerenciador de segurança lança uma exceção, impedindo a operação. 
A tecnologia java e configuração do ambiente 
 1-17 
A versão Java 1.1, implementa um recurso adicional à questão da 
segurança: a assinatura digital. Anexando uma assinatura digital ao código Java, 
a origem desse código pode ser estabelecida de uma forma criptograficamente 
segura e impossível de falsificar. 
Desta forma, o usuário pode definir que uma determinada pessoa ou 
organização merece sua confiança. A partir daí, o código que traz a assinatura 
digital dessa entidade merece confiança mesmo que seja carregado através da 
rede, podendo rodar sem as restrições do modelo de caixa de areia. 
Porém, quando se trata de segurança, é preciso ser realista. Da mesma 
forma que nunca se pode garantir que um programa seja 100% livre de bugs, 
nenhuma linguagem ou ambiente pode ter a garantia de ser 100% seguro. 
Dentro desses limites, Java com certeza oferece um bom nível de segurança 
para a maioria das aplicações práticas. Java antecipa e se defende contra a 
maioria das técnicas que têm sido usadas para fazer com que software tenha 
comportamento malicioso. 
A segurança de Java foi intensamente testada por experts em segurança e 
também por hackers. Desta forma, foi possível sanar alguns furos de segurança 
encontrados nas primeiras versões de Java. É igualmente razoável esperar que 
quaisquer furos que venham a ser descobertos no futuro sejam sanados com a 
mesma rapidez. 
 
A tecnologia java e configuração do ambiente 
 1-18 
O Just in Time Compiler - JIT 
 
• Traduzem bytecodes Java para instruções nativas da máquina. 
• Evitam a reinterpretação de blocos de código Java. 
• Úteis se o mesmo bloco de código é executado mais de uma vez. 
• Otimizam a execução de blocos de código repetitivos, como laços 
(for/while). 
 
 
A JVM transforma os bytecodes Java em instruções nativa de máquina. Se 
um bloco de código é executado diversas vezes, a JVM tem o trabalho 
reinterpretar este mesmo bloco de código toda vez que o fluxo de execução o 
atingir. 
Mas porque interpretar um bloco de código que não muda e já foi uma vez 
interpretado? 
Uma nova técnica, conhecida como compilação sob demanda (Just-in-
Time Compilation ou JIT Compilation), foi então desenvolvida para contornar este 
tipo de situação. Compiladores JIT, quando encontram um bloco de bytecodes 
Java pela primeira vez, o traduzem de maneira definitiva para instruções nativas 
de máquina. 
Se o mesmo bloco é executado novamente, não há porque novamente 
interpretá-lo: as instruções nativas de máquina resultado da compilação Just-in-
Time assumem o controle da execução, dispensando a necessidade de 
interpretação. Compiladores JIT aumentam o desempenho de programas Java, 
fazendo-os rodar mais rapidamente, uma vez que dispensam a necessidade de 
traduções sucessivas e “inúteis” de um mesmo bloco de bytecodes Java. 
Os ganhos de desempenho são mais significativos quando da otimização de 
laços e funções recursivas, em que um mesmo bloco de código é 
exaustivamente repetido. 
A tecnologia java e configuração do ambiente 
 1-19 
O Java Standard Development Kit – J2SDK 
 
 
 
 Abaixo temos uma figura que mostra toda a plataforma java de 
desenvolvimento. Observe que existem muitas tecnologias presentes nesta 
plataforma. Você não precisa saber todas elas para trabalhar com java. 
Colocamos esta figura de forma que você possa ver algumas importantes, as 
quais listamos abaixo: 
 
 
• [ javac ] – Compilador Java, traduz programas Java para bytecodes 
• [ java ] – Interpretador de bytecodes, para executar programas java 
• [ appletviewer ] – Visualizador de applets, lê uma página HTML, carrega o 
applet referenciado pela página e o executa, mostrando em sua própria 
tela a entrada e saída do applet 
• [ javadoc ] – Gerador de documentação, ferramenta que gera 
automaticamente documentação em HTML a partir dos comentários do 
código fonte Java 
• [ jar ] – Empacotador de aplicações java, para a geração e manutenção 
de archives (jar). O formato de arquivos JAR possibilita o agrupamento de 
múltiplos arquivos em um único, que recebe o nome de Java Archive (ou 
.jar). Desta forma, um único arquivo .jar tipicamente contém vários 
binários Java (arquivos .class) e arquivos auxiliares de recursos utilizados 
pelo applet ou application Java 
• [ javap ] – Disassembler, ferramenta recebe como entrada um binário 
Java (arquivo .class) e fornece como saída uma lista de comandos 
assembly da máquina virtual Java referentes ao binário analisado, ou uma 
lista de protótipos de classes encontradas no binário 
• [ Swing ] – Framework para criação de interfaces dráficas 
• [ Java Web Start ] – Tecnologia para distribuição de software 
• [ JDBC ] – Framework para conexão com banco de dados 
 
 
 
 
 
 
 
A tecnologia java e configuração do ambiente 
 1-20 
 
 
 
Arquitetura da tecnologia java 
 
 Na figura abaixo você tem listadas as tecnologias que fazem parte da 
versão 5.0 do Java. Estas tecnologias são parte do JRE (Java Runtime 
Environment) e do JDK ( Java Development Kit). 
 
 
Figura 1-5: Estrutura do JDK e JRE 
 
A tecnologia java e configuração do ambiente 
 1-21 
 
Figura 1-6: Relação dos grupos de tecnologias 
 
A tecnologia java e configuração do ambiente 
 1-22 
Configurando o ambiente 
 
 
 Para trabalhar com a linguagem java na sua máquina é preciso configurar 
algumas coisas antes de escrever o promeiro programa. Estas configurações não 
são necessárias na máquina do usuário que irá rodar a sua aplicação, sendo 
configurações somente para a máquina do desenvolvedor. 
 
 Você precisará adicionar as seguintes variáveis de ambiente ao sistema 
operacional que estiver utilizando: 
 
 
1) JAVA_HOME - local onde foi instalado o java na sua máquina. Esta 
variávelé utilizada por programas para localizar a máquina virtual java 
e o compilador 
 
2) CLASSPATH – esta variável contém o caminho onde estão as 
classes/bibliotecas java que o programa irá utilizar. Se você baixar 
algum pacote jar da internet com classes que desejar utilizar, será 
necessário colocar o caminho deste pacote nesta variável para que as 
classes do mesmo sejam localizadas no momento da compilação 
 
 
3) PATH – esta variável é importante estar configurada para poder rodar os 
programas que estão localizados dentro do diretório bin da sua 
instalação do java 
 
 
Versão para windows: 
 
JAVA_HOME=C:\jdk1.5 
CLASSPATH=%JAVA_HOME%\lib\tools.jar 
PATH=%JAVA_HOME%\BIN;%PATH% 
Codigo 1-1: Configuração das variáveis de ambiente para windows 
 
 
Versão para linux: 
 
JAVA_HOME=/jdk1.5 
CLASSPATH=$JAVA_HOME/lib/tools.jar 
PATH=$JAVA_HOME/bin;$PATH 
Codigo 1-2: Configuração das variáveis de ambiente para linux 
 
 
 
A tecnologia java e configuração do ambiente 
 1-23 
API’s da linguagem 
 
 Java possui um conjuntomuito grande classes para serem utilizadas no 
desenvolvimento de palicações. Estas classes estão organizadas em pacotes que 
fazem parte do JDK. Abaixo você tem alguns dos principais pacotes que serão 
utilizados para o desenvolviemtno de aplicações. Para ter uma visão do todo 
basta acessar a documentação do JDK através de um browser. Siga o seguinte 
link para isto: 
 
http://java.sun.com/j2se/1.5.0/docs/api/ 
 
 
java.applet Fornece as classes necessárias para a criação de um applet e 
para a comunicação que posteriormente se estabelece entre 
o applet e o contexto em que executa. 
 
java.awt Contém todas as classes para a criação de interfaces gráficas 
do usuário e controle de imagens. 
 
java.beans Contém as classes relacionadas aos desenvolvimento de Java 
Beans. 
 
java.io Permite entrada e saída através de data streams, serialization e 
sistema de arquivos. 
 
java.lang Classes relacionadas ao próprio projeto da linguagem Java, 
referindo-se à manipulação e conversão de tipos, strings, 
threads e ambiente de execução. 
 
java.math Classes utilizadas para aritmética de inteiros de precisão 
arbitrária (BigInteger) e para a aritmética de decimais de 
precisão arbitrária (BigDecimal) 
 
java.net Classes contendo facilidades de comunicação em rede 
(manipulação sockets, resolução de nomes, estabelecimento 
de canais de comunicação). 
 
java.security Classes e interfaces relacionadas às questões de segurança. 
 
java.sql Classes que permitem interface com o banco de dados (JDBC) 
 
java.text Classes e interfaces para manipulação de texto, datas, 
números e mensagens. 
 
java.util Miscelânea de classes auxiliares: tratamento do tempo, gerador 
de números aleatórios, vetores de bits, internacionalização do 
aplicativo, manipulação de archives Java, etc. 
 
javax.swing Conjunto de componentes visuais “peso leve” que, com o 
máximo grau de compatibilidade possível, funcionam da 
A tecnologia java e configuração do ambiente 
 1-24 
mesma maneira em todas as plataformas. 
 
Tabela 1-1: Pacotes mais comuns da API J2SDK 
A tecnologia java e configuração do ambiente 
 1-25 
Espaço para anotações
Java Fundamentals 
 
 2-1 
22.. TTiippooss ee OOppeerraaddoorreess 
 
 
 
 
 
Tipos e operadores 
 2-2 
Objetivos 
• Compreender as seguintes estruturas: 
o Variáveis 
o Tipos Primitivos 
o Literais 
• Compreender os tipos de dados primitivos: 
o char 
o boolean 
o byte, short, int, long 
o float, double 
• Compreender os tipos de dados compostos 
• Apreender conversões de tipos 
• Conceituar expressões e operadores 
• Definir precedência e associatividade entre estruturas 
Tipos e operadores 
 2-3 
Variáveis 
 
Java é uma linguagem fortemente tipada. 
Isto significa que a utilização de qualquer variável deve ser compatível com 
a sua prévia definição. 
Compete ao compilador da linguagem verificar, antes mesmo da execução 
do programa (isto é, de maneira estática), se há a referida compatibilidade entre 
definição e uso de uma variável. 
Os contextos em que uma variável pode ser validamente empregada são 
determinados pelo seu tipo. O tipo determina a utilização: restringe as operações 
aplicáveis e concede sentido ao resultado de uma operação válida (semântica 
da operação). Seria contra-senso somarmos um tipo booleano com outro tipo 
booleano ou, ainda pior, multiplicarmos um booleano por um número fracionário. 
Qual a resposta esperada para estas operações? 
Não há resposta, porque a operação frente aos tipos carece de coerência. 
Ao definirmos um inteiro (ou um número real, ou um booleano, etc.), estamos a 
dizer quais operações são válidas quando aplicadas a este inteiro (real, 
booleano, etc.) e quais simplesmente carecem de sentido. 
Decorrem do fato de Java ser fortemente tipada: 
• Todas as variáveis em Java devem ter um tipo associado (a fim de que se 
possa avaliar futuramente se os empregos dados a esta variável são ou 
não corretos) 
• A utilização de uma variável deve ser posterior à sua definição 
• As conversões forçadas de tipo (casts) devem ser rigidamente controladas 
pela linguagem, tanto sob o aspecto estático (não se permitindo 
conversões entre tipos distintos, e autorizando tão somente a conversão 
entre tipos derivados), quanto sob o aspecto dinâmico (controle em 
tempo de execução das conversões de tipo efetuadas). 
• Não se permitem conversões implícitas de tipo. Todas as conversões de 
tipo devem ocorrer de maneira expressa. 
Tipos e operadores 
 2-4 
Tipos primitivos e tipos compostos 
 
Tipos primitivos são aqueles tipos já embutidos na linguagem java e 
estudados no capítulo anterior, enquanto tipos compostos são todas as classes 
da linguagem java ou classes que você venha a criar. 
Variáveis de tipos primitivos são tratadas de uma maneira bem diferente de 
variáveis de referências para objetos ( variáveis de tipos compostos). É bastante 
importante saber quais são estas diferenças e porque Java foi projetada desta 
forma. 
 
Variáveis de tipos primitivos 
 
Quando você declara uma variável de um tipo primitivo, Java aloca um 
pedaço de memória que é grande o suficiente para guardar valores do tipo 
primitivo declarado. Se você define uma variável de tipo primitivo como uma 
variável de instância, a variável é inicializada para 0 se for inteira, para false se 
for booleana e para '\0' se for caractere. 
Variáveis de tipos primitivos armazenam o seu valor diretamente. Se você, 
por exemplo, declara uma variável do tipo int e atribui um valor 3 para esta 
variável, o valor é armazenado diretamente nos quatro bytes reservados para a 
variável. 
 
Variáveis de referências para objetos (tipos compostos) 
 
Quando você declara uma variável de referência, você também recebe 
um pedaço de memória, mas esta memória é grande o suficiente para 
armazenar apenas uma referência para o objeto. Talvez seja útil pensar em uma 
referência como um apontador para o objeto. 
Como mencionado antes, declarar uma variável de referência não cria um 
objeto do tipo especificado. Conseqüentemente, uma variável de instância é 
inicializada para null a fim de indicar que ainda não recebeu referência para 
nenhum objeto ainda. 
Tipos e operadores 
 2-5 
Use o operador de atribuição para fazer com que uma variável de 
referência se refira a uma instância de uma classe. A atribuição pode ser para 
um objeto existente ou para um objeto recém criado através do operador new. 
Tipos e operadores 
 2-6 
Tipos Primitivos 
 
 
Tipos primitivos são aqueles fornecidos diretamente pela linguagem, ou seja, 
tipos já embutidos na linguagem. São tipos atômicos, indivisíveis e sobre os quaisa linguagem, de ante mão, já oferece operações pré-definidas. Exemplos de 
tipos primitivos são inteiros e booleanos. Para usá-los, basta associá-los a uma 
variável. A maior parte das linguagens permite ao programador criar tipos 
compostos. Tipos compostos procuram representar de maneira conjunta e 
unificada os vários atributos de uma entidade modelada. Um catálogo telefônico 
pode ser representado dentro de um programa como uma lista de Strings 
contendo nomes, outra contendo os endereços e, por fim, uma outra contendo 
os telefones. 
Todas as informações necessárias à pesquisa ou à manipulação do 
catálogo estão presentes em tais listas. Mas esta definitivamente não é a melhor 
maneira de se representar um catálogo telefônico. Se perguntarmos a alguém o 
que é um catálogo, dificilmente ouviremos como resposta uma lista de nomes, 
endereços e telefones. 
A resposta mais provável é uma lista de assinantes. Um assinante, por sua 
vez, é identificado pelo nome que possui ou endereço onde reside. Ao 
procurarmos descobrir o telefone de um assinante, pesquisaremos pelas chaves 
que o identificam: nome ou endereço. A representação estruturada da 
informação é, em si, informação relevante. Ao modelarmos um catálogo como 
uma lista de assinantes e identificarmos um assinante pelo seu nome ou 
endereço, estamos trazendo para dentro do programa não apenas informação 
contida em um catálogo, mas também a própria estrutura de um catálogo: 
informação sobre como a informação é organizada. 
Os tipos compostos não são apenas armazéns de dados. A sua função 
principal não é conter o dado, pois para isto já temos tipos primitivos. O seu 
objetivo principal é organizar a informação. Aproximar a estrutura empregada na 
confecção do modelo da estrutura existente no mundo real modelado. Tornar a 
tarefa de programar mais intuitiva, permitindo uma relação direta entre o modelo 
e o objeto modelado. A representação do dado dentro do programa facilita a 
compreensão do próprio programa como modelo. Não basta fazer um programa 
(modelo) que funcione. É necessária tanto uma compreensão do mundo real 
através do programa, quanto uma compreensão do próprio programa como 
modelo do mundo real. 
Tipos compostos são construídos tendo como blocos construtores tipos 
primitivos ou, de maneira recursiva, outros tipos compostos. Em última análise, os 
tipos primitivos são os únicos responsáveis pela construção dos tipos compostos. 
Um tipo composto nada mais é que um conjunto organizado de tipos primitivos. 
Tipos compostos serão vistos em capítulos posteriores. 
Tipos e operadores 
 2-7 
Java possui oito tipos primitivos: boolean, char, byte, short, int, long, 
float e double. Cada um destes tipos será estudado de maneira mais 
detalhada nas seções seguintes. A tabela abaixo apresenta um resumo dos tipos 
primitivos encontrados na linguagem Java. 
Cumpre observar que o tamanho do tipo em bytes e a sinalização fazem 
parte da especificação da linguagem. 
Ou seja, um char em Java ocupará sempre 16 bits, um int 32 bits, um long 
64 bits, e assim por diante, independente da plataforma em que o programa 
esteja sendo executado. 
Tipos e operadores 
 2-8 
Tabela 2-1: Tipos primitivos e suas características. 
Ao contrário do que acontece com outras linguagens de programação, as 
características dos tipos de dados listados acima idependem da plataforma em 
que o programa deverá ser executado. 
Dessa forma, os tipos de dados primitivos são realmente únicos e garantem a 
capacidade de intercâmbio de informações entre diversos tipos de 
Tipo Contém Default Tamanho Faixa de valores 
boolean true ou false false 1 bit Pode assumir o valor true ou o 
valor false 
char caracter Unicode \u0000 16 bits Serve para a armazenagem de 
dados alfanuméricos. Também 
pode ser usado como um dado 
inteiro com valores na faixa 
entre: 
0 e 65535 (\u0000 a \uFFFF) 
byte inteiro com sinal 0 8 bits Inteiro de 8 bits em notação de 
complemento de dois. Pode 
assumir valores entre: 
-27 a 27-1 
short inteiro com sinal 0 16 bits Inteiro de 16 bits em notação 
de complemento de dois. Os 
valores possívels cobrem a 
faixa entre: 
-215 a 215-1 
int inteiro com sinal 0 32 bits Inteiro de 32 bits em notação 
de complemento de dois. Pode 
assumir valores entre: 
-231 a 231-1 
long inteiro com sinal 0 64 bits Inteiro de 64 bits em notação 
de complemento de dois. Pode 
assumir valores entre: 
-263 a 263-1 
float ponto flutuante 0.0 32 bits Representa números em notação 
de ponto flutuante. A sua 
representação é exponencial, 
sendo alguns bits utilizados 
para base e outros para o 
expoente. 
double ponto flutuante 0.0 64 bits Representa números em notação 
de ponto flutuante. A sua 
representação é exponencial, 
sendo alguns bits utilizados 
para base e outros para o 
expoente. 
Tipos e operadores 
 2-9 
computadores, aliviando o programador da preocupação e da árdua tarefa de 
converter dados em formatos apropriados para a portagem. 
Tipos e operadores 
 2-10 
Declarando um tipo primitivo 
 
 
São oito os tipos primitivos de Java: boolean, char, byte, short, int, long, 
float e double. Quarenta e quatro são os operadores que podem ser utilizados 
na manipulação destes tipos primitivos. 
Declarar e inicializar uma variável de um tipo primitivo é extremamente fácil. 
Basta, a exemplo da seguinte linha de código, associar ao identificador escolhido 
pelo usuário para a variável um dos tipos acima, atribuindo, logo em seguida, um 
literal para esta variável. 
 Código 2-1: Literais primitivos. 
 
O que é uma literal? 
 
Uma resposta simples seria: constantes para cada um dos tipos primitivos de 
uma linguagem. Na verdade, literais são construções sintáticas fornecidas pela 
linguagem para exprimir valores constantes para cada um dos tipos primitivos. 
Tais construções determinam como devem ser escritos um caractere, um inteiro, 
um valor booleano, etc. 
A maior parte das linguagens permite que haja mais de uma forma de se 
escrever um valor inteiro, ora transcrevendo o valor inteiro em uma base de 
numeração Octal, ora transcrevendo-o em uma base Decimal, ora em uma base 
Hexadecimal. 
O mesmo ocorre para os números em ponto flutuantes: a maior parte das 
linguagens permite que ora sejam escritos em notação convencional (parte 
inteira + caractere separador + parte fracionária), ora em notação científica 
(número fracionário + expoente em potência decimal). 
 
Conjunto de Caracteres Unicode 
 
Tipos e operadores 
 2-11 
Os programas Java são escritos usando o conjunto de caracteres Unicode. 
Ao contrário da codificação de 7 bits ASCII, que é útil somente para a língua 
inglesa, e codificações de 8 bits, tais como ISO Latin-1, que é útil somente para a 
maior parte das línguas da Europa Ocidental, a codificação Unicode, de 16 bits, 
consegue representar praticamente todas as linguagens de uso freqüente no 
planeta. Entretanto, poucos editores de texto suportam caracteres Unicode, e na 
prática, a maior parte dos programas são escritos em ASCII. 
Os caracteres Unicode, de 16 bits, são usualmente escritos em arquivos 
usando uma codificação conhecida como UTF-8, que converte os caracteres de 
16 bits em uma seqüência de bytes. O formato é projetado de forma que um 
texto escrito em ASCII ou em ISO Latin-1 são seqüências de bytes UTF-8 válidas. 
Desta forma, você pode simplesmente escrever programas em ASCII e eles 
se comportarão, graças às características de projeto da codificação UTF-8, como 
textos Unicode válidos. 
Se você quiser inserir um caracter Unicode dentro de um programa Java 
escrito em ASCII, basta usar a seqüência de escape especial para caracteres 
Unicode \uxxxx. Isto é, uma contrabarra mais a letra u em minúscula seguida de 
quatro caracteres hexadecimais.A seqüência de escape \u0020 representa caracter de espaço, e a 
seqüência \u3c00 é o caracter pi. Você pode usar caracteres Unicode em 
qualquer lugar em um programa Java, incluindo comentários e nome de 
variáveis. 
Podemos encontrar a tabela unicode no seguinte endereço: 
http://www.unicode.org 
Tipos e operadores 
 2-12 
Tipo caracter – char 
 
O tipo char representa caracteres Unicode. É motivo de surpresa para 
experientes programadores descobrir que valores char em Java possuem 16 bits 
de extensão. 
Na prática, no entanto, isto fica completamente transparente.Um literal 
caracter em Java sempre vem entre aspas simples. 
Código 2-2: Declarando um tipo char 
 
Você pode, é claro, usar qualquer caracter Unicode como um literal 
caracter, sendo necessário tão somente o emprego de seqüências de escape 
\uxxxx Unicode. 
Java suporta também várias outras seqüências de escape que facilitam a 
representação de caracteres ASCII não visíveis, tais como nova linha ou 
backspace, e permitem o escape na construção de literais contendo caracteres 
de pontuação com significado especial, tais como aspas duplas ( “ ) e aspas 
simples ( ‘ ). 
Por exemplo: 
Código 2-3: Exemplos de char especiais 
 
char a = ′A′, espaco = ′ ′; 
 
char tab = ′\t′, apostrofe = ′\′′, nulo = ′′; 
char unicode = ′\u05D0′; 
 
Tipos e operadores 
 2-13 
A tabela abaixo mostra os caracteres de escape que podem ser utilizados 
na construção de um literal caracter. 
 
Seqüência de 
escape 
Valor do caracter 
\b backspace 
\t tabulação horizontal 
\n nova linha 
\f alimentação de formulário 
\r retorno de carro 
\” aspas duplas 
\’ aspas simples 
\\ contrabarra 
\uxxxx Caracter Unicode com codificação xxxx, onde xxxx são quatro dígitos 
hexadecimais. 
Tabela 2-2: Caracteres de escape do tipo char 
 
Estas seqüências de escape podem também ser usadas em literais para 
Strings. 
Valores do tipo char não podem ser convertidos para e a partir de tipos 
inteiros. Ao contrário de byte, short, int e long, o tipo char é um tipo não 
sinalizado (unsigned). 
A classe Character vários métodos estáticos (static methods) para trabalhar 
com caracteres, incluindo isLowerCase() e toUpperCase(). 
Tipos e operadores 
 2-14 
Tipo booleano – boolean 
 
O tipo boolean procura representar predicados. Há somente dois valores 
possíveis para este tipo, representando os dois estados booleanos: ligado ou 
desligado, sim ou não, verdadeiro ou falso. 
Java reserva as palavras true e false para representar estes dois valores 
booleanos. 
Programadores C e C++ devem ter notar que Java é bem restritiva quanto à 
utilização do tipo booleano: valores booleanos não podem ser diretamente 
convertidos para outros tipos de dados, nem estes podem ser convertidos para 
booleanos. 
Em especial, o valor booleano não é um tipo inteiro (onde false é 
representado por 0 e true por qualquer valor diferente de 0), e valores inteiros 
não podem ser usados no lugar de um valor booleano. 
Os exemplos abaixo mostram a utilização incorreta de valores booleanos. No 
primeiro exemplo, um booleano é esperado e um inteiro é fornecido. 
 
Errado Correto 
int i = 10; 
while(i) { 
 ... 
 i--; 
} 
int i = 10; 
while(i!=0) { 
 ... 
 i--; 
} 
Tabela 2-3: Utilização do tipo boolean em C++ e Java 
 
Não há (como ocorre com C e C++) conversão, implícita ou forçada, entre 
booleanos e inteiros (ou outro tipo primitivo qualquer). 
 
Tipos e operadores 
 2-15 
Tipos inteiros - byte, short, int e long 
 
Os tipos inteiros em Java são byte, short, int e long. Os tipos inteiros 
diferem exclusivamente no número de bits usados para a representação do 
número e, portanto, na extensão da faixa de números que conseguem 
representar. Todos os tipos inteiros são sinalizados. 
Não existe em Java nada equivalente à especificação unsigned de C ou 
C++. 
Literais inteiros para cada um destes tipos são construídos da maneira 
esperada: uma seqüência de números decimais. Qualquer literal inteiro pode ser 
precedido por um operador unário menos, a fim de indicar um número negativo. 
Alguns literais inteiros: 
Código 2-4: Literais inteiros int 
 
Literais inteiros podem ser expressos também em notação octal ou 
hexadecimal. Um literal que começa com 0x ou 0X é interpretado como um 
número hexadecimal, valendo-se das letras A a F (ou a a f) para os dígitos 
restantes requeridos em números de base 16. 
Literais inteiros que têm um dígito 0 em seu início são interpretados como 
números octais (base 8) e, portanto, entre os dígitos subseqüentes não podem 
figurar os algarismos 8 e 9. Java não permite que literais inteiros sejam expressos 
em notação binária (base 2). Literais inteiros octais e decimais válidos: 
Código 2-5: Literais inteiros int em hexa e octal 
 
Literais inteiros exprimem valores de 32 bits, a menos que terminem com o 
caracter L ou l, indicando, neste caso, serem tais literais valores de 64 bits. 
0 
1 
-123 
-4200 
0xff // decimal 255 expresso em hexa 
0377 // mesmo número expresso em octa 
1234 // um valor int 
1234L // um valor long 
0xffL // outro valor long 
Tipos e operadores 
 2-16 
Código 2-6: Literais inteiros int e long 
A aritmética inteira em Java é modular. Não há transbordo ou estouro na 
manipulação de números inteiros. 
Ao contrário, ao exceder a faixa de um determinado tipo inteiro, em uma 
das extremidades, o resultado da operação avança de maneira circular sobre a 
extremidade oposta. 
Por exemplo: 
Código 2-7: Exemplo de expressão byte com aritmética circular 
 
Nem o compilador Java, nem a JVM avisará quando ocorrer transbordo em 
aritmética inteira. Desta maneira, ao manipular inteiros, você deve ter certeza 
que o tipo que está usando é grande o suficiente para os propósitos que tem em 
mente. Que a faixa de números oferecida pelo tipo é larga o suficiente para as 
operações pretendidas. 
Divisões inteiras por zero e operações módulo zero não são aceitas e lançam 
a exceção ArithmeticException. 
Cada tipo inteiro tem uma classe invólucro correspondente (wrapper 
classes): Byte, Short, Integer e Long. Cada uma dessas classes define as 
constantes MIN_VALUE e MAX_VALUE que descrevem as extremidades da faixa de 
números suportada pelo tipo. 
Estas classes também definem vários métodos estáticos extremamente úteis, 
tais como Byte.parseByte() e Integer.parseInt(), empregados na 
conversão de strings para inteiros. 
byte b1 = 127, b2 = 1; 
byte sum = b1 + b2; 
// sum = -128, que é o menor byte 
 
Tipos e operadores 
 2-17 
Tipos de ponto flutuante - float e double 
 
Números reais são representados em Java com os tipos float e double. 
Como mostrado anteriormente, o tipo float representa um valor de ponto 
flutuante, de 32 bits, de precisão simples, enquanto o tipo double representa um 
valor de ponto flutuante de 64 bits, de precisão dupla. Ambos os tipos seguem o 
padrão IEEE 754-1985, que especifica tanto o formato dos números quanto o 
comportamento da aritmética com estes números. 
Literais de ponto flutuante podem ser representados em Java como uma 
seqüência opcional de dígitos decimais seguido por um ponto e outra seqüência 
de dígitos decimais. 
Alguns exemplos: 
Código 2-8: Literais float e double 
 
Literais de ponto flutuante também podem ser representados através de 
notação científica, na qual um número é seguido pela letra e ou E (assinalando o 
expoente) e por um outro número. Este segundo número representa a potência 
de dez pela qual o primeiro número é multiplicado. 
Por exemplo: 
Código 2-9: Literais float em notação científica 
 
Números de ponto flutuante são double por default. Para representar um 
literal de ponto flutuante floatem um programa, basta acrescentar o caracter 
f ou F no final do número. 
Código 2-10: Literais float e double em notação científica 
 
Literais de ponto flutuante não podem ser representados em notação 
hexadecimal ou octal. A maior parte dos números reais, pela sua natureza, não 
123.45f // float 
0.0 // double 
.02 // double 
1.2345E02 // 1.2345 x 102 ou 123.45 
1e-6 // 1 x 10-6 ou 0.000001 
6.02e23 // No. de Avogrado 6.02 x 1023 
double d = 6.02e23; 
float f = 6.02e23f; 
Tipos e operadores 
 2-18 
pode ser representada exatamente em um número finito de bits. Portanto, é 
importante se lembrar que os valores double e float são apenas aproximações 
dos números que eles procuram efetivamente representar. 
Um float é uma aproximação de 32 bits, o que resulta em pelo menos 6 
dígitos decimais significativos, e o double é uma aproximação de 64 bits, o que, 
por sua vez, resulta em pelo menos 15 dígitos decimais significativos. Na prática, 
estes tipos são suficientes para a maior parte das computações de ponto 
flutuante. 
Tipos e operadores 
 2-19 
Tipo composto – String 
 
Além dos tipos primitivos caracter, booleano, inteiro e real, Java também 
possui um tipo de dado próprio para trabalhar com seqüências de texto (Strings). 
O tipo String, no entanto, não é um tipo primitivo da linguagem. Devido 
ao uso extremamente freqüente de Strings em um programa, Java permite uma 
sintaxe especial para a representação de literais Strings. Um literal String consiste 
de uma porção arbitrária de texto delimitada por aspas duplas. 
Por exemplo: 
Código 2-11: Literias Strings 
 
Literais Strings podem conter qualquer uma das seqüências de escapes 
permitidas para um valor char. Utilize a seqüência \" para incluir aspas duplas 
dentro de um literal String. String e literais Strings serão discutidos com mais 
detalhes a seguir. 
"Hello, World" 
"Isto é uma string \n" 
Tipos e operadores 
 2-20 
Conversões de tipos – casting 
 
Java permite conversão entre valores inteiros e valores reais. Além disto, por 
corresponder todo caracter a um número na codificação Unicode, o tipo char 
pode ser convertido para e a partir de um tipo inteiro ou de ponto flutuante. De 
fato, o tipo boolean é o único tipo que não pode ser convertido para ou a partir 
de um outro tipo primitivo em Java. Há dois tipos de conversão. 
Uma conversão de ampliação (widening conversion) ocorre quando um 
valor de um tipo é convertido para outro tipo mais amplo  um tipo que possui 
mais bits de representação e, portanto, uma faixa mais ampla de valores 
representados. 
Uma conversão de redução (narrowing conversion) ocorre quando um valor 
é convertido para outro que possui menos bits de representação. Java 
automaticamente se encarrega das conversões de ampliação quando, por 
exemplo, uma variável double recebe um valor int, ou um literal char é 
atribuído a uma variável int. 
Conversões de redução são um problema a parte, e nem sempre são 
seguras. É razoável, por exemplo, converter o valor inteiro (int) 13 para um byte, 
mas não o é fazer a mesma conversão para o valor 13000, pois o tipo byte 
suporta somente valores entre –128 e 127. A informação pode ser perdida em 
conversões de redução e o compilador Java sempre reclama quando há uma 
tentativa de efetuar uma conversão de redução, ainda que o valor sendo 
convertido se situe entre os valores aceitos pela faixa mais estreita do novo tipo. 
Código 2-12: Atribuição de valor inteiro int não permitida para byte 
 
A única exceção a esta regra é que você pode atribuir um literal inteiro 
(portanto, um valor int) para uma variável byte e short, se o literal pertencer à 
faixa de representação desta variável. Se você precisa de conversões de 
redução e está confiante que o pode fazer sem perda de informação ou 
precisão, você pode forçar Java a executar a conversão usando uma 
construção da linguagem conhecida como cast (conversão explícita). 
A conversão explícita é feita colocando-se o nome do tipo pretendido entre 
parênteses antes da variável a ser convertida. 
Por exemplo: 
int i = 13; 
byte b = i; // Erro em tempo de compilação. 
int i = 13; 
byte b = (byte) i; 
i = (int) 13.456; 
Tipos e operadores 
 2-21 
Código 2-13: Conversão forçada de tipos primitivos 
Casting de tipos primitivos são mais freqüentes em conversões de números 
reais para inteiros. Quando isto ocorre, a parte fracional do número real é 
simplesmente truncada (o valor de ponto flutuante é arredondado para zero e 
não para o inteiro mais próximo). Os métodos Math.round(), Math.floor() e 
Math.ceil() permitem outros tipos de arredondamento. 
Código 2-14: Atribuição de valores implícitos e expressos 
 
O tipo char funciona como um tipo inteiro a maior parte das vezes, 
podendo, portanto, ser usado em qualquer lugar em que se espere um int ou 
long. 
Lembre-se, no entanto, que o tipo char é não sinalizado e se comporta de 
maneira diferente do tipo short, embora ambos possuam 16 bits. 
short s = (short) 0xffff; 
char c = '\uffff'; 
 
 
int i1 = s; 
int i2 = c; 
Tipos e operadores 
 2-22 
Tipos de referência 
 
Além dos oito tipos primitivos, Java define duas outras categorias de tipos: 
classes e vetores. Programas em Java são construídos através de definições de 
classes; cada classe define um novo tipo de dado que pode ser manipulado por 
programas Java. 
Um programa pode, por exemplo, definir uma classe chamada Ponto e usá-
la para armazenar coordenadas (x,y) de um sistema cartesiano de coordenadas. 
Com isto, Ponto passa a ser um novo tipo de dado em um programa. 
Um tipo vetor representa uma lista de valores de um determinado tipo. int é 
um tipo de dado, e um vetor de valores do tipo int é outro tipo de dado, escrito 
em Java como int[]. Um vetor de objetos do tipo Ponto também é um tipo, 
escrito como Ponto[]. E um vetor de vetores de Ponto é também um outro tipo, 
escrito em Java como Ponto[][]. 
Como você pode ver, há um número infinito de tipos de dados de classes e 
vetores possíveis. Basta o programador defini-los. Estes tipos são conhecidos 
coletivamente como tipos de referência. 
A razão para este nome ficará clara logo a seguir. Por enquanto, é 
importante compreender apenas que classes e vetores são tipos de dados 
diferentes dos tipos primitivos. Tipos de dados de classes e vetores são conhecidos 
como tipos compostos. Um tipo de dado primitivo guarda somente um único 
valor. 
Classes e vetores são tipos agregados que contém vários valores. O tipo 
Ponto, por exemplo, armazena dois valores double representando as 
coordenadas x e y do ponto. Classes e vetores serão retomados logo adiante. 
Código 2-15: Tipos de referências: arrays e Strings 
 
int[] vet = {1,2,3}; 
String str = new String(“Java”); 
 
 
Tipos e operadores 
 2-23 
Expressões e operadores 
Até o presente momento, aprendemos sobre os tipos primitivos que os 
programas Java são capazes de manipular e vimos como construir literais para 
cada um destes tipos. Utilizamos também variáveis, nomes simbólicos que 
representam e armazenam um valor. 
Literais e variáveis são importantes tokens com os quais programas são 
construídos em Java. 
Expressões são o próximo nível de estrutura de um programa Java. O 
interpretador Java (JVM) avalia uma expressão para determinar o seu resultado. 
As expressões mais simples são chamadas expressões primárias e consistem de 
apenas um literal ou uma variável. 
São exemplos de expressões primárias: 
Código 2-16: Expressões primárias 
 
Quando o interpretador Java avalia uma expressão literal, o resultado da 
avaliação é o próprio literal. Quando o interpretador avalia uma expressão 
contendo umavariável, o resultado da avaliação é o resultado armazenado 
nesta variável. 
Expressões primárias não são muito interessantes. Expressões mais complexas 
são construídas utilizando operadores para combinar expressões primárias. Por 
exemplo, a seguinte expressão usa o operador de atribuição ( = ) para combinar 
duas expressões primárias – uma variável e um literal de ponto flutuante – em 
uma expressão de atribuição. 
Código 2-17: Expressão de atribuição 
 
Mas operadores não são usados apenas com expressões primárias; eles 
também podem ser usados com expressões de qualquer nível de complexidade. 
As seguintes construções são, portanto, expressões válidas. 
1.7 
'A' 
true 
sum 
sum = 1.7 
sum = 1 + 2 + 3 * 1.2 + (4 + 8) / 3.0; 
sum = (sum / Math.sqrt(3.0 * 1.234) ); 
sum = (int) (sum + 33); 
Tipos e operadores 
 2-24 
Código 2-18: Expressões válidas e combinadas 
Tipos e operadores 
 2-25 
Sumário de operadores 
Os tipos de expressões que você pode escrever em uma linguagem de 
programação dependem completamente do conjunto de operadores que a 
linguagem disponibiliza. A tabela abaixo apresenta síntese dos operadores 
disponíveis em Java. A colunas P e A desta tabela indicam, respectivamente, a 
precedência e a associatividade de cada grupo de operadores correlatos. Neste 
curso veremos alguns operadores listados na tabela abaixo, os demais serão 
vistos a medida do estudo da linguagem. 
 
Operadores Tipo de 
operando 
Operação executada 
. objeto, membro acesso a membro do objeto 
[] vetor, inteiro acesso a elemento do vetor 
( args ) método, lista de 
args 
invocação do método 
++, -- variável pós incremento, pós decremento 
++, -- variável pré incremento, pré decremento 
+, - número mais unário, menos unário 
~ inteiro complemento (NOT bit a bit) 
! booleano NOT booleano 
new classe, lista de args criação de objetos 
(type) tipo, qualquer 
coisa 
cast (conversão explícita de tipo) 
*, /, % número, número multiplicação, divisão e resto 
+, - número, número adição e subtração 
+ string, qqr coisa concatenação de strings 
<, <= número, número menor que, menor que ou igual 
>, >= número, número maior que, maior que ou igual 
instanceof referência, tipo comparação de tipos 
== primitivo, primitivo igual (o mesmo valor) 
!= primitivo, primitivo não igual (valores diferentes) 
Tipos e operadores 
 2-26 
== referência, 
referência 
igual (o mesmo objeto) 
!= referência, 
referência 
não igual (objetos diferentes) 
& inteiro, inteiro AND bit a bit 
& booleano, 
booleano 
AND booleano 
^ inteiro, inteiro XOR bit a bit 
^ booleano, 
booleano 
XOR booleano 
| inteiro, inteiro OR bit a bit 
| booleano, 
booleano 
OR booleano 
&& booleano, 
booleano 
AND booleano com curto circuito 
|| booleano, 
booleano 
OR booleano com curto circuito 
? : booleano, qqr 
coisa, qqr coisa 
operador ternário condicional 
= variável, qqr coisa atribuição 
*=, /=, %=, +=, 
-=, <<=, >>=, 
>>>=, &=, ^=, 
|= 
variável, qqr coisa atribuição geminada com operação 
 Tabela 2-4:Sumário de Operadores 
Tipos e operadores 
 2-27 
Precedência 
 
A precedência indica a ordem na qual as operações são executadas. 
Considere a seguinte expressão: 
Código 2-19: Expressão com precedência 
 
O operador de multiplicação tem prioridade mais alta que o operador de 
adição, logo a é somado ao resultado da multiplicação de b e c. 
A precedência de um operador pode ser pensada como uma medida de 
quão firmemente está ligado o operador aos seus operandos. 
Quanto maior a precedência de um operador, mais firmemente ele está 
ligado aos seus operandos. 
A precedência default de um operador pode ser afastada através do uso 
de parêntesis, de forma a explicitar a ordem exata das operações. A expressão 
anterior pode ser rescrita como se segue, determinando explicitamente que a 
adição deve ocorrer aqui antes da multiplicação. 
 
Código 2-20: Expressão utilizando parêntesis 
 
A precedência default dos operadores de Java foi escolhida procurando 
torná-la compatível com C. Os projetistas de C, ao determinar a precedência 
default de cada um dos operadores, tiveram em mente a maneira mais fácil e 
direta de se escrever expressões sem a necessidade do uso de parêntesis. 
Há apenas algumas expressões em Java em que se faz necessária a 
presença de parêntesis. 
a + b * c 
(a + b) * c 
Tipos e operadores 
 2-28 
Associatividade 
Quando uma expressão contém vários operadores que têm a mesma 
precedência, a associatividade dos operadores indicarão a ordem na qual as 
operações serão executadas. A maior parte dos operadores tem associatividade 
da esquerda para direita, o que significa que as operações são feitas da 
esquerda para a direita. Operadores unários e de atribuição possuem, 
entretanto, associatividade da direita para esquerda. 
Os operadores aditivos possuem associatividade da esquerda para direita, 
sendo a expressão a+b-c avaliada da esquerda para direita: (a+b)-c. 
Operadores unários e de atribuição são avaliados da direita para a esquerda. 
Considere a seguinte expressão: 
Código 2-21: Associatividade com incremento 
 
O valor das variáveis seria: 
Código 2-22: Resultado depois da execução do código acima 
 
 
 
A associatividade, assim como a precedência, estabelece a ordem default 
de avaliação para uma expressão. Esta ordem default pode ser afetada com o 
uso de parênteses. Entretanto, a escolha da precedência e da associatividade 
conduz a uma sintaxe mais natural, e raramente você precisará alterá-la. 
int a = 5; 
int b = 4; 
int c = a++ + b++ 
a = 6 
b = 5 
c = 9 
 
Tipos e operadores 
 2-29 
Tipos de operadores: unários e binários 
A quarta coluna da tabela acima especifica o número e o tipo dos 
operandos esperados para cada operador. Alguns operadores atuam somente 
sobre um único operando; são chamados operadores unários. 
A maior parte dos operadores, no entanto, são operadores binários e atuam 
sobre dois operandos. 
 
Exemplo operador unário: i++ é igual a i = i + 1 
Exemplo operador binário: res = x + y 
 
Tipos e operadores 
 2-30 
Espaço para anotações 
Tipos e operadores 
 2-31 
Java Fundamentals 
 
 3-1 
33.. CCrriiaannddoo ccllaasssseess ee oobbjjeettooss 
Criando classes e objetos 
 3-2 
Objetivos 
 
 
• Definir classes, atributos e operações 
• Trabalhar com pacotes 
• Conhecer padrões para codificação 
• Aplicar visibilidade a classes, atributos e operações 
• Comentar os códigos fonte 
• Gerar documentação do código fonte 
• Estudar o escopo das variáveis 
Criando classes e objetos 
 3-3 
Classes e Objetos 
 
Uma classe é um gabarito utilizado para criar múltiplos objetos. Uma classe 
encapsula todos os dados e comportamentos que definem um objeto. Quando 
você pede ao interpretador Java para criar ou instanciar um objeto, Java usa a 
definição de classes como gabarito para a criação de novos objetos. 
Uma classe pode conter atributos que são atribuídos a todos os novos 
objetos desta classe. Atributos são informações ou dados que descrevem, 
categorizam ou quantificam um objeto. Cada novo objeto de uma dada classe 
terá seu próprio conjunto de atributos de classe. Um objeto da classe Cliente, por 
exemplo, terá um nome, um endereço e um número telefônico como atributos. 
Dados armazenados em um objeto podem ser tanto primitivos, tais como 
inteiros ou caracteres, ou referências para outros objetos. 
Uma classe pode conter também métodos ou funções que especifiquem o 
comportamento ou ações que a classe consegue realizar. A classe Cliente, por 
exemplo, pode alugar um carro, efetuar um pagamento ou alteraro seu 
endereço. 
Java utiliza pacotes para agrupar classes que estão logicamente 
relacionadas. Pacotes consistem de classes fisicamente localizadas em um 
mesmo diretório. Pacotes também são usados para controlar o acesso de classes 
definidas fora do pacote. 
Criando classes e objetos 
 3-4 
Criando uma classe 
 
O bloco contendo a definição de uma classe começa pela palavra 
reservada class. No código abaixo temos a criação de uma classe para 
reprensentar um Produto. 
Código 3-1: Declaração da classe Produto 
 
Uma classe – o bloco de construção básico para uma linguagem orientada 
a objetos – é uma coleção de dados e de métodos que manipulam estes dados. 
A classe é um modelo abstrato, a partir do qual serão criadas instâncias desta 
classe, contendo os dados e os métodos nela definidos. 
Observe que a definição da classe acima é muito simples e a mesma é feita 
através da palavra reservada class. O par de chaves utilizado serve para 
delimitar o corpo da classe, ou seja, onde iremos colocar as operações e 
atributos da mesma. Veremos mais adiante como colocar os atributos e 
operações 
Os dados referentes a uma classe são armazenados em variáveis e as 
operações efetuadas sobre estes dados são implementadas através de métodos. 
Seguindo os passos contidos nesta lição você conseguirá criar e executar 
sua primeira Java Application. Para isto vamos adicionar um método especial 
nesta classe que nos permitirá executar a máquina virtual e executar algum 
código. 
Tomaremos como exemplo, para a primeira Java Application, o consagrado 
“Hello World”. Este programa, bastante simples, imprime na tela do computador a 
mensagem “Hello World”. Usando um editor de texto, crie um arquivo de nome 
HelloWorld.java contendo as seguintes linhas. 
Código 3-2: Exemplo de HelloWorld Java 
class Produto { 
 
} 
class HelloWorld { 
 
 public static void main( String[] args ) { 
 System.out.println( "Hello World!" ); 
 } 
 
} 
Criando classes e objetos 
 3-5 
 
O arquivo fonte pode ser compilado através de seu IDE ou usando o 
compilador javac através de linha de comando como mostrado abaixo 
Código 3-3: Compilando uma classe Java 
Obtendo êxito na compilação, o arquivo HelloWorld.class, contendo os 
bytecodes Java, será criado pelo compilador no mesmo diretório em que se 
encontra o arquivo fonte. 
Caso o compilador tenha reportado alguma falha, verifique se não digitou 
algo incorretamente, prestando atenção para o uso de maiúsculas e minúsculas. 
Certifique-se também de ter dado ao arquivo o nome correto. Execute a 
aplicação Java usando a máquina virtual fornecida pelo JDK (java): 
Código 3-4: Executando uma classe Java sem pacote 
 
Você verá a mensagem “Hello World!” escrita na tela de seu computador. 
 
C:\> javac HelloWorld.java 
 
C:\>java HelloWorld 
Hello World! 
Criando classes e objetos 
 3-6 
Padrões 
 
 
 A linguagem java segue padrões para escrita de código especificados 
pela Sun, empresa criadora da linguagem java. Desenvolvedores devem 
procurar seguir estes padrões, uma vez que todo código de APIs que existem 
seguem este padrão para facilitar o endendimento dos mesmos bem como a 
leitura destes códigos. 
 
O compilador Java (javac), bem como todas as demais ferramentas do JDK, 
diferenciam maiúsculas de minúsculas. Este recurso é chamado de case-sensitive. 
Portanto, bastante cuidado ao grafar o nome de classes, métodos, variáveis e 
pacotes. Erros comuns decorrem muitas das vezes de problemas envolvendo 
grafia, em que um nome, por exemplo, é definido em maiúsculas, e depois, logo 
adiante, é utilizado em minúsculas. O compilador simplesmente alegará que tal 
variável, método, classe ou pacote não foi definido. Abaixo são apresentados 
alguns padrões: 
 
 
Nomes de arquivos 
 
Arquivos contendo os fontes Java terminam com a extensão .java. Todo 
arquivo fonte Java deve ter no máximo uma única classe public. Pode haver 
mais de uma classe por arquivo, porém somente uma pública. O nome do 
arquivo fonte java é case-sensitive, ou seja, deve respeitar letras maiúsculas e 
minúsculas, devendo também ter o mesmo nome da classe publica declarada 
dentro do mesmo. 
 
Exemplo: Produto.java 
 
Nomes de classes 
 
Escolha nomes significativos, de tal forma que a simples leitura do nome já 
crie uma expectativa acerca do que se pode esperar da classe. Use para isto um 
ou mais substantivos. O primeiro caractere de cada palavra utilizada para o 
nome da classe deve ser maiúsculo. Quando o nome de uma classe tiver mais de 
uma palavra as mesmas devem estar concatenadas. 
 
Exemplo: NotaFiscal, Cliente, Item 
Criando classes e objetos 
 3-7 
Nomes de operações 
 
 Conselho similar pode ser dado à escolha dos nomes dos métodos: use 
nomes significativos. Use verbos ou estruturas verbais que captem a ação 
principal contida no método. O nome deve representar a real utilidade 
desempenhada pelo método. A primeira letra do nome de uma operação deve 
ser em minúscula e a primeira letra de todas as demais palavras que compõem o 
nome da operação, caso existam, em maiúsculo. 
 
Exemplo: getDescricao(), setPrecoFinal(…), imprimirRelatorio() 
 
Nomes de atributos/variáveis 
 
Use nomes curtos, mas que não sejam críticos. A primeira letra do nome da 
variável deve ser em minúscula e a primeira letra de todas as demais palavras 
presente no nome deve ser maiúscula. Evite usar nomes de variáveis com uma 
única letra. O que você esperaria de uma variável de nome r ou x? O nome 
deve ser representativo e a simples leitura do mesmo leva à compreensão do 
papel desempenhado pela variável no aplicativo. A única exceção aceitável é 
para contadores em laços, ou variáveis temporárias de uso restrito. 
 
Exemplo: nome, descricao, precoFinal, idade, dataNascimento 
 
Nomes de constantes 
 
O nome de constantes é definido de uma forma um tanto diferente. Toda 
constante tem o seu nome escrito sempre com todos os caracteres em 
maiúsculo, e se o nome for composto por mais de uma palavra, as mesmas 
devem ser separadas pelo caractere ‘_’. Veja abaixo um exemplo: 
 
Exemplo: TAMANHO_MAXIMO_VETOR = 100, BORDA = 4 
 
Caracteres especiais 
 
Números, sublinhado e dólar podem ser usados em nomes. A única 
restrição é que o nome deve sempre começar por um caractere que seja 
diferente de um número. Mas evite o mau uso de tais caracteres especiais. 
 
Criando classes e objetos 
 3-8 
Nome de pacotes 
 
 Pacotes devem possuir nomes significativos e não devem ter seus nomes 
separados por caracteres como “_”. Seus nomes devem ser escritos sempre com 
todas as letras em minúsculo e os nomes de pacotes seprados pelo caractere 
ponto (“.”). Veja o exemplo abaixo: 
 
Exemplo: com.targettrust.database 
 
 Observe que o nome do pacote foi iniciado com a palvra “com” e em 
seguida com a palavra targettrust. Normalmente começamos o nome de um 
pacote com o inverso do domínio da empresa. Isto explica o porque utilizar 
com.targettrust no início do nome do pacote. 
 
Criando classes e objetos 
 3-9 
Criando e importando pacotes 
 
 
Java fornece o mecanismo de pacote como uma maneira de agrupar as 
classes relacionadas. 
 
A declaração de pacote, caso exista, deve estar no início do arquivo de 
origem. Ela pode ser precedida apenas de espaços em branco e comentários. 
Somente uma declaração de pacote é permitida e influencia todo o arquivo de 
origem. 
 
Os nomes de pacote são hierárquicos e separados por pontos. 
 
Convencionalmente, os elementos do nome de pacote estão 
normalmente em letras minúsculas. O nome de classe, entretanto, geralmente 
começa com letra maiúscula e pode usar maiúsculas para separar as palavras 
do nome. 
 
Veja o exemploa seguir: 
Código 3-5: Definindo um pacote para uma classe 
 
Compilando e executando: 
Código 3-6: Compilando um classe com pacote e realizando sua execução. A opção –d indica o 
deretório de destino para o byte-code 
 
 
Código 3-7: Sintaxe para importar pacotes 
package com.targettrust.java; 
 
 class HelloWorld { 
 public static void main( String[] args ) { 
 System.out.println( "Hello World!" ); 
 } 
 } 
 
C:\> javac –d . HelloWorld.java 
C:\> java com.targettrust.java.HelloWorld 
Hello World! 
package com.targettrut.java; 
 
import java.sql.*; 
import java.io.*; 
import java.net.*; 
import javax.swing.JFrame; 
Criando classes e objetos 
 3-10 
 
Criando classes e objetos 
 3-11 
Static import 
 
 
 
Este recurso presente a partir da versão 1.5 do java é extremamente útil 
para simplificar e facilitar a escrita de código. Permite utilizarmos os membros 
(atributos ou métodos) static sem que tenhamos que prefixar os membros com o 
nome da classe. Veja o exemplo abaixo: 
 
System.out.println( Math.random() ); 
System.out.println( ( raio * raio) * Math.PI ); 
Código 3-8: Uso de operações static sem a importação dos membros static 
 
 
Este código utilizando o static import ficaria assim: 
 
import static java.lang.Math.*; 
import static java.lang.System.*; 
... 
out.println( random() ); 
out.println( ( raio * raio) * PI ); 
Código 3-9: Importanto os membros static da classe Math 
 
 
Veja que o código acima fica mais claro e fácil de ser escrito. Esta 
facilidade de escrita do código deve ser utilizada mas com cuidado para não ser 
abusada, pois pode prejudidar a legibilidade do código das suas aplicações. 
Sempre que muitos membros static de uma classe forem ser utilizados é útil este 
recurso, mas se somente um ou dois membros forem ser utilizados o uso deste 
recurso não é aconselhável. 
 
A importação dos membros static pode ser feito de forma genérica ou 
específica como mostra o código abaixo: 
 
1 import static java.lang.Math.PI; 
2 import static java.awt.BorderLayout.*; 
Código 3-10: Importando a estrutura estatica de uma classe 
 
Com o static import da linha 2 é possível se utilizar todas as constantes da 
classe BorderLayout. Isto evita termos que escrever portanto o nome da classe 
cada vez que uma constante for utilizada. 
Criando classes e objetos 
 3-12 
Criando objetos 
 
 Neste momento do seu aprendizado iremos mostrar como pode ser criao 
um objeto de uma determinada classe para que você possa aproveitar melhor 
os passos seguintes do curso. Não iremos ainda aqui nos aprofundar neste 
assunto, visto que a criação de objeto é algo que merece um tempo maior de 
estudo. Veremos então como pode ser criado um objeto. 
 
 
 ... 
 
 Produto prod; 
 prod = new Produto(); 
 
 ... 
Código 3-11: Criando um objeto da classe Produto 
 
 
 Observe no código acima a criação de um objeto que será referenciado 
por “prod”. Na primeira linha estamos fazendo a declaração de uma referência 
para um futuro objeto da classe produto. Esta referência irá receber um objeto 
que está sendo criado na linha segunte. A palavra reservada “new” é a 
responsável por alocar memória e construir o objeto da classe Produto. Logo 
depois de construído este objeto o endereço do mesmo ;e atribuído para a 
referência prod. 
 
 Para criar um objeto precisamos da classe e no momento de criação do 
mesmo veja que logo depois deste nome de classe colocamos os sinais de 
parênteses. 
 
 Esta criação também pode ser feita em uma única linha de código para 
simplificar o processo, como mostrado abaixo: 
 
 ... 
 
 Produto prod = new Produto(); 
 
 ... 
Código 3-12: Criand objeto da classe Produto em uma única linha 
 
 Agora em uma única linha você esta declarando uma referência para o 
objeto, criando o objeto e atribuindo o endereço de memória do mesmo para 
esta referência. 
 
Criando classes e objetos 
 3-13 
O que é a referência null? 
 
 Sempre que declararmos uma referência e esta não receber valor teremos 
um valor null “dentro” da mesma. Desta forma é importante estudarmos um 
pouco este valor null, pois muito erros em tempo de execução na linguagem java 
ocorrem em função desta palavra. 
 
Considere o seguinte comando: 
Código 3-13: Atribuindo null para a referência de Produto 
 
Ele declara uma variável/referência prod e a inicializa com null. Isto indica 
que a variável de referência prod não se refere a nenhum objeto ainda, em 
outras palavras, ela somente foi delarada. 
null é uma palavra reservada na linguagem Java. Você pode usá-la com o 
operador de igualdade para verificar se uma variável de referência já recebeu 
uma referência válida a um objeto ou mesmo para saber se duas referências 
apontam para o mesmo objeto 
 
Código 3-14: Teste entre uma referência e a palavra reservada null 
 
Quando você tiver terminado de usar um objeto, você pode atribuir o valor 
null para a variável que o referencia. Isto indica que a variável não mais se 
refere ao objeto. Quando nenhuma referência houver para um objeto, o objeto 
será marcado como inacessível e será considerado pelo coletor de lixo (garbage 
collector). Iremos estudar com mais detalhes o coletor de lixo nos próximos 
capítulos. 
Na prática, somente em casos muito especiais você precisa atribuir null 
para uma variável. A JVM automaticamente decrementa o número de 
referências ativas para um objeto sempre que a variável que o referencia recebe 
Produto prod = null; 
 
if( prod == null ) { 
 ... 
 ... 
} 
 
... 
 
prod == prodRef 
 
... 
Criando classes e objetos 
 3-14 
o valor null, sai de fora de escopo ou então recebe o valor de uma referência 
para outro objeto. 
Criando classes e objetos 
 3-15 
Atribuindo referências 
Como mencionamos antes, quando você declara uma variável de 
referência para um objeto, esta variável tem o seu valor inicializado para null. 
Antes que você possa usar esta variável (ou seja, acessar o objeto a que ela 
referencia), você tem de inicializá-la. Todos os atributos de uma classe que forem 
de tipos compostos (Classes) serão inicializados automaticamente pela JVM no 
momento da criação de um objeto da classe para o valor null. 
Quandor declaramos uma referência para um objeto e na mesma linha já 
criamos este objeto, estamos inicializado a referência com um valor diferente de 
null, ou seja, o endereço do objeto criado.V eja código abaixo: 
Código 3-15: Criação do produto prod 
 
Podemos também fazer atribuição de referência, para isto basta utiliza o 
operador de atribuição. Neste caso as duas referências irão apontar para o 
mesmo objeto. Veja o código abaixo: 
Código 3-16: Atribuição da referência prod1 para prod2 
 
Esta sintaxe está perfeitamente correta, mas vale frisar que há apenas um 
objeto Produto criado. Quando você atribui uma referência para um objeto 
para outra referência, você termina com duas referências para o mesmo objeto, 
e não uma cópia do objeto. 
Você pode acessar o mesmo objeto através de ambas as referências, 
entretanto, há apenas um único objeto. Este objeto é conhecido como objeto de 
referência. 
É importante se lembrar disto, principalmente ao passar uma referência para 
uma operação . Isto será visto em maiores detalhes adiante. 
Você pode alterar uma referência (mudando o valor da variável de 
referência), sem que isto afete a outra referência (o valor da outra variável de 
referência). 
Caso você precise de um outro objeto, ao invés de ter múltiplas referências 
para o mesmo objeto, você terá de criar este novo objeto. 
 
Produto prod = new Produto(); 
 
Produto prod1 = prod2; 
 
Criando classes e objetos 
 3-16 
Visibilidade aplicada a classesEncapsulamento é uma das palavras-chave para a orientação a objetos. 
Uma classe bem defina deve separar completamente a sua interface pública da 
implementação interna. Neste momento do estudo iremos mostrar quais são so 
tipos de encapsulamentos que uma classe pode receber. Certos de que a esta 
altura dos estudos você já conhece os tipos de encapsulamentos existentes 
vamos agora aplicar os mesmos para classe. A palavra visibilidade também pode 
ser aplicada para este assunto, uma vez que de acordo com o modificador que 
utilizaremos iremos tormar mais ou menos visível uma classe. 
pacote/default 
 
 Esta visibilidade é a visibiliade padrão quando não se especifica nenhuma 
visibilidade. Ao contrátio de ontras linguagen onde a visibilidade padrão é public 
java define a visibilidade pacote/default. Se uma classe possuir esta visibilidade 
isto significa que a mesma pode ser utilizada somente por outras classes que 
estiverem dentro do mesmo pacote. Classes que estiverem em pacotes 
diferentes do pacote onde esta classe estiver não “saberão” que a mesma existe. 
No exemplo abaixo a classe email poderá ser utilizada somente por classes do 
pacote com.targettrust.comunicacao e nenhum outro pacote mais 
 
package com.targettrust.comunicacao; 
class Email { 
... 
... 
} 
Código 3-17: Visibilidade de package aplicada a classes 
 
 
 
 
 
Criando classes e objetos 
 3-17 
public 
 
 Uma classe normalmente é declara como sendo pública, isto deixa a 
classe visível, ou seja, capaz de ser utilizada por qualquer outra classe do sistema, 
idependente do pacote onde a mesma se encontra. Recomenda-se que a 
classe sempre seja pública a não ser que você queira restringir o acesso de uso a 
esta classe. Quando em um arquivo fonte for delcarado mais de uma classe o 
nome do arquivo fonte deve levar o mesmo nome da classe pública que foi 
declarado neste. Lembre-se que não é possível declarar mais de uma clase 
pública em cada arquivo fonte. Veja o exemplo abaixo de uma classe pública: 
 
public class Email { 
... 
... 
} 
 
class Produto { 
... 
... 
} 
Código 3-18: Duas classes declaradas no mesmo arquivo fonte 
 
Criando classes e objetos 
 3-18 
Definindo operações 
 
Quando você define uma classe é necessário definir também as operações 
que farão parte desta classe. As operações são definidas dentro das chaves das 
classes. Cada operação terá uma implementação específica que é conhecida 
como método. Um método, portanto, é a implementação de uma operação. 
Um método em Java é equivalente a uma função, procedimento ou sub-
rotina em outras linguagens, com a diferença que ele deve ser definido dentro 
da declaração da classe. Em outras palavras, não existe em Java métodos 
globais (completamente desvinculados de uma classe). Todo método deve ser 
definido dentro de uma classe. 
Anteriormente quando criamos uma classe, definimos uma operação 
chamada “main”, agora iremos estudar a anatomia das operações bem como 
definir outras operações em uma classe. 
Anatomia de uma operação: 
 
 Abaixo temos uma operação definda dentro da classe Produto. Observe os 
elementos que fazem parte desta operação: 
 
public class Produto { 
 public void foo(String arg, int cod) { 
 
 } 
} 
Código 3-19: Declaração da operação 
 
Os elementos integrantes de uma operação são: 
 
• Modificador de acesso: utilizados para restringirem o acesso as operações. 
Pode ser public, default, protected ou private. 
 
 public void foo(String arg, int cod) { 
 
 } 
Código 3-20: Visibilidade da operação 
 
 
Criando classes e objetos 
 3-19 
• Tipo de retorno: pode ser um tipo primitivo (como int ou char – tipos 
primitivos serão estudados mais adiante), ou um tipo composto (um objeto 
String ou Produto, por exemplo), ou mesmo não haver retorno algum. 
Neste caso deverá constar void como tipo de retorno. Em resumo: toda 
operação em java deve indicar o tipo de retorno. 
 
 public void foo(String arg, int cod) { 
 
 } 
 
 public String getDescricao() { 
 
 } 
Código 3-21: Tipo de retorno das operações 
 
• Nome da operação: O nome da operação deve expressar o que a 
operação faz. Normalmente este nome deve ser um verbo ou estar no 
imperativo dando a idéia de uma ação. 
 
 public String getDescricao() { 
 
 } 
Código 3-22: Nome da operação 
 
Parâmetros: representam os valores que podemos passar para a operação. 
Toda operação pode receber parâmetros, sendo assim a operação pode definir 
logo após o seu nome um ou uma lista de parâmetros. Se o método recebe 
vários parâmetros, cada um deles deve ser separado dos demais por vírgula. 
Uma operação também pode não receber parâmetros. Havendo ou não 
parâmetros, os mesmos devem ser representados entre parênteses. 
 
 public void foo(String arg, int cod) { 
 
 } 
 
 public String getDescricao() { 
 
 } 
Código 3-23: Parâmetros da operação 
 
 
Criando classes e objetos 
 3-20 
• Corpo da operação: é o local onde fica a implementação da mesma. 
Este código deve ficar entre chaves, que representam o início e fim do 
bloco. 
 
 public void foo(String arg, int cod) { 
 System.out.println( arg ); 
 System.out.println( cod ); 
 } 
Código 3-24: Corpo da operação. Impressão dos valores passados como parâmetros 
Criando classes e objetos 
 3-21 
Comando return 
O comando return é utilziado na linguagem java para que as operações 
possam retornar valores. 
Um comando return aceita um valor simples ou uma expressão que deve 
ser compatível com o tipo de retorno do método em que este comando está 
inserido. 
Código 3-25: Comando return para retorno de método com ou sem valor de retorno. 
 
Quando um comando de return é encontrado, o fluxo de execução 
abandona o método imediatamente, ignorando quaisquer comandos que 
existam entre o comando de return e o final do método (o fecha chaves do 
corpo do método). 
Esta alteração do fluxo de execução pode ser usada mesmo em métodos 
que não retornam nenhum valor (métodos cujo tipo de retorno é void), com a 
finalidade de abandonar o método imediatamente. 
Neste caso especial, o comando return não aceitará nenhum valor de 
retorno ou expressão (afinal o método é void). 
public class Produto { 
 
 public String getDescricao() { 
 return "Nome: " + nome + " Preço: R$ " + preco; 
 } 
 
 
 public void setNome( String n ) { 
 nome = n; 
 return; 
 } 
 
} 
Criando classes e objetos 
 3-22 
Visibilidade para operações 
 
 Operações assim como os atributos e as classes podem ter visibilidades. 
Para as operações são aplicados os seguintes tipos de visibilidades: private, 
public, protected e pacote/default. O uso destas visibilidades é freqüente para 
as operações uma vez que pode ser utilizada paa restringir o acesso a um objeto. 
 
 
public 
 
 Esta visibilidade expõe as operações para serem chamadas de outros 
objetos. Acima quando criamos as operações você pode observar que as 
mesmas foram definidas como sendo públicas. Uma operação é definida 
sempre, por padrão, como sendo pública, veja o código abaixo: 
 
package com.targettrust.java; 
 
public class Produto { 
 
 public void foo() { 
 … 
 } 
 
} 
 
Código 3-26: Visibilidade pública 
 
 
 A operação foo() mostrada acima pode ser chamada a partir de qualquer 
outra classe independende do pacote onde se encontrar esta classe. Veja o 
código abaixo onde criamos um objeto para poder chamar esta operação: 
 
package com.targettrust.vendas; 
import com.targettrust.java.*; 
 
public class CriaObjetos { 
 
 public static void main(String[] args) { 
 Produto prod = new Produto();prod.foo(); 
 } 
 
} 
Código 3-27: Criando um objeto de uma classe e chamando a iperação pública 
 
Criando classes e objetos 
 3-23 
private 
 
 A visibilidade private restringe o acesso a esta operação ao próprio objeto 
que a contém. Uma operação privada portanto não pode ser acessada por 
outro objeto a não ser aquela que a definiu. Operações privadas não são 
comuns e se existirei representam um serviço interno do próprio objeto. 
 
 Veja abaixo como pode ser definida uma operação privada: 
 
public class Produto { 
 
 private void foo() { 
 … 
 } 
 
} 
Código 3-28: Visibilidade provada 
 
 Esta operação foo() é uma operação que pode ser chamada somente 
através de outras operações da própria classe, veja abaixo: 
 
public class Produto { 
 
 private void foo() { 
 … 
 } 
 
 public void salvar() { 
 foo(); 
 } 
 
} 
Código 3-29: Chamando operação com visibiliade privada 
 
 
 
 
 
 
 
 
 
 
 
 
 
Criando classes e objetos 
 3-24 
O código abaixo não é permitido, pois veja que agora a operação foo() esta 
definida com sendo privada. 
 
public class CriaObjetos { 
 
 public static void main(String[] args) { 
 
 Produto prod = new Produto(); 
 
 prod.foo(); 
 
 } 
 
} 
Código 3-30: Chamada de operação privada fora da classe 
 
protected 
 
 O uso desta visibilidade, assim como para os atributos está ligada ao uso de 
herança, desta forma iremos deixar este tipo de visibilidade para ser 
demonstrado mais adiante quando estudarmos o mecanismo de herança. 
 
 Uma operação protegida é uma operação visível para objetos de classes 
que estão no mesmo pacote daquela classe que define a operação ou para 
uma classe filha desta classe que contém a operação protegida. 
 
package/defalut 
 
 Uma operação com visibilidade de pacote/default é uma operação que 
tem comportamento de pública dento do pacote que a contém. Normalmente 
uma operação não é definida como package, mas sim como public ou private. 
 
 Para definir uma operação com esa visibilidade não se deve especificar 
nenhum modificador de acesso, isto a tornará default/package. 
 
Veja abaixo na classe Produto como ficaria a operação com esta 
visibilidade: 
 
public class Produto { 
 
 void foo() { 
 … 
 } 
 
} 
Código 3-31: Visibilidade default 
Criando classes e objetos 
 3-25 
Definindo atributos 
 
 
 Os atributos de uma classe definem a estrutura dos objetos. Estes atributos 
são declarados dentro do bloco que define a classe. Veja no exemplo abaixo a 
declaração de alguns atributos para a classe produto: 
 
 
public class Produto { 
 String descricao; 
 float preco; 
 boolean emVenda; 
} 
Código 3-32: Atributos da classe produto 
 
 
Observe que na declaração acima os atributos ficam dentro do bloco de código 
da claase. Estes atributos são atributos com visibilidade default. Logo 
estudaremos os tipos de visibilidade que podem ser aplicadas aos atributos. 
 
 Estes atributos especificados acima são conhecidos como atrubutos de 
intância e para serem acessados precisam que um objeto da classe que os 
contém seja criado. 
 
 Um atributo pode ser inicializado com valores já no momento da sua 
declaração como mostrado no código abaixo. Isto fará com que quando um 
objeto da classe que o contém for criado o mesmo já possua um determinado 
valor. O atributo emVenda irá possuir o valor true, neste caso, para todos os 
objetos criados 
 
 
public class Produto { 
 String descricao; 
 float preco; 
 boolean emVenda = true; 
} 
Código 3-33: Inicialização do atributo 
 
 
Criando classes e objetos 
 3-26 
Visibilidade aplicada a atributos 
 
 
 Os atributos são elementos que podem conter os quatro tipos de 
visibilidades definidos pela orientação a objetos. Vejamos agora o significado 
destes tipos de visibilidade aplicadas aos atributos. 
 
 
public 
 
 Esta visibiliade irá tornar o acesso ao atributo disponível para qualquer 
outra classe que estiver em qualquer outro pacote. Isto significa que objetos 
gerados a partir desta classe que define o atributo público poderão ter os valores 
destes atributos modificados por qualquer outro objeto. Este tipo de 
encapsulamento/visibilidade não é o recomendado para atributos. Veja o 
exemplo abaixo com os atributos para a classe Produto sendo públicos: 
 
 
public class Produto { 
 public String descricao; 
 public float preco; 
 public boolean emVenda; 
} 
Código 3-34: Visibilidade pública para os atributos 
 
 
 Veja agora como seria o acesso a estes atributos em um pseudo-código. 
Observe que a palavra “prod” é utilizada para referenciar um objeto da classe 
Produto criado. 
 
 
public class Consulta { 
 
 public static void main(String[] args) { 
 Produto prod = new Produto(); 
 prod.descricao = “Notebook”; 
 prod.preco = 3500.0f; 
 prod.emVenda = false; 
 } 
 
} 
Código 3-35: Acessando atributos com visibiliade pública 
 
Criando classes e objetos 
 3-27 
 
 
Criando classes e objetos 
 3-28 
private 
 
 A visibilidade provate é a visibilidade recomendada pela orientação a 
objetos para os atributos de uma classe. Você estudou estes tipos de visibilidade 
e a importância do uso das mesmas nos cursos anteriores, então vejamos agora 
como ficaria esta visibilidade aplicada aos atributos. 
 
 
public class Produto { 
 private String descricao; 
 private float preco; 
 private boolean emVenda; 
} 
Código 3-36: Definindo atributos provados 
 
 
 O acesso agora aos atributos não poderia mais ser feito de forma direta 
como na visibilidade pública. Veja o código abaixo e observe que nas linhas 
onde tentamos acessar os atributos teríamos um erro sendo reportado pelo 
compilador dizendo que o atributo é privado e não pode ser acessado desta 
forma. 
 
 
public class Consulta { 
 
 public static void main(String[] args) { 
 Produto prod = new Produto(); 
 
 prod.descricao = “Notebook”; 
 prod.preco = 3500.0f; 
 prod.emVenda = false; 
 
 } 
 
} 
Código 3-37: Acessando atributos privados 
 
 
 Como então deve ser feito o acesso a atributos privados. O acesso a 
atributos com visibilidade privada deve ser feito através de operações públicas 
que serão especificadas na classe. Já vimos como definir operações, então veja 
agora como ficaria o acesso a estes atributos. 
 
 
 Primeiramente teríamos que modificar a classe Produto adicionando 
métodos públicos para fazer este acesso. Veja abaixo: 
 
 
 
Criando classes e objetos 
 3-29 
 
 
 
 
 
public class Produto { 
 private String descricao; 
 private float preco; 
 private boolean emVenda; 
 
 public void setDescricao(String novaDescricao) { 
 descricao = novaDescricao; 
 } 
 
 public String getDescricao() { 
 return descricao; 
 } 
 
 ... 
} 
Código 3-38: Definindo operações para acesso aos atributos 
 
 
Logo depois de modificarmos a classe Produto podemos fazer acesso a 
seus atributos através das operações. Veja abaixo: 
 
 
public class Consulta { 
 
 public static void main(String[] args) { 
 Produto prod = new Produto(); 
 
 prod.setDescricao(“Notebook”); 
 prod.setPreco(3500.0f); 
 prod.setEmVenda(false); 
 
 } 
 
} 
Código 3-39: Utilizando as operações para acesso aos atributos 
 
Criando classes e objetos 
 3-30 
package/default 
 
 Um atributo com visibilidade de pacote/default é um atributo que pode ser 
acessado diretamente como se fosse público por classes que estiverem nomemo 
pacote. Para definir um atributo com esta visibilidade não é necessário colocar 
modificador antes do mesmo. Este é o modificador padrão para visibilidades 
quando as mesmas não forem definidas. 
 
 Abaixo veja a nova versão da classe Produto: 
 
package com.targettrust.java; 
 
public class Produto { 
 String descricao; 
 float preco; 
 boolean emVenda; 
} 
Código 3-40: Visibilidade default 
 
 Observe que a classe acima está dentro de um pacote chamado 
com.targettrust.java e que a mesma será utilizada por outra classe que está no 
mesmo pacote. 
 
package com.targettrust.java; 
 
public class Consulta { 
 
 public static void main(String[] args) { 
 Produto prod = new Produto(); 
 
 prod.descricao = “Notebook”; 
 prod.preco = 3500.0f; 
 prod.emVenda = false; 
 
 } 
 
} 
Código 3-41: Acesso a visibilidade defalut 
 
 
 
Criando classes e objetos 
 3-31 
Agora se movermos a classe Consulta para outro pacote e fizermos a 
importação do pacote com.targettrust.java para tentar acessar os atributos nõa 
teremos sucesso. 
 
 
package com.targettrust.exemplo; 
 
import com.targettrust.java.*; 
 
public class Consulta { 
 
 public static void main(String[] args) { 
 Produto prod = new Produto(); 
 
 prod.descricao = “Notebook”; 
 prod.preco = 3500.0f; 
 prod.emVenda = false; 
 
 } 
 
} 
Código 3-42: Acessando atributo default fora do pacote 
 
 O código que temos para acessar os atributos é o mesmo que temos 
quando a classe é pública, mas agora como a classe Consulta está em pacote 
diferente, e os atributos de Produto tem a visibilidade de pacote/default o acesso 
não pode mais ser feito de forma direta. Neste caso se tivéssemos interesse em 
acessar os atributos a partir de outra classe fora do pacote teríamos que fornecer 
métodos públicos para isto. 
 
protected 
 
 Esta visibiliade para ser entendida necessita o estudo do mecanismo de 
herança entre classes. Vamos deixar para mais tarde quando mostrarmos aqui 
este mecanismo para então dar exemplos de códigos com protected. 
 
 Um atributo protegido é um atributo que terá visibilidade de pacote, mas 
também irá permitir o acesso direto a ele para classes que estiverem em pacotes 
diferentes daquele pacote onde está a classe que o define, desde que a classe 
fora do pacote seja filha da que contém o atributo. 
Criando classes e objetos 
 3-32 
Acessando atributos 
 
 O acesso a atributos de uma classe deve ser feito somente por operações 
definidas na mesma classe que contém este atributo. Desta forma devemos 
tornar os atributos de uma classe por padrão privados e as operações que irão 
acessá-los públicas. 
 
Cada atributo irá possuir um par de métodos que chamamos de métodos 
de leitura e escrita ou getter e setter. Veja abaixo como ficaria a classe produto: 
 
 
public class Produto { 
 
 private int codigo; 
 private String descricao; 
 private float preco; 
 
 public void setCodigo(int novoCodigo) { 
 codigo = novoCodigo; 
 } 
 
 public int getCodigo() { 
 return codigo; 
 } 
 
 public void setDescricao(String novaDescricao) { 
 descricao = novaDescricao; 
 } 
 
 public String getDescricao() { 
 return descricao; 
 } 
 
 public void setPreco(float novoPreco) { 
 preco = novoPreco; 
 } 
 
 public float getPreco() { 
 return preco; 
 } 
 
} 
Código 3-43: Definição da classe Produto 
 
Criando classes e objetos 
 3-33 
Comentários no código fonte 
 
Os comentários de código fonte estão presentem em todas as linguagens 
de programação, e como java não poderia ficar de fora o mesmo possui 3 tipos 
de comentários. Os comentários são importantes pois são um mecanismo para o 
programador explicar dentro do fonte com as suas próprias palavras o que 
significa ou faz os elementos que o mesmo está escrevendo. 
Java possui um tipo de cometário que pode ser utilizado por um gerador de 
documentação a fim do mesmo criar um conjunto de páginas HTML com 
informações sobre a classe. O programador interessado em utilizar aquela clase 
não precise olhar o fonte da mesma para saber do que ele dispõe, mas sim basta 
olhar em qualquer browser esta documentação em formato HTML. 
Na linguagem java existem os seguintes tipos de comentários: 
 1 – Comentário de linha 
 2 – Comentário de múltiplas linhas 
 3 – Comentário de documentação 
 
 
 
Comentário de linha 
 
 O comentário de linha é um comentário bastante prático e muito utilizado. 
Seve para podermos colocar em qualquer ponto do código uma 
documentação. No entanto esta documentação é feita somente em uma linha, 
não podendo haver múltiplas linhas como no anterior. Veja o exemplo abaixo: 
 
public class Produto { 
 
 public float calcularPreco() { 
 // para calcular o preço deve ser descontado o desconto 
 preco = preco – desconto; 
 ... 
 } 
} 
Código 3-44: Comentário de linha 
 
 
Criando classes e objetos 
 3-34 
Comentário de múltiplas linhas 
 
 O comentário de múltiplas linhas pode ser utilizado em qualquer ponto do 
código. Este tipo de comentário não fará parte da documentação gerado pelo 
javadoc. O programador pode escrever mais de uma linha documentando o 
código. Os caracteres /* e */ representam o início e fim deste tipo de comentário. 
 
public class Produto { 
 
 public void imprimir() { 
 /* Mostra os dados do produto. 
 Estes dados mostrados são: nome, descrição e preço 
 */ 
 System.out.println(“Dados do produto:”); 
 ... 
 } 
} 
Código 3-45: Comentário de múltiplas linhas 
 
 
Comentário de documentação 
 
 Este tipo de cometário deve ser colocado antes do elemento que se quer 
documentar, ou seja antes da definição de uma classe ou operação. As 
marcações /** e */ indicam o início e fim de um comentário de documentação. 
Todo o conteúdo colocado dentro destas marcações será capturado pelo 
utilitário javadoc para montar a documentação da classe em formato HTML. 
/** 
 Classe para representar um produto da loja. 
 Um produto deve conter sempre um código e uma descrição 
 Criada dia 05-05-2005 
*/ 
public class Produto { 
 
 /** 
 Método para mostrar os dados de um produto 
 */ 
 public void imprimir() { 
 
 } 
} 
Código 3-46: Comentário de documentação para classe e operação 
 
 
Criando classes e objetos 
 3-35 
Os comentários de documentação podem ter algumas marcações 
especiais para serem capturadas pelo javadoc e adicionadas na 
documentação HTML da classe. Estas marcação são as seguintes: 
 
@return Representa o tipo de retorno de uma operação. Pode conter texto 
para explicar o que é o tipo de retorno 
@param Representa o parâmetro de uma operação. Deve conter uma 
descrição do que significa este parâmetro. 
Tabela 3-1: macros para documentação 
 
Veja código de exemplo abaixo: 
 
public class Produto { 
 
 /** 
 Calcula o custo de um produto. 
 @param arg um argumento a ser utilizado para calcular o custo 
 @param cod código do produto a ser utilizado no calculo 
 @return float indicando o custo do produto 
 */ 
 public float calcularCusto(String arg, int cod) { 
 … 
 } 
 
} 
Código 3-47: Comentário de documentação para a classe Produto 
 
 
Criando classes e objetos 
 3-36 
Escopo das variáveis 
 
Este é um assunto muitas vezes não abordado em materiais sobre java, 
porém de extrema importância. Nesta linguagem as variáveis quando forem 
declaradas irãoestar visíveis dentro de um determinado escopo de código. Este 
escopo é delimitado por chaves que representam blocos de códigos. Isto 
significa que uma variável declarada dentro de um bloco de código é visível 
somente aquele bloco de código bem como a outros blocos que estiverem 
dentro deste. 
Normalmente existe um bloco de código delimitado por chaves para 
representar o corpo de código de uma classe (veja na figura abaixo o escopo de 
classe) e de uma operação (veja abaixo escopo de método). Isto significa que 
se declararmos uma variável dentro do bloco da classe a mesma será visível a 
códigos que se encontrarem dentro daquele escopo de classe (não estamos 
aqui levando em consideração os tipos de encapsulamento). Dentro de um 
corpo de código para classes podemos ter operações definidas e estas 
operações possuem também seus blocos de códigos (escopo de método). Isto 
significa que se dentro do bloco de código de uma classe definirmos uma 
variável, esta variável poderá ser acessada normalmente dentro de qualquer 
bloco de código de uma operação que foi definido dentro do bloco da classe. 
Isto tudo pode ser resumido da seguinte maneira: uma operação pode chamar 
qualquer outra operação da classe ou mesmo acessar uma variável desta classe. 
Podemos também definir dentro do escopo de um método outros blocos de 
código. Isto pode ser feito através do uso de chaves. Não é normal definirmos 
blocos de código desta maneira, mas esta mesma idéia pode ser utilizada para 
os comandos que possuem blocos de códigos como o “if”, “for”, “while”, etc... 
Veja abaixo na figura a representação dos escopos. 
 Figura 3-1: Escopos de implementação. 
 
 
Criando classes e objetos 
 3-37 
 
 
public class Produto { 
 
 private float preco; 
 
 public void setPreco(float novoPreco) { 
 preco = novoPreco; 
 } 
 
} 
Código 3-48: Acessando a variável preco 
 
 
 Observe no código acima o escopo onde foi definido o preço. Esta 
variável (podemos também chamar de atributo) foi definido dentro do escopo 
da classe, ou seja, dentro das chaves da classe. Pode, portanto, ser acessado por 
qualquer operação que estiver também definda dentro do escopo de classe, 
como a operação setPreco(...). 
 Veja agora o código abaixo ao qual adicionamos mais variáveis e outro 
escopo. 
 
public class Produto { 
 
 private float preco; 
 
 public void setPreco(float novoPreco) { 
 preco = novoPreco; 
 x = 34; // Erro 
 } 
 
 public void foo(int y) { 
 int x = 10; 
 if ( x > y) { 
 int res = x + y; 
 } 
 System.out.println( res ); // Erro 
 } 
 
} 
Código 3-49: Acessando variáveis fora de escopo 
 
 No código acima temos a declaraçõ de uma variável inteira x dentro do 
bloco de código da operação foo(...). Isto significa que esta variável somente 
poderá ser acessada por outros códigos que estiverem dentro desta mesma 
operação. Este tipo de variável é conhecida como variável local. Observe que 
na linha onde é atribuído o valor 34 ao x teremos um erro. 
Criando classes e objetos 
 3-38 
 Neste mesmo código mostrado acima podemos observar que foi 
declarado um comando condicional if dentro da operação e que dentro deste 
comando declaramos uma variável res. Esta variável é uma variável local ao 
comando condicional, ou seja, é válida somente dentro deste comando, não 
podendo ser acessada fora do mesmo. Veja a linha onde tentamos imprimir o 
conteúdo da variável res, nesta linha teremos um erro de acesso. 
 Podemos definir “x” e “res” como sendo variáveis locais, enquanto preço 
pode ser definido como sendo uma variável de instância. Par6ametros de 
métodos também são considerados como sendo variáveis locais. 
 
Criando classes e objetos 
 3-39 
Passando Tipos Primitivos para Métodos 
 
Quando um valor de tipo primitivo (int, char, etc.) é passado para o 
método, uma cópia deste valor preencherá o respectivo parâmetro do método. 
Se o método alterar o valor de seus parâmetros, esta alteração terá um efeito 
local: alterará apenas a cópia (o parâmetro formal ou argumento), mas o valor 
original permanecerá o mesmo. 
Quando o método termina, todos os seus parâmetros são descartados e as 
variáveis originais presentes na chamada permanecem inalteradas. 
O exemplo abaixo ilustra a maneira com que tipos primitivos são passados 
por valor para os métodos. 
Código 5-20: Escopo de execução da variável preco. 
 
Código 3-50: Escopo de execução da variável arg 
 
O código à esquerda declara uma variável int chamada preco e atribui o 
valor 150 a esta variável. Quando preco é passada para foo(), uma cópia de 
seu valor corrente preencherá o parâmetro arg, que terá o valor inicial de 100. 
Dentro de foo(), arg recebe o valor 55. Quando foo() termina, o 
parâmetro arg é descartado e o fluxo de execução retorna ao chamador. 
A variável preco, definida no contexto do chamador, não foi afetada e tem 
ainda o valor de 100. 
 A saída do programa será, portanto, a seguinte: 
 
int preco = 100; 
obj.foo(preco); 
System.out.println("preço = " + preco); 
 
public void foo(int arg) { 
 if(arg > 0 && arg < 2000) 
 arg = 55; 
 System.out.println("arg = " + arg); 
} 
arg = 55 
preco = 100 
 
preco 
100 
arg 
100 
Criando classes e objetos 
 3-40 
Passando Referências para Métodos 
 
Quando você passa um objeto para um método, a referência para o objeto 
original é passada como argumento, e não uma cópia do objeto. Qualquer 
alteração que o método fizer valendo-se da referência recebida, alterará o 
objeto original. Quando o método terminar, todas as alterações feitas pelo 
método no objeto permanecerão. 
O exemplo abaixo ilustra a maneira pela qual referências para objetos são 
passadas para métodos. 
O código à esquerda cria um objeto Produto e armazena a referência para 
este objeto na variável p1. Neste exato instante, o título de p1 é "DVD” e o código 
é "1". 
Quando p1 é passada para foo(), o método recebe a referência para o 
objeto Produto original. Dentro de foo(), através da variável de referência ref, 
o nome e o código são alterados. Quando foo() termina, o objeto Produto 
original referenciado por prod tem o título "CD" e o código "2". 
 
 
Código 3-51: Escopo de execução do objeto prod 
 
 Código 3-52: Escopo de execução do objeto prod pela referência 
ref. 
Produto prod = new Produto( “CD” ); 
 
prod.setCodigo( 1 ); 
obj.foo( prod ); 
public void food(Produto ref) { 
 ref.setCodigo( 2 ); 
 ref.setNome( "CD" ); 
} 
prod 
 
nome:"CD" 
codigo: 2 
 
ref 
Criando classes e objetos 
 3-41 
Espaço para anotações 
Criando classes e objetos 
 3-42 
Exercícios 
 
1. Neste exercício você irá criar uma classe para representar um Produto com 
a estrutura (atributos) descrita abaixo. Esta classe estará associada com 
outra classe, a ItemPedido. Item pedido possui o produto e a sua 
quantidade. No final você irá criar uma classe com método main para 
testar sua aplicação. Siga os passos abaixo para realizar o exercício. 
 
 
Passo 1: Crie uma classe chamada Produto dentro de seu projeto. Esta 
classe deverá pertencer ao pacote com.targettrust.java. 
 
 
Passo 2: Defina nesta classe os seguintes atributos privados: 
 
private String codigo 
private String descricao 
private float preco 
private boolean emVenda 
private float desconto 
 
 
 Passo 3: Crie operações públicas para acessar estes atributos permitindo 
que os mesmos possam ser lidos e modificados. 
 
 Passo 4: Documente o código escrito por você. Use comentário de 
documentação para mostrar o que as operações realizam bem como seus 
parâmetros e tipo de retorno. 
 
 Passo 5: Crie uma outraclasse pública com o nome ItemPedido. Esta 
classe deve pertencer ao pacote com.targettrust.venda. 
 
 Passo 6: Para esta classe declare os seguintes atributos privados: 
 
private int quantidade 
private Produto produto 
 
 
 Passo 7: Crie operações públicas para acessar estes atributos de forma 
que seja possível modificar e ler os seus valores. 
 
 Passo 8: Crie uma nova classe chamada Aplicação no pacote 
com.targettrust.java. Dentro desta classe declare o método main mostrado 
anteriormente na apostila. O método main é aquele que permite executar a 
classe. 
 
Criando classes e objetos 
 3-43 
 
 Passo 9: Dentro do método main crie objetos da classe ItemPedido e 
Produto e em seguinda associe estes objetos. Lembre-se que um ItemPedido 
possui uma referência para um Produto. Defina valores para os outros atributos 
dos objetos. 
 
 Passo 10: Crie na classe Aplicacao uma operação que seja capaz de 
receber como parâmetro um ItemPedido e faça a impressão das informações do 
objeto que esta operação receber. 
 
 Passo 11: Gere a documentação utilizando o javadoc para as classes 
criadas no exercício.
Java Fundamentals 
 
 4-1 
44.. CCoommaannddooss ddaa LLiinngguuaaggeemm 
 
 
 
 
 
 
 
 
Comandos da Linguagem 
 4-2 
Objetivos 
 
• Conhecer os comandos da linguagem java 
• Compeender os comandos e saber o contexto no qual podem ser 
utilizados 
• São estudados os seguintes comandos: 
• switch 
• while 
• do 
• for 
• for-each 
• break 
• continue 
• if 
• else if 
• Operador ternário 
Comandos da Linguagem 
 4-3 
Comandos 
 
 Os comandos da linguagem são comandos comuns a maioria das 
linguagens de programação. O objetivo deste capítulo é adaptar o aluno a 
sintaxe destes comandos na linguagem java. Para isto abxaixo aprensentamos os 
comandos:: switch, while, do, for, for-each, break, continue, 
return, if e else if. 
 
Comandos da Linguagem 
 4-4 
Comando if / else / else if 
 
O comando if é o principal comando de controle de fluxo. Ele possibilita 
ao programador Java tomar decisões ou, mais precisamente, executar um 
comando somente quando uma determinada condição for verdadeira. 
O comando if sempre vem sempre acompanhado de uma expressão 
(que é a condição que pende sobre a execução do comando) e um comando 
(que somente será executado se a expressão anterior for avaliada para 
verdadeiro). Se a expressão for verdadeira o comando é executado. Se a 
expressão for falsa, o comando é saltado. 
Por exemplo: 
Código 4-1: Comando if simples. 
 
Embora pareça um pouco estranho, os parêntesis que envolvem a 
expressão são exigidos pela sintaxe do comando. Como já foi mencionado, um 
bloco de comandos delimitados por chave (comando composto) comporta-se 
como um comando simples, e pode ser sempre colocado onde um comando 
simples é esperado. Desta forma, o comando if também pode ser escrito assim: 
 
Código 4-2: Comando if com expressão lógica e bloco de comandos. 
 
Um comando if pode opcionalmente incluir a palavra reservada else 
seguida de um comando (simples ou composto). Neste caso, a expressão 
condicional é avaliada e, se for verdadeira, o comando que segue a palavra 
reservada if é executado e o comando que segue a palavra else é pulado. 
Se a expressão for falsa o contrário ocorrerá: o comando que segue a 
palavra reservada if é pulado e o comando que segue a palavra reservada 
else é executado. 
 
if(usuario == null) { 
 usuario = "admin"; 
} 
if( (endereco == null) || (endereco.equals("") ) ) { 
 endereco = "[desc.]"; 
 System.out.println("Endereço não encontrado"); 
} 
 
Comandos da Linguagem 
 4-5 
Código 4-3: Comando if/else simples. 
 
Quando há vários comandos if/else aninhados é necessário alguma 
precaução para garantir que a cláusula else se refere ao comando if correto. 
Considere as seguintes linhas: 
 
Código 4-4: Comando if mal identado. 
 
Infelizmente não está claro com qual if a cláusula else faz par. A 
identação sugere ser o primeiro if o par da cláusula else. E sugere 
erradamente, levando o programador a uma situação de erro. 
A regra para o casamento dos pares if/else é bem simples. A cláusula 
else sempre faz par com o comando if mais próximo. Corrigindo a identação, 
para que represente corretamente os pares if/else, teremos: 
Código 4-5: Comando if mal identado. 
 
if(usuario != null) { 
 System.out.println("Olá! " + usuario); 
}else { 
 usuario = getNomeUsuario(); 
 System.out.println("Olá! " + usuario + "Esta é sua primeira sessão" ); 
} 
 
if(i == j) 
 if(j == k) 
 System.out.println("i é igual a k"); 
else 
 System.out.println("i não é igual a j"); // ERRADO 
if(i == j) 
 if(j == k) 
 System.out.println("i é igual a k"); 
 else 
 System.out.println("i não é igual a j"); // ERRADO 
Comandos da Linguagem 
 4-6 
Muito cuidado deve ser tomado, pois não há erro de sintaxe nos dois 
exemplos acima. São construções é perfeitamente legal. Só não ocorre o que o 
programador deseja. Ao trabalhar com comandos ifs aninhados use chaves a 
fim de tornar o código mais legível. 
Código 4-6: Comando if identado corretamente. 
if(i == j) { 
 if(j == k) { 
 System.out.println("i é igual a k"); 
 } 
}else { 
 System.out.println("i não é igual a j"); // CORRETO 
} 
Comandos da Linguagem 
 4-7 
Seqüência de Cláusulas else if 
O comando if/else é útil para testar uma condição e escolher qual 
comando ou bloco de comandos executar. Mas, e se devemos escolher não um 
bloco entre dois, mas sim um entre vários? Para resolver este tipo de problema é 
comum usarmos uma seqüência de cláusulas else if. 
Cláusulas else if não são uma novo comando da linguagem Java, ou 
mesmo uma sintaxe alternativa de um comando existente. Estas cláusulas são 
apenas o emprego inteligente do conhecido comando if/else associado a 
uma identação que facilite o entendimento. 
Veja o exemplo abaixo: 
Código 4-7: Comando if em sequência identado a esquerda. 
 
Não há nada de especial no código acima. É apenas uma seqüência de 
comandos ifs, onde cada if é parte da cláusula else do comando anterior. 
No entanto, escrito desta forma o código fica bem mais legível e claro do que se 
fosse escrito com sucessivos aninhamentos (basta dar uma olhada no exemplo 
abaixo). 
if(n == 1) { 
 // executa bloco de código 1 
}else if(n == 2) { 
 // executa bloco de código 2 
}else if(n == 3) { 
 // executa bloco de código 3 
}else { 
 // se todas as condições acima falham, então 
 // executa bloco de código 4 
} 
 
if(n == 1) { 
 // executa bloco de código 1 
} 
else { 
 if(n == 2) { 
 // executa bloco de código 2 
 } 
 else { 
 if(n == 3) { 
 // executa bloco de código 3 
 } 
 else { 
 // se todas as condições acima falham, então 
 // executa bloco de código 4 
 } 
 } 
} 
 
Comandos da Linguagem 
 4-8 
Código 4-8: Comando if em sequência identado em relação a blocos de código. 
 
Comandos da Linguagem 
 4-9 
Operador ternário 
 
 Java também define um operador ternário, chamado freqüentemente de 
operador condicional. Funciona como um comando if dentro de uma 
expressão. Seus três operandos são separados por um ponto de interrogação ‘?’ 
e por dois pontos ‘:’. O segundo e o terceiro operando devem ser do mesmo 
tipo. 
Veja o código abaixo: 
int x, y; 
... 
String res = “”; 
if ( x > y ) { 
 res = “X é maior que Y”; 
}else { 
 res = “Y é maior que X”; 
} 
... 
System.out.println( res ); 
 
Código 4-9: Comando if else a ser transformado em operador ternário 
 
Agora vamos ver o mesmo código fazendo usto do operador ternário: 
 
int x, y; 
...String res = (x > y)?“X é maior que Y”:“Y é maior que X”; 
... 
System.out.println( res ); 
Código 4-10: Expressão com operador ternário 
 
Observe que o código é bem mais enxuto para este caso de if..else 
Comandos da Linguagem 
 4-10 
Comando switch 
O comando if provoca um desvio no fluxo de execução de um programa. 
Você pode usar múltiplos comandos ifs, como mostrado na seção anterior, para 
executar desvios múltiplos de execução. Entretanto, esta nem sempre é a melhor 
solução especialmente quando todos os desvios dependem do valor de uma 
única variável. 
Neste caso é ineficiente conferir repetidas vezes o valor de uma mesma 
variável em múltiplos comandos ifs. 
Uma solução melhor é usar o comando switch. Embora a sintaxe deste 
comando não possua a mesma elegância apresentada por outros comandos da 
linguagem, a praticidade deste tipo de construção o torna extremamente útil. Se 
você não está familiar com este comando, talvez já conheça, no entanto, a 
idéia que está por detrás dele. 
O comando switch possui uma expressão inteira e um corpo que contém 
vários pontos de entrada numerados. A expressão é avaliada e o fluxo de 
execução salta para o ponto de entrada especificado com o valor avaliado. O 
comando switch seguinte é equivalente ao uso repetido de comandos if e 
else/if, como mostrado na seção anterior. 
Código 4-11: Comando switch padrão de inteiros utilizando break 
 
Como você pode ver a partir deste exemplo, os vários pontos de entrada 
do comando switch são rotulados ou com a palavra reservada case seguida de 
um valor inteiro e dois pontos, ou então da palavra reservada default seguida 
de dois pontos. 
switch(n) { 
 case 1: 
 // começa aqui se n == 1 
 // executa bloco de código 1 
 break; // para aqui 
 
 case 2: 
 // começa aqui se n == 2 
 // executa bloco de código 2 
 break; // para aqui 
 
 case 3: 
 case 4: 
 // começa aqui se n == 3 
 // executa bloco de código 3 
 break; // para aqui 
 
 default: 
 // se todas as condições acima falham, então 
 // executa bloco de código 4 
 break; // para aqui 
} 
Comandos da Linguagem 
 4-11 
Quando o comando switch é executado, o interpretador Java calcula o 
valor da expressão entre parêntesis e então procura pelo rótulo case que tenha 
especificado este valor. 
Se ele consegue encontrar tal rótulo, o fluxo de execução é transferido 
para o bloco de código que tem início no primeiro comando após o rótulo. 
 Se ele não encontra um rótulo com o valor da expressão avaliada, o fluxo 
de execução salta para o primeiro comando após o rótulo especial default. Ou, 
caso um rótulo default não tenha sido definido, o fluxo de execução salta 
totalmente para fora do comando switch. 
Observe o uso da palavra reservada break ao final de cada rótulo case no 
exemplo anterior. O comando break será descrito mais adiante, mas, neste caso, 
ele faz com que o fluxo de execução salte para fora do corpo do comando 
switch. 
Os rótulos case em um comando switch especificam somente o ponto de 
entrada para o bloco de código a ser executado. Os rótulos cases não são 
blocos independentes de código, e não possuem um ponto de término implícito. 
Portanto, você deve especificar o fim de cada rótulo com um comando break 
ou equivalente. 
Na ausência de um comando break, a expressão é avaliada e o fluxo de 
execução salta para o bloco de código que tem seu início logo após o rótulo 
que define a expressão avaliada, e a execução continua até o final do 
comando switch. 
Em raras ocasiões se revela útil escrever código em que a execução 
atravessa mais de um rótulo. Em 99% dos casos, depois de encontrado o rótulo e 
executado o bloco de código associado a este, a execução deve deixar o 
comando switch por força de um comando break. Lembre-se, portanto, de 
sempre verificar se há um comando break após cada rótulo, garantindo a saída 
correta do comando e impedindo que o fluxo de execução passe por todos os 
rótulos do comando. 
Um comando switch pode ter mais de uma cláusula case rotulando um 
mesmo comando. 
Considere o seguinte método: 
boolean respostaSimOuNao( char resposta ) { 
 switch( resposta ) { 
 case 's': 
 case 'S': return true; 
 
 case 'n': 
 case 'N': return false; 
 
 default: return false; //por default a resposta será false 
 } 
} 
 
Comandos da Linguagem 
 4-12 
Código 4-12: Comando switch de char sem utilização de break e com comando return. 
 
Há algumas importantes restrições sobre o comando switch e os rótulos 
cases. A expressão associada com o comando switch deve ter um tipo byte, 
char, short ou int. Valores booleanos ou reais não são suportados, nem o tipo 
long, apesar de ser um tipo inteiro. 
Os valores associados com cada rótulo case devem ser ou constantes, ou 
expressões constantes avaliáveis em tempo de compilação. Um rótulo case não 
pode conter expressões avaliáveis em tempo de execução, tais como variáveis 
ou chamadas de métodos. 
Os valores presentes nos rótulos cases devem estar compreendidos na faixa 
de valores do tipo usado na expressão do comando. Por fim, dois rótulos cases 
não podem ter o mesmo valor, nem um comando switch pode ter mais de uma 
cláusula default. 
Comandos da Linguagem 
 4-13 
Comando while 
 
Assim como o comando if é o principal comando de controle de fluxo, 
permitindo ao programador tomar uma entre várias decisões, o comando while 
é o principal comando de iteração da linguagem Java e permite ao 
programador executar um bloco de código reiteradas vezes. 
Ele possui a seguinte sintaxe: 
Código 4-13: Estrutura do comando while. 
 
O comando while começa por avaliar a expressão entre parêntesis. Se 
esta expressão é avaliada para falso, o fluxo de execução pula o corpo do 
comando while e passa a executar o próximo comando definido no programa. 
Se, no entanto, a expressão é verdadeira, o corpo do laço while é executado e 
a expressão entre parêntesis é reavaliada. Este ciclo continua enquanto a 
avaliação da expressão resultar verdadeiro. 
Quando a expressão se tornar falsa, a execução do comando while 
termina e o fluxo de execução passa para o próximo comando. Você pode criar 
um laço infinito com a sintaxe while(true) (pois a expressão sempre é 
verdadeira). 
Um exemplo de um laço que imprime os números de 0 a 9: 
Código 4-14: Comando while com teste lógico para impressão de inteiros entre 0 e 9. 
 
Como você pode ver, a variável cont começa em 0, neste exemplo, e é 
incrementada cada vez que o corpo do laço é executado. Após o laço ter sido 
executado 10 vezes, a expressão do comando while se torna falsa (i assume o 
valor 10), o comando while termina, e o fluxo de execução passa para o 
próximo comando do programa. 
A maior parte dos laços tem uma variável contadora, como i. Os nomes 
de variáveis: i, j e k são usados, na maioria das vezes, para tais variáveis 
contadoras, embora você possa escolher um nome mais claro. 
while(expressao) { 
 comandos 
} 
int i = 0; 
while(i < 10) { 
 System.out.println(i); 
 i++; 
} 
 
Comandos da Linguagem 
 4-14 
Comando do 
 
O comando do é bastante similar ao comando while. A diferença é que, 
no comando do, o teste da expressão é feito no final do laço. 
Isto significa que o corpo do laço é executado pelo menos uma vez. 
Eis a sintaxe do comando: 
Código 4-15: Estrutura do comnado do/while. 
 
Há algumas diferenças a se observar entre o laço presente no comando do 
e o laço presente no comando while. O laço do comando do requer tanto a 
palavra reservada do para marcar seu início, quanto a palavra reservada while 
para marcar o seu término e introduzir a expressão condicional do laço. 
Ao contrário do laço do comando while, olaço do comando do sempre 
termina com um ponto e vírgula. Isto obviamente ocorre pelo fato de a 
expressão condicional ser colocada no final do comando. 
O laço abaixo gera a mesma saída que o código apresentado para o 
comando while: 
Código 4-16: Comando do/while com teste lógico no final para impressão de inteiros entre 0 e 9. 
 
Observe que o comando do é bem menos usado que o comando while. 
Isto acontece porque, na prática, é incomum encontrarmos situações em que se 
deseje que o corpo do laço seja executado pelo menos uma única vez. 
do { 
 comandos 
} 
while(expressao); 
int i = 0; 
do { 
 System.out.println( i ); 
 i++; 
} while( cont < 10 ); 
 
Comandos da Linguagem 
 4-15 
Comando for 
 
O comando for fornece uma construção de iteração que é, na maioria 
das vezes, mais conveniente que os laços while e do. O comando for tira 
vantagem de haver um padrão de iteração bastante freqüente. A maior parte 
dos laços possui um contador, ou algum tipo de variável de estado, que é 
inicializado antes da execução do laço e incrementado, ou de alguma forma 
alterado, após o término da execução do corpo do laço e antes da reavaliação 
da expressão condicional associada ao laço. 
Os passos de inicialização, teste e atualização constituem as principais 
manipulações feitas sobre as variáveis do laço e integram a sintaxe do comando 
for. 
 
Código 4-17: Estrutura do comando for 
 
Colocar as expressões de inicialização, teste e atualização no início do 
laço é algo que facilita a compreensão do que está ocorrendo no corpo do 
laço, e evita erros tais como esquecer de inicializar as variáveis do laço. 
O interpretador Java descarta os valores das expressões de inicialização e 
atualização, logo, para que estas expressões sejam úteis, elas devem ter efeitos 
colaterais. 
A expressão de inicialização é tipicamente uma expressão de atribuição, 
enquanto a expressão de atualização é usualmente uma expressão de 
incremento, decremento ou atribuição. 
O seguinte laço imprime os números de 0 a 9, como os exemplos 
anteriormente colocados para os comandos while e do: 
Código 4-18: Comando for com teste lógico e incremento para impressão de inteiros entre 0 e 9. 
 
Observe como esta sintaxe coloca todas as informações importantes sobre 
a variável do laço em uma única linha, facilitando a compreensão do que 
ocorre no corpo do laço. 
for( declaração e inicialização; teste; atualização ) { 
 
} 
 
for( int i = 0; i < 10; i++ ) { 
 Sytem.out.println( i ); 
} 
Comandos da Linguagem 
 4-16 
Colocar a expressão de atualização da variável do laço na sintaxe do 
próprio comando for simplifica também o corpo do laço, permitindo que este 
possa ser expresso, muita das vezes, através de um único comando simples, sem 
a necessidade do uso de um bloco de código entre chaves. 
O comando for suporta sintaxes alternativas que ajudam ainda mais 
facilitar o seu uso. Pelo fato da maioria dos laços usar as variáveis de laço apenas 
dentro do corpo do laço, o comando for permite que a expressão de 
inicialização contenha uma declaração completa de variáveis. 
O escopo das variáveis declaradas na expressão de inicialização de um 
comando for se restringe ao corpo do laço e tais variáveis não mais podem ser 
acessadas fora do comando. 
 
Código 4-19: Comando for com escopo de variável local (i). 
 
Além do mais, a sintaxe do comando não restringe a utilização do 
comando a laços com apenas uma variável. Tanto a expressão de inicialização 
quanto a de atualização podem conter, em verdade, a inicialização e 
atualização de mais de uma variável, desde tais variáveis venham separadas por 
vírgulas. 
Por exemplo: 
Código 4-20: Comando for com expressão utilizando o índice e variáveis locais. 
 
Muito embora todos os exemplos de utilização do comando apresentem 
contadores numéricos, os laços construídos com o comando for não se 
restringem apenas à utilização de contadores. 
 As expressões de inicialização, teste e atualização do comando for são 
todas elas opcionais. O caractere de ponto e vírgula que separa tais expressões 
é, no entanto, obrigatório. Se a expressão de teste é omitida, presume-se que ela 
é sempre verdadeira. 
Com isto, um laço infinito pode ser escrito desta forma: 
Código 4-21: Comando for com loço infinito. 
for( int i = 0; i < 10; i++ ) { 
 Sytem.out.println( i ); 
} 
 
for( int i = 0, j = 10; i < 10; i++, j-- ) { 
 sum += i * j; 
} 
 
for( ;; ) // for infinito 
 
Comandos da Linguagem 
 4-17 
 
Comandos da Linguagem 
 4-18 
Comando “for-each” 
 
O novo for é um laço de repetição mais fácil e bonito de escrever. Este 
substitui o laço for atual de uma forma mais elegante para iterar sobre coleções. 
Observe o código abaixo que nos permite iterar uma coleção de alunos através 
do laço for tradicional: 
 
 Collection<Aluno> c = new ArrayList<Aluno>(); 
 ... 
 for (Iterator<Aluno> i = c.iterator(); i.hasNext(); ) { 
 System.out.println( i.next().getNome() ); 
 } 
Código 4-22: Comando for a ser transformado em for-each 
 
 
 Veja que uma simples tarefa de iterar uma coleção demanda um volume 
considerável de código. Agora observe a mesma versão deste código utilizando 
o laço “for-each” juntamente com o novo “import static”: 
 
 Collection<Aluno> c = new ArrayList<Aluno>(); 
 ... 
 for ( Aluno a : c ) { 
 out.println( a.getNome() ); 
 } 
Código 4-23: Comando for-each, mais simples que for 
 
 
 O sinal de “:” é lido com “em”. Desta forma o código acima pode ser lido 
da seguinte forma: “Para cada aluno a em c”. 
 
 For-each também pode ser aplicado a arrays. Neste caso você pode iterar 
um array da seguinte forma: 
 
 int[] notas = {2, 5, 7, 9, 4, 18}; 
 int total = 0; 
 for( int n : notas) { 
 total += n; 
 } 
 out.println( total ); 
Código 4-24: For-each para somar notas 
 
Comandos da Linguagem 
 4-19 
Comando break 
O comando break é utilizado para transferir o controle para fora do corpo 
do comando de laço ou switch mais próximo, transferindo imediatamente o 
controle para o primeiro comando após o corpo do laço ou switch. É usado, 
assim, para prematuramente sair de qualquer tipo de laço. 
Este comando é muito útil para abortar um laço quando algum evento 
ocorre durante a execução do corpo deste laço. 
Código 4-25: Estrutura do comando break 
 
O seguinte trecho de código utiliza o comando break junto ao comando 
while. Ele imprime números que juntos somam um valor menor que 200, iniciando 
em 0. 
Código 4-26: Comando break finalizando um loço while 
 
O comando break é também utilizado junto ao comando switch, para sair 
do corpo do comando. O trecho a seguir demonstra este uso. 
Código 4-27: Comando break finalizando um comando switch 
 
O comando break pode ser utilizado também seguido por um label que 
especifica um comando presente no método. Com o uso do comando break 
break; 
int i = 0; 
int total = 0; 
while( i < 100 ) { 
 total += i; // total = total + i; 
 if( total >= 200 ) { 
 break; 
 } 
 System.out.println( i ); 
 i++; 
} 
switch( resposta ) { 
 case 's': 
 case 'S': System.out.println("Resposta SIM."); 
 break; 
 
 case 'n': 
 case 'N': System.out.println("Resposta NÃO."); 
 break; 
 
 default: System.out.println("Resposta não reconhecida."); 
} 
Comandos da Linguagem 
 4-20 
associado a um label, é possível interromper qualquer laço dentro da definição 
do método, e não somente o laço mais próximo. 
Para utilizar o comando break com label, o label deve ser inserido antes do 
comando que se deseja interromper.O label pode ser qualquer identificador 
válido, seguido por “:”. 
Um comando break especificando este label causará um pulo para o 
primeiro comando após o fim do corpo do comando com este label. 
Código 4-28: Estrutura de comando break para quebra de laços nomeados 
 
O trecho de código a seguir exemplifica este uso. Após o múltiplo dos inteiros 
i e j atingir um valor maior que 200, o comando for associado ao label 
comandoFor é interrompido (comando for mais externo) e a linha indicando que 
o múltiplo foi atingido será impressa. 
Código 4-29: Comando break para quebra de laço for externo “comandoFor”. 
 
O comando break com label é muito utilizado para interromper laços 
aninhados. Contudo, embora este seja um mecanismo válido, ele pode levar a 
um código que não é claro e de difícil manutenção, sendo melhor evitá-los 
repensando a lógica do laço. 
label: 
comando { 
... 
break label; 
... 
} 
comandoFor: 
for( int i = 0; i < 100; i++ ) { 
 
 for( int j = 0; j < 100; j++ ) { 
 System.out.println(i*j); 
 if (i * j >= 200) { 
 break comandoFor; 
 } 
 } 
} 
System.out.println( "Fim do Comando FOR" ); 
Comandos da Linguagem 
 4-21 
Comando continue 
 
O comando continue é usado para transferir o controle para o fim do 
corpo do laço, antes da re-avaliação da expressão de teste. Causa, assim, a 
interrupção da interação do laço corrente e o pulo para a próxima interação do 
laço. 
Código 4-30: Estrutura do comando continue. 
 
O trecho a seguir exemplifica o seu uso. Neste exemplo, o comando 
continue é utilizado para interromper a execução do resto do corpo do 
comando for em todos os números pares. 
 Ao final, a soma de todos os números ímpares positivos menores que 10 é 
apresentada. 
Código 4-31: Comando continue reiniciando o laço for na próxima iteração de i 
 
O comando continue deve ser utilizado com cuidado, pois o algoritmo 
resultante se torna pouco estruturado e de difícil manutenção. 
O comando continue pode, assim como o break, ser utilizado com um 
label. Um comando continue com label causará a interrupção da interação 
corrente e o pulo para a próxima interação do laço associado ao label. 
 
continue; 
int total = 0; 
for( int i=0; i < 10; i++ ) { 
 if( i % 2 == 0 ) { 
 continue; 
 } 
 total = total + i; 
} 
System.out.println( total ); 
forExterno: 
for( int i = 0; i < 100; i++ ) { 
 
 for( int j = 0; j < 100; j++ ) { 
 System.out.println( i*j ); 
 if( i * j >= 200 ) { 
 continue forExterno; 
 } 
 } 
} 
System.out.println( "Fim do FOR Externo" ); 
Comandos da Linguagem 
 4-22 
Código 4-32: Comando continue para reinício de laço for externo “forExterno” no próximo índice 
de i 
 
 
Comandos da Linguagem 
 4-23 
Espaço para anotações 
Comandos da Linguagem 
 4-24 
Exercícios 
 
 1. Este exercício fará com que você altere as classes criadas no capítulo 
anterior adicionando algumas validações as suas operações. 
 Passo 1: Na classe Produto faça uma validação do parâmetro passado 
para operação que altera o preço do Produto. Não permita preços negativos. 
Valide também o código do Produto. Este deve possuir no máximo 6 caracteres. 
 Passo 2: Na classe ItemPedido, não permita atribuir através do método 
“set” um item do pedido ao produto se este não estiver em vendas. Faça o 
objeto item pedido “recusar” (não realizar a atribuição) o produto. 
 Passo 3: Agora faça uma alteração na classe Aplicacao para que a 
mesma ao imprimir os atributos booleanos imprima as palavras “Sim” e “Não” ao 
invés de true/false. Para isto utilize o operador ternário. Compile e teste a 
aplicação. 
 Passo 4: Altere um dos objetos produto que você criou para que o 
mesmo não esteja mais em vendas. Rode novamente a sua aplicação e verifique 
que para o pedido com o qual você tentou associar um produto que não estava 
em venda não sairá dados do produto. Nesta execução a JVM lancará também 
uma exception (NullPointerException). 
 Passo 5: Altere o código agora que faz a impressão das informações de 
um ItemPedido na classe Aplicacao para que quando um ItemPedido não tenha 
um produto seja impresso uma string mostrando isto. 
 
 2. Crie uma classe com o nome GeradorSenhas para que nesta seja 
possível gerar senhas através de um laço de repetição. 
 Passo 1: Crie uma classe pública chamada GeradorSenhas no pacote 
com.targettrust.java e nesta classe declare o método main para que a mesma 
possa ser executada. 
 Passo 2: Utilizando um laço de repetição a sua escolha (for, while, ..) faça 
a geração de 10 senhas randômicas com no máximo 8 díditos. 
 
 Dica para gerar números randomicamente: 
 Utilize a classe Math do pacote java.lang. Esta possui um método 
chamado random() que gera números aleatórios entre zero e um, excluindo o 
inteiro um. Veja a documentação JAVADOC para mais detalhes. 
Comandos da Linguagem 
 4-25 
 
Comandos da Linguagem 
 4-26 
Java Fundamentals 
 
 5-1 
55.. AApprrooffuunnddaannddoo oo eessttuuddoo ssoobbrree 
CCllaasssseess 
Aprofundando o estudo sobre classes 
 5-2 
Objetivos 
 
 
• Estudar overloading e overriding 
• Como utulizar métodos construtores 
• Compreender a referência this 
• Estudar o método destrutor finalize 
• Criar operações com escopo de classe e instância 
• Compreender o mecanismo de herança 
• Utilizar o recurso de varargs 
• Aplicar o polimorfismo 
• Compreender o modificador final 
• Estudar as enumerations 
Aprofundando o estudo sobre classes 
 5-3 
Visão Geral 
 
Métodos de instância são o fundamento para o encapsulamento de classes 
e peças chaves para fornecer uma interface consistente. Classes definidas 
através de técnicas adequadas de encapsulamento fornecem métodos de 
instâncias como o único meio de se acessar e alterar o estado de um objeto. 
Permitir o acesso direto às variáveis de instância de uma classe, sem que seja 
necessário invocar métodos para tal, é uma técnica de programação perigosa, 
pois não garante um estado sempre consistente para o objeto (o usuário não fica 
restrito às regras de negócios definidas na manipulação do objeto). 
A sobrecarga permite que uma chamada a um método possua diferentes 
comportamentos de acordo com os parâmetros passados. Suponha, por 
exemplo, a classe Cliente. 
O método comprar() desta classe pode ter comportamentos distintos 
dependendo dos parâmetros recebidos. 
Se a chamada for comprar(dinheiro), o comportamento invocado será 
provavelmente um pagamento à vista, enquanto se for comprar(cheque), outro 
será o comportamento invocado, fazendo com que o débito de pagamento 
possa ser realizado em um dia posterior. 
Sobrecarga é uma técnica poderosa, ao permitir que a classe tenha uma 
aparência uniforme para o mundo externo. 
Construtores garantem que, a despeito de quem cria o objeto, o objeto terá 
as características esperadas para a classe. 
Ao se criar um objeto, o método construtor é implicitamente chamado, 
oferecendo um local adequado para as rotinas de inicialização. Isto é ponto 
chave para programação orientada por objetos, já que é impossível saber quem 
criará novos objetos das classes que você definiu. 
Aprofundando o estudo sobre classes 
 5-4 
Overloading – sobrecarga de operação 
 
Dois ou mais métodos em uma classe podem ter o mesmo nome, desde que 
tenham assinaturas diferentes. A assinatura de um método é formada por seu 
nome, juntamente com o número, tipo e ordem dos parâmetros. O tipo de 
retorno do método não é considerado como parte da assinatura. 
A definição de dois ou mais métodos com o mesmo nome, mas com 
assinaturas diferentes é conhecida como sobrecarga de métodos (method 
overloading). Esta técnica é útil, pois oferece umainterface unificada da classe 
para o mundo externo. 
O método exato a ser chamado é determinado pelos parâmetros presentes 
na chamada, ou seja pela assinatura. Sem a técnica de sobrecarga, cada 
método exigiria um nome único, tornando mais difícil a codificação. Se você 
quisesse, por exemplo, recuperar informações sobre um cliente usando como 
chave de pesquisa o ID do cliente ou o nome, teria de escrever métodos com 
nomes distintos: getClientePorNome(nome) e getClientePorID(id). 
Usando sobrecarga, os dois métodos podem ter o mesmo nome 
getCliente(), um esperando o parâmetro id e o outro esperando o parâmetro 
nome, como mostrador abaixo: 
public class ClienteDB { 
 
 public Cliente getCliente(String nome) { 
 ... 
 } 
 
 public Cliente getCliente(int id) { 
 ... 
 } 
} 
Código 5-1 : Overloading da operação getCliente() 
 
Quando o usuário de uma classe chamar um método sobrecarregado, o 
compilador escolherá o método correto a ser chamado analisando os 
parâmetros passados na chamada e comparando tais parâmetros com os 
esperados por cada um dos métodos com aquele nome na definição da classe. 
Se o compilador não conseguir um “casamento compatível”, mesmo após 
efetuar as conversões implícitas permitidas pela linguagem, um código de erro 
será retornado. Do contrário, se mais de um casamento é possível, o compilador 
reclamará e assinalará erro de ambigüidade na definição do método. 
Métodos sobrecarregados não podem ser diferenciados exclusivamente 
pelo tipo de retorno. Se a única diferença entre a declaração de dois métodos 
Aprofundando o estudo sobre classes 
 5-5 
for o tipo de retorno, o compilador retornará um erro e não aceitará a 
construção. 
A distinção entre métodos sobrecarregados deve sempre ter por base o 
número e os tipos de parâmetros esperados. 
Código 5-2: Sobrecarga de métodos. 
public class Produto { 
 private float preco; 
 
 public float getPreco() { 
 ... 
 } 
 
 public float getPreco( float desconto ) { 
... 
 } 
} 
sobrecarga de 
método 
Aprofundando o estudo sobre classes 
 5-6 
Métodos construtores 
 
Métodos construtores são chamados quando um objeto da classe estiver 
sendo criado. Podem ser utilizados para realizar algo no momento de criação do 
objeto, como por exemplo, inicializar atributos do mesmo para determinados 
valores. 
O construtor é um método especial chamado automaticamente pelo 
ambiente de execução Java quando um objeto é criado. Um construtor sempre 
tem o mesmo nome que a classe. Ele pode esperar nenhum, um ou vários 
parâmetros, mas não pode ter nenhum tipo de retorno. Veja no código abaixo a 
declaração de um construtor: 
 
public class Produto { 
 
 Produto( ) { 
 ... 
 } 
 
} 
Código 5-3: Definindo construtores 
 
O construtor acima é conhecido como construtor default. O que acontece 
se um construtor não é fornecido? Caso nenhum construtor seja fornecido, Java 
supre esta ausência com um construtor default. Este construtor não recebe 
nenhum parâmetro e não executa nenhuma tarefa de inicialização. 
É possível colocar dentro deste construtor um código a ser executado no 
momento de criação do objeto. Assim quando o objeto da classe produto for 
criado utilizando o construtor acima este código será executado. Veja como 
pode ser criado um objeto utilizando o construtor acima: 
 
public class CriaObjeto { 
 public static void main(String[] args) { 
 Produto prod = new Produto(); 
 } 
} 
Código 5-4 : Criando um objeto e chamando o construtor 
 
Observe que o código acima já havia sido utilizado anteriormente, mas 
agora você pode perceber que estamos chamando o construtor default no 
momento da criação do objeto. 
Aprofundando o estudo sobre classes 
 5-7 
Se você desejar, poderá fornecer mais construtores na mesma classe. Desta 
maneira se fornecer algum construtor o compilador não mais ir;a gerar o 
construtor default. 
 Entretanto, na maioria das vezes, será necessário declarar um ou mais 
construtores para a classe, a fim de permitir diferentes formas de criação do 
objeto, como mostrado no código abaixo a criação de quatro objetos da classe 
produto de quatro formas diferentes: 
 
 
 
 
Código 5-5: Sobrecarga de construtores de Produto 
 
Para permitir que o usuário crie objetos desta maneira, será necessário 
fornecer os contrutores na classe Produto e que inicialize o estado do objeto 
Produto com as opções fornecidas. 
Construtores geralmente são declarados como public, salvo quando se 
deseja restringir quem pode criar objetos da classe. Veja abaixo um exemplo de 
construtor para a primeira e a segunda inicialização acima: 
 
public class Produto { 
 
 private String descricao; 
 private int codigo; 
 private float preco; 
 
 public Produto(int c, String d, float p ) { 
 codigo = c; 
 descricao = d; 
 preco = p; 
 } 
 
 public Produto(int c, String d) { 
 codigo = c; 
 descricao = d; 
 } 
} 
Código 5-6 : Construtores da classe Produto 
 
Observe o código acima e veja que além de termos definido construtores 
na classe Produto para dentro dos mesmos fazer a inicialização de um produto, 
também temos overloading de construtores. 
Produto prod1 = new Produto( 1, "CD", 45.50f ); 
Produto prod2 = new Produto( 2, "DVD" ); 
Produto prod3 = new Produto( "VHS" ); 
Produto prod4 = new Produto(); 
Aprofundando o estudo sobre classes 
 5-8 
 
Aprofundando o estudo sobre classes 
 5-9 
Referência this 
 
Esta referência representa um objeto da própria classe. O this referencia o 
objeto corrente. Todos os objetos “possuem” o this. 
Todos os métodos de instância recebem um parâmetro implícito chamado 
this, que pode ser usado dentro do método de instância para se referir ao 
objeto corrente. O objeto corrente é aquele cujo método foi invocado. O 
parâmetro this é uma referência implícita para objeto chamado e, como tal, 
não é necessário na maioria dos casos. 
 
 
Código 5-7: Referência implícita this do objeto invocado. 
 
Dentro de um método de instância, todas as referências não qualificadas 
para variáveis de instância ou métodos de instância estão implicitamente 
associadas com a referência this. Os dois comandos dentro do método 
setNome(), apresentados abaixo, são equivalentes: 
 
Código 5-8: Referência implícita this para representar variáveis de instância. 
 
public class Produto { 
 public void setNome(String nome) { 
 this.nome = nome; 
 } 
} 
 
public void metodo() { 
 Produto p1 = new Produto(); 
 Produto p2 = new Produto(); 
 
 p1.setNome( "CD" ); 
 p2.setNome( "DVD" ); 
} 
 
public void setNome( String nome ) { 
 nome = nome; // ERRO! 
 this.nome = nome; // Forma correta 
} 
p1 nome:"CD" 
 
p2 nome:"DVD" 
 
this 
Aprofundando o estudo sobre classes 
 5-10 
Há duas situações em que você deve usar explicitamente a referência this: 
 
• O nome de uma variável de instância é escondido por uma parâmetro 
formal, de mesmo nome, do método de instância. Suponha, por exemplo, 
uma classe que tenha uma variável de instância nome, e um método de 
instância que recebe uma variável também chamada nome. O parâmetro 
formal nome deste método esconde a variável de instância nome. 
Qualquer referência para nome, dentro deste método, acessará o 
parâmetro formal, não à variável de instância. Para acessar a variável de 
instância, você deve usar this.nome. 
 
• Quando você precisa passar uma referência para o objeto corrente 
como parâmetro de um outro método 
Aprofundando o estudo sobre classes 
 5-11 
Compartilhando código entre Construtores 
 
 
Um construtor pode chamar outro construtor da mesma classe usando a 
sintaxe this(). 
Código 5-9:Referência this invocando o construtor da própria classe de acordo com os tipos de 
parâmetros. 
 
O primeiro construtor chama o segundo construtor passando “vazio” como 
parâmetro. O segundo construtor copia a referência para o objeto String na 
variável nome. Esta técnica garante que o nome default para todos os objetos 
Produto seja uma string vazia sem a necessidade de se duplicar código em 
múltiplos construtores. 
A sintaxe this() minimiza a necessidade de se duplicar código nos 
construtores. Esta técnica é especialmente útil se a rotina de inicialização é 
complexa. Toda a complexidade vai em um construtor que é chamado pelos 
demais. 
Ao usar a sintaxe this() algumas regras de sintaxe devem ser observadas: 
• A chamada para this() deve ser o primeiro comando do construtor 
• Os parâmetros de this() devem casar com os parâmetros esperados por 
um construtor que não seja o chamador. 
public class Produto { 
 private String nome; 
 
 public Produto() { 
 this( “” ); 
 } 
 
 public Produto(String nome) { 
 this.setNome( nome ); 
 } 
} 
Um construtor pode 
chamar outro construtor 
usando a sintaxe this() 
Aprofundando o estudo sobre classes 
 5-12 
Método destrutor – finalize() 
 
 
Em algumas linguagens como C++, uma classe pode fornecer um destrutor. 
Um destrutor é similar a um construtor, sendo chamado automaticamente logo 
antes de o objeto ser destruído. 
Um destrutor é normalmente empregado para liberar recursos mantidos pelo 
objeto, tais como memória secundária alocada, arquivos abertos, etc. 
Java gerencia automaticamente a memória, logo um objeto não precisa 
explicitamente liberar memória que tenha alocado. Conseqüentemente, Java 
não suporta destrutores. A fim de permitir que um objeto libere outro recurso que 
não memória (pois esta já é automaticamente gerenciada), tais como arquivos 
abertos, Java permite que uma classe forneça um método finalize(). 
O método finalize() é chamado automaticamente quando um objeto é 
coletado pelo sistema coletor de lixo. Infelizmente, como vimos antes, não há 
como saber quando isto ocorrerá, ou mesmo que ocorrerá antes de o programa 
terminar. 
A falta de previsibilidade de quando o método finalize() será chamado 
é inaceitável se os recursos são escassos. 
A única solução é gerenciar tais recursos manualmente. A fim de assumir o 
controle do processo, você pode definir um método público dispose() em sua 
classe, que os usuários da classe terão de chamar quando tiverem terminado de 
usar um objeto desta classe. 
Você pode ainda manter o método finalize() se quiser, como um último 
esforço de liberar os recursos. 
Código 5-10: Método finalize para liberação de recursos alocados pela objeto. 
public class Produto { 
 
 public void finalize() { 
 // Libera todos os recursos alocados pela classe 
 System.out.println( "Instância sendo coletada pelo GC!" ); 
 } 
} 
Aprofundando o estudo sobre classes 
 5-13 
Variáveis de instância 
 
 Variáveis de instância são definidas dentro do bloco de código da classe. 
As variáveis de instância são variáveis que irão guardar valores específicos para 
cada instância da classe. Normalmente definimos variáveis/atributos como sendo 
de instância. Pode-se chamar os atributos que declaramos até o momento como 
variáveis de instância. O padrão quando declaramos atributos é que os mesmos 
sejam de instância. 
 
 Veja o exemplo abaixo: 
 
public class Cliente { 
 
 /* Variáveis/atributos de instância */ 
 private String codigo; 
 private String nome; 
 private char plano; 
 
 /* Variável de classe */ 
 public static float desconto; 
} 
Código 5-11 : Declarando vaiáveis de instância 
 
 
 Uma variável/atributo de instância pode ser acessado por um método de 
instância somente, ou pelo construtor da classe. 
 
 Observe que no código acima termos três variáveis de instância e uma de 
classe declaradas no fonte. Cada variável de instância terá um valor específico 
para o atributo. Veja a figura abaixo: 
 
 
 
 
 codigo = 98 codigo = 100 
 nome = Rafael nome = Walter 
 plano = A plano = B 
 
 
 obj01 obj02 
 
 
Figura 5-1 : Objetos com variáveis de instância 
 
 
 
 
 
Aprofundando o estudo sobre classes 
 5-14 
 
 
 
 
 O código que cria estes objetos é o seguinte: 
 
 
public class CriaCliente { 
 public static void main(String[] args) { 
 Cliente obj01 = new Cliente(); 
 obj01.setCodigo(98) 
 obj01.setNome(“Rafael”); 
 obj01.setPlano(‘A’); 
 
 Cliente obj02 = new Cliente(); 
 obj02.setCodigo(100) 
 obj02.setNome(“Walter”); 
 obj02.setPlano(‘B’); 
 
 } 
} 
Código 5-12 : Criando objetos Cliente 
 
Aprofundando o estudo sobre classes 
 5-15 
Métodos de instância 
 
De maneira análoga às variáveis de instâncias, você utiliza o operador 
ponto para chamar um método de instância de um objeto. A sintaxe é a 
seguinte: 
 
Código 5-13: Estrutura de chamada de um método de instância com parâmetros. 
 
Se o método não espera nenhum argumento, você deve se lembrar apenas 
de colocar os parêntesis (uma lista vazia de parâmetros): 
 
Código 5-14: Estrutura de chamada de um método de instância sem parâmetros. 
 
 
 No exemplo abaixo temos declaros na classe três métodos de instância. 
Observe estes e veja que os mesmos acessam os atributos de instância da classe. 
 
public class Cliente { 
 
 /* Variáveis/atributos de instância */ 
 private String codigo; 
 private String nome; 
 private char plano; 
 
 /* Métodos de instância */ 
 public void setCodigo(String codigo) { 
 this.codigo = codigo 
 } 
 
 public String getCodigo() { 
 return this.codigo; 
 } 
 
 public boolean validar() { 
 ... 
 } 
} 
 
Código 5-15: Definindo métodos de instância 
 
 
referenciaObjeto.nomeMetodo(parâmetros ...); 
 
referenciaObjeto.nomeMetodo(); 
 
Aprofundando o estudo sobre classes 
 5-16 
Variáveis de classe 
 
Variáveis de classe são variáveis comparadas as variáveis globais. Estas ao 
serem definidas irão possuir o mesmo valor para todos os objetos da classe. 
Uma variável de classe, também chamada variável estática (variável 
static), é aquela que pertence à classe e é comum a todas as instâncias desta 
classe. Em outras palavras, há somente uma instância de uma variável de classe, 
não importa quantas instâncias da classe existam. 
Observe o código que declaramos na sessão anterior quando estávamos 
estudando variáveis de instância. Havia uma variável/atributo de classe. O 
código é o seguinte: 
 
public class Cliente { 
 
 /* Variáveis/atributos de instância */ 
 private String codigo; 
 private String nome; 
 private char plano; 
 
 /* Variável de classe */ 
 public static float desconto; 
} 
Código 5-16 : Variável de classe definida 
 
Agora veja como seria o desconto para os objetos da classe: 
 
 
 
 
 codigo = 98 codigo = 100 
 nome = Rafael nome = Walter 
 plano = A plano = B 
 
 
 desconto= ... 
 obj01 obj02 
 
 
Figura 5-2 : Objetos compartilhando variável de classe 
 
 
Aprofundando o estudo sobre classes 
 5-17 
 
O desconte seria o mesmo para ambos os objetos. Em outras palavras 
podemos dizer que um atributo/variável de classe é compartilhado por todos os 
objetos da classe. Veja como ficaria o código para acesso a este 
atributo/variável: 
 
public class CriaCliente { 
 public static void main(String[] args) { 
 Cliente.desconto = 5.4f; 
 
 Cliente obj01 = new Cliente(); 
 obj01.setCodigo(98) 
 obj01.setNome(“Rafael”); 
 obj01.setPlano(‘A’); 
 
 Cliente obj02 = new Cliente(); 
 obj02.setCodigo(100) 
 obj02.setNome(“Walter”); 
 obj02.setPlano(‘B’); 
 
 } 
} 
Código 5-17: Acessando variável de classe 
 
Quando formos nos referencia a um atributo/variável de classe devemos 
utilizar o nome da classe para tal e não o nome do objeto. Neste exemplo 
estamos acessando diretamente o atributo, porém iremos mostrar mais adiante 
como deve ser feito o acesso a ele via uma operação. 
Em Java variáveis de classe são declaradas usando a palavra reservada 
static. No exemplo abaixo, nós declaramos a variável de classe precoMinimo 
porque, obviamente, o preço mínimo se aplica a todas as instâncias da classe 
Produto. 
Observe que precoMinimo foi declarada private, porque ela precisa ser 
acessada apenas pelos métodos da classe Filme. Neste exemplo, a variável 
precoMinimo é compartilhada por todos objetos, ou seja, é igual para todas as 
instâncias de Filme, muito embora cada instância possua sua própria descrição 
e código. 
Código 5-18: Variáveis de classe 
 
public class Produto { 
 
 private static double precoMinimo; // var. de classe 
 private String descricao; // var. de instância 
 private int codigo; // var. de instância 
 
} 
Aprofundando o estudo sobre classes 
 5-18 
Figura 5-3: Variáveis de classe e variáveis de instância. 
 
Aprofundando o estudo sobre classes 
 5-19 
Inicializando Variáveis de Classe 
 
Variáveis de classe são inicializadas quando a classe é carregada. Como 
construtores são utilizados para construir instâncias (e, portanto, invocados toda 
vez que uma nova instância é criada), você não pode utilizar construtores para 
inicializar variáveis de classe. 
Variáveis de classe possuem os mesmos valores de inicialização default que 
as variáveis de instância (na verdade qualquer variável definida e não 
inicializada recebe um valor de inicialização default): inteiros recebem o valor 0, 
reais o valor 0.0, booleanos o valor false, caracteres o valor '\u0000' e 
referências o valor null. 
Assim como as variáveis de instância, as variáveis de classe também podem 
ser inicializadas com valores diferentes do valor default. Basta, para isto, utilizar 
inicializadores. 
Código 5-19: Declaração de variáveis de classe 
 
Rotinas complexas de inicialização de variáveis de classe devem ser 
colocadas no bloco de inicialização estático (também conhecido como 
inicializador estático). 
Um inicializador estático não possui nome, nem valor de retorno e começa 
com a palavra reservada static seguida por um bloco de código delimitado 
por chaves (static {...}). 
Funciona de maneira similar a um construtor, com a diferença de que é 
executado apenas uma única vez e não depende das variáveis de instância de 
uma classe (não pode sequer referenciá-las). 
Código 5-20: Bloco static para inicialização de estruturas da classe 
 
public class Produto { 
 private static double precoMinimo = 30.50; 
 private String nome = "CD"; 
 private int codigo = 1234; 
 ... 
} 
public class Produto { 
 private static double precoMinimo; 
 static { 
 Date dataAtual = new Date(); 
 precoMinimo = getPrecoMinimoDia( dataAtual ); 
 } 
} 
Aprofundando o estudo sobre classes 
 5-20 
Métodos de classe 
Um método de classe, também conhecido como estático (método static) 
, é um método que pertence à classe e é compartilhado por todas as instância 
desta classe. Ao contrário de um método de instância, uma método de classe 
não atua sobre um único objeto. Estes métodos não recebem, portanto, a 
referência implícita this. 
Um método de classe pode acessar somente variáveis de classe e invocar 
métodos de classe. 
Métodos de classe são ideais para acessar variáveis de classe. De fato, eles 
são a única maneira, caso não exista nenhuma instância da classe (lembre-se: 
mesmo não existindo nenhuma instância de uma classe, as variáveis de classe já 
existem e têm um valor associado, pois são criadas quando a classe é carregada 
pelo ambiente de execução. 
Não é necessário ter uma instância da classe criada para poder acessar 
variáveis de classe) No exemplo abaixo, o valor do preço mínimo é alterado 
para todos os produtos, mesmo que nenhum objeto produto tenha sido criado 
ainda. 
Código 5-21: Declaração de método de classe 
 
 Veja o código que usaria esta classe definida acima: 
 
public class TestaStatic { 
 public static void main(String[] args) { 
 Produto.setPrecoMinimo( 17.5 ); 
 // ou 
 Produto p1 = new Produto(); 
 p1.setPrecoMinimo( 19.23 ); // Não recomendnado! 
 } 
} 
Código 5-22 : Acessando métodos de classe 
 
Objetos de classe são chamados com a seguinte sintaxe: 
Código 5-23: Estrutura de chamada de métodos de classe 
 
public class Produto { 
 private static double precoMinimo; 
 public static void setPrecoMinimo( float precoMinimo ) { 
 Produto.precoMinimo = precoMinimo; 
 } 
} 
NomeClasse.nomeMetodo(parametros); 
Aprofundando o estudo sobre classes 
 5-21 
Você pode chamar métodos de classe usando uma referência para um 
objeto e o operador ponto (da mesma maneira usada para métodos de 
instância), mas ainda assim, o método de classe só poderá acessar as variáveis 
de classe. 
Aprofundando o estudo sobre classes 
 5-22 
Exemplos de variáveis e métodos estáticos 
Quando você executa uma aplicação Java, a JVM localiza e chama o 
método main() desta classe. Muito embora tudo em um programa Java deva 
estar definido dentro de uma classe, você não precisa criar uma instância da 
classe principal se main() chama apenas métodos de classe e manipula apenas 
variáveis de classe. 
 
Código 5-24: Exemplos de métodos estáticos. 
 
Se, no entanto, main() acessa variáveis ou métodos de instância da própria 
classe em que se encontra definido, é necessário, antes de mais que ele crie 
instâncias desta classe. 
A classe Math fornece métodos de classe para o cálculo de muitas funções 
matemáticas, tais como funções trigonométricas e logaritmos. 
Fornece também várias constantes de classe tais como e (2.71828) e pi 
(3.1415926). 
A classe System fornece vários métodos de classe que representam o 
estado de todo o sistema (ambiente computacional). System.out é uma 
variável de classe que se refere ao objeto PrintStream. 
Esta variável de classe representa a saída padrão de dados. println() é 
um método de instância de PrintStream. 
 
 
public class ApenasMetodosEstaticos { 
 
 public static void main( String args[] ) { 
 double num, raiz; 
 // ... 
 raiz = Math.sqrt( num ); // Usando uma biblioteca 
 System.out.println("A raiz de " + num + " é " + raiz); 
} 
Aprofundando o estudo sobre classes 
 5-23 
O mecanismo de herança entre classes 
 
Herança define uma relação entre classes, onde uma classe (subclasse) 
toma de empréstimo as estruturas de dados e os comportamentos de outra 
classe (superclasse). 
Herança é uma valiosa técnica porque estimula e possibilita a reutilização 
de software ao permitircriar uma nova classe baseada nas propriedades de uma 
classe existente. Como resultado, o desenvolvedor é capaz de alcançar grande 
produtividade que, de outra forma, seria impossível. 
Construtores são blocos de código executados quando um objeto de uma 
classe é criado. Já vimos isto anteriormente. Ao usar o modelo de herança, cada 
subclasse tem acesso ao construtor da superclasse. Qualquer código comum 
relativo a inicialização do objeto, pode ser colocado na superclasse e invocado 
pela subclasse. 
Esta técnica minimiza a necessidade de se duplicar código e garante 
consistência na criação de objetos. 
Polimorfismo descreve a capacidade de Java executar um método 
específico com base na referência a um objeto utilizada na chamada. Usando 
esta técnica, você pode definir um método na superclasse e sobrescrevê-lo na 
subclasse apropriada. 
Você pode invocar os métodos da superclasse e, caso o método tenha 
sido sobrescrito na subclasse, Java automaticamente chamará o método 
apropriado. Isto é uma construção muito poderosa que possibilita definir métodos 
na superclasse sem mesmo conhecer detalhes de qualquer subclasse específica. 
Somente use herança para modelar uma genuína relação “é um tipo de”. 
Em outras palavras, não use herança senão quando todos os métodos herdados 
se aplicam à subclasse. 
Se você não pode substituir um objeto da superclasse por um objeto da 
subclasse, então você não tem uma genuína relação “é um tipo de”. Neste caso, 
as classes podem se relacionar, mas não hierarquicamente. 
Se você realmente usa herança, deve explorar a natureza polimórfica dos 
métodos de instância na hierarquia de classes. Por exemplo, se você acha que 
deve testar o tipo de um objeto na árvore de herança, use polimorfismo para 
evitar ter de escrever código separado para tratar objetos de cada classe. Isto 
maximiza a reutilização de seu código, e o torna mais fácil de manter no futuro. 
Vamos agora ver como estes conceitos mostrados acima são aplicados em 
java 
Aprofundando o estudo sobre classes 
 5-24 
Herdando estrutura e comportamento 
 
 Uma relação de herança faz com que a classe filha herde toda a estrutura 
e comportamento dos pais. 
 
A classe Produto define os atributos e métodos que são relevantes para 
todos os itens de inventário. Entre os atributos e métodos prováveis: 
• Atributos tais como data de aquisição, custo de aquisição, e condição. 
• Métodos tais como cálculo de quantia a ser paga pelo item, mudança 
de condições, e definição de preço. 
Dependendo do que quiser fazer no programa, você precisará definir um 
tipo específico de Produto. Você pode usar herança para definir uma subclasse 
de itens de inventário para cada tipo distinto de item. 
Você poderia definir, por exemplo, as seguintes subclasses: CD, DVD e VHS. 
Cada uma destas subclasses automaticamente herdaria todos os atributos 
e métodos de Produto e atributos e métodos adicionais poderiam ser fornecidos 
se necessários. 
A classe CD, por exemplo, poderia definir os seguintes atributos e métodos 
adicionais: 
• Atributos tais como título, produtor, duração. 
• Métodos tais como play, stop, etc. 
Subclasses podem também sobrescrever métodos da superclasse se 
desejarem fornecer um comportamento mais especializado para o método. 
 
 Figura 5-4: Herança entre Produto e CD. 
 
Aprofundando o estudo sobre classes 
 5-25 
Especificando herança em Java 
 
Quando você define uma subclasse, você precisa somente fornecer 
código para as facilidades da subclasse que diferem das existentes na 
superclasse. Efetivamente, a subclasse apenas estende a superclasse. 
A sintaxe para especificar herança em Java faz uso da palavra reservada 
extends. 
Por exemplo: 
 
Código 5-25: Especificando herança em Java. 
 
Se você tem experiência com outras linguagens OO (orientada por 
objetos) tais como C++, observe que Java permite somente herança simples. 
Em outras palavras, uma classe pode especificar somente uma única 
superclasse da qual herda. 
Lembre-se também que todas as classes em Java herdam 
automaticamente de uma classe raiz conhecida como Object, que se situa 
sempre no topo da árvore de herança. 
Se uma classe não especifica explicitamente uma superclasse, como no 
caso de Produto, então esta classe é forçada a herdar diretamente de Object, 
sendo sua definição (implícita) equivalente à seguinte definição explícita: 
Código 5-26: Utilizando a cláusula extends. 
public class Produto extends Object { 
 // Definição da classe Produto 
} 
 
public class CD extends Produto { 
 // Métodos e atributos adicionais para distingui-la 
 // dos outros tipos de itens de produto 
} 
public class Produto extends Object { 
 // Definição da classe Produto 
} 
Aprofundando o estudo sobre classes 
 5-26 
Objetos de subclasses 
 
A superclasse define as variáveis que são relevantes para todos os tipos de 
Produto, tais como nome e codigo. A subclasse CD herda estas variáveis sem ter 
de fazer qualquer esforço, e precisa somente especificar as variáveis que lhe são 
específicas, tais como duração. 
Suponha as seguintes classes: 
 Figura 5-5: Herança entre as classes CD e Produto. 
 
Se você cria um objeto Produto, ele apenas contém as variáveis definidas 
para Produto: 
Código 5-27: Criando um novo Produto. 
 
Entretanto, se você cria um objeto CD, ele conterá cinco variáveis de 
instância: as três herdadas de Produto mais as duas que ele próprio CD definiu. 
 
Código 5-28: Criando um novo CD 
 
Variáveis de instância devem normalmente ser declaradas private, o que 
significa que instâncias de subclasses herdam os valores, mas não podem acessá-
los diretamente. 
Como visto anteriormente, você deve definir, métodos para acessar 
variáveis privadas. Você pode definir métodos na subclasse ou herdá-los da 
superclasse. 
Produto produto = new Produto(); 
CD cd = new CD(); 
Aprofundando o estudo sobre classes 
 5-27 
Chamando construtores da superclasse 
 
A superclasse e a subclasse geralmente terão construtores que esperam 
parâmetros. Suponha, por exemplo, que Produto tenha um construtor que 
espera como parâmetros os valores iniciais de preco, nome e codigo. 
Da mesma forma, a classe CD tem um construtor que espera parâmetros 
suficientes para inicializar seus atributos. As coisas aqui começam a ficar 
interessantes.Um objeto CD tem cinco atributos: preco, nome e codigo herdados 
de Produto, e produtor e duracao definidos na própria classe CD. 
O construtor de CD terá, portanto, cinco argumentos: 
Código 5-29: Utilizando o contrutor de CD com parâmetros. 
 
Ao invés de inicializar preco, nome e codigo explicitamente, tudo o que o 
construtor de CD deve fazer é chamar o construtor de sua superclasse. Isto pode 
ser feito usando a palavra reservada super. A chamada super(...) deve ser o 
primeiro comando do construtor. 
Código 5-30: Invocando o construtor da superclasse a partir da referência super. 
 
Se você não chamar explicitamente super(...) o compilador chamará 
automaticamente o construtor sem parâmetros. Se a superclasse não tiver um 
construtor sem parâmetros, o compilador acusará um erro. 
public CD(float preco, String nome, int codigo, String produtor, int duracao) 
 
public CD(float preco, String nome, int codigo, String produtor, int duracao) { 
 super( preco, nome, codigo ); 
 setProdutor( produtor ); 
 seDuracao( duracao ); 
} 
public Produto(float preco, String nome, int codigo) { 
 setPreco( preco ); 
 setNome( nome ); 
 setCodigo( codigo ); 
} 
public CD(float preco, String nome, int codigo, String produtor, 
 int duracao) { 
 super( preco, nome, codigo ); 
 setProdutor( produtor ); 
 seDuracao( duracao ); 
} 
Aprofundando o estudo sobre classes5-28 
 Código 5-31: Referenciando o construtor da superclasse. 
Aprofundando o estudo sobre classes 
 5-29 
Overloading e Overriding de métodos 
 
 Overloading e overriding são freqüentes na programação orientada a 
objetos. Overloading é conhecido como sobrecarga enquanto overriding é 
conhecido como sobreescrita. Vejamos abaixo a definição destes dois conceitos: 
 
 
• Sobrecarga de métodos é quando você define múltiplos métodos com 
mesmo nome e diferentes assinaturas. Métodos sobrecarregados são 
resolvidos em tempo de compilação (resolver um método é descobrir 
qual versão do método deve ser chamada com base nas informações 
dadas pelo programador), com base no número e tipo dos parâmetros 
fornecidos. 
 
 
• Sobrescrita de métodos é quando você fornece um método com 
exatamente o mesmo nome e assinatura que este método possui em 
uma superclasse. Métodos sobrescritos são resolvidos em tempo de 
execução. Esta técnica é conhecida como polimorfismo e será discutida 
mais adiante. 
Aprofundando o estudo sobre classes 
 5-30 
Redefinindo métodos – overriding 
 
 
 Quando uma classe herda operações de outra classe, estas operações 
passam a fazer parte da estrutura da classe filha. Nem sempre desejamos manter 
a mesma implementação para a operação nos filhos, desta forma podemos 
redefinir tal operação. 
 
 Vejamos os códigos de exemplo abaixo: 
 
 Código 5-32: Especificando métodos adicionais na 
subclasse. 
 
O exemplo acima mostra alguns dos métodos declarados pela subclasse e 
pela superclasse. 
A superclasse define métodos que são relevantes para todos os tipos de 
Produto. 
A subclasse CD herda estes métodos da superclasse, e tem de adicionar 
apenas os métodos que lhe são específicos (relevantes para todos os objetos CD), 
tais como recuperação do produtor do CD e duração. 
Quando você cria um objeto, você pode chamar qualquer um dos seus 
métodos públicos (public), bem como qualquer método declarado público em 
uma de suas superclasses. 
Se você, por exemplo, cria um objeto Produto, você pode chamar os 
métodos públicos definidos em Produto, bem como quaisquer métodos públicos 
de sua superclasse Object: 
Código 5-33: Criando um Produto e acessando métodos herdados. 
 
public class Produto { 
 public float getPreco(); 
 public String getNome(); 
 
} public class CD extends Produto { 
 public int getDuracao(); 
 public String getProdutor(); 
} 
Produto produto = new Produto(); 
float preco = produto.getPreco(); // método public de Produto 
Class classe = produto.getClass(); // método public de Object 
Aprofundando o estudo sobre classes 
 5-31 
 
 
Se você cria um objeto CD, você pode chamar métodos públicos definidos 
em CD, Produto e Object. 
Código 5-34: Criando um CD e acessando métodos herdados 
 
 
Sobrescrevendo métodos da superclasse 
 
Uma subclasse herda todos os métodos de sua superclasse. Uma subclasse 
pode modificar o comportamento de um método de sua superclasse 
sobrescrevendo-o, como mostra o exemplo abaixo: 
 Código 5-35: Sobreescrevendo o método getPreco() 
 
Para sobrescrever um método de uma superclasse, a subclasse define o 
método exatamente com a mesma assinatura e tipo de retorno que o método 
possui quando declarado na superclasse. 
O método da subclasse efetivamente esconde o método declarado na 
superclasse. É importante ter certeza de que o método na subclasse mantém a 
mesma semântica que o método que está sendo sobrescrito. 
Qual método é chamado? No exemplo acima, a classe Produto fornece 
um método getPreco() e a classe CD sobrescreve este método com uma versão 
mais especializada. 
Se você criar um objeto Produto e chamar getPreco(), o método 
chamado será a versão definida em Produto. 
CD cd = new CD(); 
int duracao = cd.getDuracao() // método public de CD 
float preco = cd.getPreco(); // método public de Produto 
Class classe = cd.getClass(); // método public de Object 
public class Produto { 
 public float getPreco() { 
 return preco; 
 } 
} public class CD extends Produto { 
 public float getPreco() { 
 float x = getCustoCD() + calculaImpostos(); 
 return x; 
 } 
} 
Aprofundando o estudo sobre classes 
 5-32 
Se você criar um objeto CD e chamar getPreco(), o método chamado 
será a versão especializada definida em CD. 
Aprofundando o estudo sobre classes 
 5-33 
Referência super 
 
A referência super é útil quando a classe possui um ancestral. Uma 
subclasse herda todos os métodos e variáveis de sua superclasse, bem como 
define ela própria. Métodos da superclasse podem ser sobrescritos na subclasse, 
bastando a subclasse declará-los novamente e redefinir o seu comportamento 
(declarar novamente significa manter a assinatura do método tal qual se 
encontra na superclasse alterando apenas o corpo do método). 
A palavra reservada super permite que você acesse métodos da 
superclasse sobrescritos pela subclasse. 
Um dos usos mais comuns de super é chamar os construtores da classe pai. 
Quando a superclasse foi projetada, um construtor provavelmente foi declarado 
para garantir a inicialização correta de qualquer novo objeto. Como a subclasse 
herda todas as variáveis da superclasse, tais variáveis precisarão ser inicializadas 
para objetos da subclasse também. A palavra reservada super permite que 
você use o código do construtor definido na superclasse sem ter que duplicar o 
código em cada subclasse. 
Adicione a referência super no construtor da subclasse a fim de acessar o 
construtor da superclasse: 
Código 5-36: Estrutura de chamada explícita do construtor da superclasse 
 
A regra de sintaxe é que a palavra reservada super deve ser, neste caso, a 
primeira linha do construtor da subclasse. A palavra reservada super pode ser 
usada também para acessar os métodos da superclasse. 
Exemplo de uso da referência super: 
 
 
class SubClasse extends SuperClasse { 
 ... 
 public SubClasse(int param) { 
 super(param); 
 /* coloque aqui o código específico do construtor da subclasse */ 
 } 
} 
public class Produto { 
 private String nome; 
 public Produto( String nome ) { 
 super(); 
 this.nome = nome; 
 } 
} 
Aprofundando o estudo sobre classes 
 5-34 
 
 
 
public class Filme extends Produto { 
 private int ano; 
 public Filme( String nome, int ano ) { 
 super( nome ); 
 this.ano = ano; 
 } 
Código 5-37: Referência super invocando o construtor da superclasse 
 
No exemplo acima, há rotinas de inicialização que devem ocorrer para 
todos os objetos Produto. Estas rotinas são colocadas nos construtores de 
Produto. Tais rotinas devem sempre ser usadas, não interessando o tipo do 
Produto sendo construído, seja ele um CD, um Filme ou um Livro (subclasses de 
Produto). 
Há também construtores em cada uma das subclasses encarregados de 
rotinas de inicialização específicas destas subclasses. 
O construtor de Filme reutiliza o construtor de Produto ao referenciá-lo com 
a palavra reservada super. Este comando é o primeiro comando do construtor 
de Filme e pode ser seguido por quaisquer comandos que se fizerem necessários 
para uma adequada inicialização de objetos Filme. 
Aprofundando o estudo sobre classes 
 5-35 
Invocando métodos da superclasse 
 
Como mencionado anteriormente, quando uma subclasse sobrescreve um 
método de sua superclasse, ela esconde o método da superclasse. 
 
 
 
 
 Código 5-38: Sobreescrevendo e invocando o método getPreco() 
 
Se, por exemplo, o programa criar um objeto CD e chamar o método 
getPreco(), ele sempre estará executando a versão de getpreco()definida 
em CD. 
Código 5-39: Executando o método getPreco() 
 
Dentro do método getPreco() definido na classe CD pode-se invocar o 
método escondido de mesmo nome e assinatura, definido na superclasse 
Produto, através da palavra reservada super. 
A palavra reservada super é similar a this, salvo que atua como 
referência para o objeto corrente como uma instância da superclasse. 
Chamar um método escondido da superclasse usando super evitamos 
duplicar o código contido no método escondido. Ao reduzir o volume de código 
duplicado, facilita-se a tarefa de manutenção do software. 
public class Produto { 
 
 public float getPreco() { 
 return preco; 
 } 
 
} 
public class CD extends Produto { 
 
 public float getPreco() { 
 return super.getPreco() + calculaImpostos(); 
 } 
 
} 
CD cd = new CD(); // Cria objeto CD 
float v = cd.getPreco(); // Executa versão getPreco() de CD 
Aprofundando o estudo sobre classes 
 5-36 
Visibilidade protected 
 
 A visibilidade protected não foi demonstrada anteriormente pois o uso da 
mesma envolve o processo de herança. Agora que já vimos este recurso estamos 
aptos a estudar esta visibilidade. 
 
 Vejamos o código abaixo: 
 
package com.targettrust.java; 
public class Funcionario { 
 private String nome; 
 protected float salario; 
 ... 
} 
Código 5-40: Visiblidade protected aplicada a atributos 
 
 O código acima define uma classe Funcionário, a qual possui na sua 
estrutura um nome e um salário. Perceba que o nome é privado enquanto o 
salário é protected. O atributo nome poderá ser acessado somente por 
operações definidas dentro da classe, porém o atributo salário poderá ser 
acessado diretamente por outras classes que forem filhas de Funcionario. Isto 
poderá ser feito mesmo com a classe filha em outro pacote diferente do pacote 
onde estiver o Funcionário. Veja exemplo abaixo: 
 
package com.targettrust.rh; 
public class Vendedor extends Funcionario { 
 private float comisssao; 
 ... 
 public void calcularSalario() { 
 ... 
 float total = salario + comissao; 
 } 
} 
Código 5-41: Acessando um atributo protected 
 
 Veja que o acesso ao atributo é acessado na classe filha como se fosse 
declarado na mesma classe. Já o atributo privado não pode ser acessado. 
 
 Esta visibilidade também pode ser aplicada a operações da classe, porém 
o uso dela nestes casos não é comum. 
Aprofundando o estudo sobre classes 
 5-37 
Varargs 
 
Varargs é um recurso popular em algumas linguagens como C, C++ e 
linguagens derivadas. Este recurso permite passar um número variável de 
parâmetros a um método sem a necessidade de encapsulá-los manualmente 
em um array. Junto com varargs será utilizado o recurso de autoboxing. Veja o 
exemplo abaixo utilizando este recurso: 
 
public class Varargs { 
 
 public static void main(String[] args) { 
 
 foo("Java", "Oracle", "Linux"); 
 foo("Porto Alegre", "Ijui", "São Leopoldo", "Cruz Alta"); 
 
 } 
 
 public static void foo(String... args) { 
 for (int i=0; i<args.length; i++) { 
 System.out.println(args[i]); 
 } 
 } 
} 
Código 5-42: Usando varargs para receber mais de um parâmetro 
 
 A declaração acima “String... args” equivale a “String[] args”, mas se 
utilizado este recurso deve ser o último parâmetro do método. Quando este 
método for chamado na chamada podem ser passados vários parâmetros 
separados por vírgula desde que os tipos sejam sempre Strings. O enpasulamento 
dos parâmetros String em um vetor será feito de forma automática pelo 
compilador. Se o tipo de parâmetro é um Object, então os parâmetros se forem 
tipos primitivos serão transformados em objetos com o recurso de autoboxing. 
Para evitar este overhead da transformação de tipos primitivos nos objetos 
correspondentes utilizando o recurso de autoboxing, você pode utilizar, por 
exemplo “int... args”. 
 
 Se você tentar passar parâmetros com tipo incorretos, portanto não 
esperados pelo método, o compilador irá perceber e avisar. Veja exemplo 
abaixo: 
 
public class Varargs { 
 
 public static void main(String[] args) { 
 foo("Java", "Oracle", "Linux", 88); // Erro nesta linha! 
 } 
 
 public static void foo(String... args) { 
 for (int i=0; i<args.length; i++) { 
 System.out.println(args[i]); 
 } 
 } 
} 
Aprofundando o estudo sobre classes 
 5-38 
Código 5-43: Erro pois esta pasando inteiro e não String 
 
 
Aprofundando o estudo sobre classes 
 5-39 
Polimorfismo 
Usando a técnica de polimorfismo visualize a seguinte hierarquia de classes. 
 Figura 5-6: Hierarquia de classes representando herança e polimorfismo do método getPreco(). 
 
Ao projetar a aplicação de venda, não era sabido todo o tipo de produtos 
que seriam vendidos em longo prazo. Em programação não orientada por 
objetos, isto criaria um problema, que seria resolvido alterando o código sempre 
que um novo tipo de item fosse adicionado. Em Java, nós podemos usar 
polimorfismo para resolver este problema. Eis como: 
O método getPreco() da classe Produto é sobrescrito pelas classes CD e 
DVD, cada qual fornecendo uma versão especializada do método. 
A classe CarrinhoCompras possui um método addItem(Produto 
produto) que chama o método getPreco() através da referência recebida a 
um objeto Produto. 
Em tempo de execução Java interroga o parâmetro de addItem() para 
descobrir o tipo real do objeto e se o objeto possui alguma função sobrescrita. Se 
sim, Java usa o método sobrescrito pela subclasse (CD ou DVD), ao invés de usar o 
método definido pela superclasse (Produto). 
Aprofundando o estudo sobre classes 
 5-40 
Por exemplo, se a variável cd do tipo CD e dvd do tipo DVD forem 
adicionadas: 
Código 5-44: Adicionando CD e DVD ao método que espera Produtos. 
 
O mais importante é que as classes CarrinhoCompras e Produto não 
precisam ser modificadas quando novos tipos de itens de inventários forem sendo 
adicionados ao negócio. 
 
addItem(cd); // O método addItem chamará a versão de getPreco 
 // definida em CD e não em Produto 
 
addItem(dvd); // O método addItem chamará a versão de getPreco 
 // definida em DVD e não em Produto 
Aprofundando o estudo sobre classes 
 5-41 
Modificador final 
 
Por default todas as variáveis e métodos podem ser sobrescritos. Especificar 
uma variável como final evita que seu valor seja alterado. Isto é útil para 
garantir que um determinado valor seja consistente entre todos os usuários de 
uma classe. 
Você pode também declarar uma classe como final. Uma classe final 
não pode ser superclasse de nenhuma outra classe. Em outras palavras, não se 
pode herdar de uma classe final. 
Ao declarar uma classe como final você está tomando uma importante 
decisão de projeto, pois está dizendo que tal classe é completa o suficiente para 
atender todas as expectativas presentes e futuras de seus usuários, e que, 
portanto, nunca será necessário estendê-la para fornecer alguma funcionalidade 
adicional. 
Um método final não pode ser sobrescrito por nenhuma subclasse. Em outras 
palavras, se o programador herda de uma classe, não será permitido que ele 
forneça uma versão alternativa de um método declarado como final na 
superclasse. 
Esta é uma técnica útil para evitar que programadores inadvertidamente ou 
maliciosamente redefinam métodos essenciais que devem funcionar de uma 
maneira esperada. 
Resumindo: 
• Uma variável final é uma constante 
• Uma variável final não pode ser modificada 
• Uma variável final deve ser inicializada 
• Uma variável final é geralmentepública (public), permitindo o acesso 
externo 
 
Código 5-45: Variáveis final 
 
Métodos e classes são declarados final por suas razões principais: 
segurança e otimização. 
public final class Color { 
 public final static Color BLACK = new Color(0,0,0); 
 // ... 
} 
Aprofundando o estudo sobre classes 
 5-42 
Se um método executa alguma operação vital, tal como validação de 
identidade ou verificação de autorização, ele deve ser declarado final, a fim 
de evitar que seja sobrescrito por um método mal-intencionado que esteja 
procurando se esquivar das verificações de segurança. 
Muitos dos métodos definidos nas classes do pacote java.net são 
declaradas final. 
Se você declara uma classe como final, ela não poderá nunca mais ser 
estendida por nenhuma outra classe. Esta é uma decisão de projeto importante, 
pois afirma que a classe atende a todas as necessidades presentes e futuras de 
seus usuários. Esta implicação é clara: você não precisa. 
Código 5-46: Definindo uma Classe e um método final. 
 
public final class Criptografia{ 
 private String senha; 
 
 public final void getSenha(String senha) { 
 getCriptografia(senha, 128) // Chama Criptografia de 128 bits 
 } 
} 
Aprofundando o estudo sobre classes 
 5-43 
Enums 
 
Enums é uma forma mais fácil e segura para representar um conjunto de 
valores que são conhecidos em tempo de compilação e que não mudam com o 
passar do tempo. Estes valores são muitas vezes conhecidos como constantes de 
classe. A partir da nova versão do java, a versão 1.5, foi incluído este novo tipo 
que trás algumas vantagens listadas abaixo. Veja inicialmente o padrão que se 
costuma utilizar para representar constantes e guardar estações do ano: 
 
public static final int ESTACAO_INVERNO = 0; 
public static final int ESTACAO_PRIMAVERA = 1; 
public static final int ESTACAO_VERAO = 2; 
public static final int ESTACAO_OUTONO = 3; 
Código 5-47: Constantes de classe 
 
 
Este padrão tem os seguintes problemas: 
• Não é seguro – Uma vez que uma estação é um int, você pode passar 
qualqeur outro valor diferente dos especificados nas constantes acima, ou 
mesmo somar estas constantes, o que não faria sentido. 
• Prefixar constantes – Você precisa prefixar as constantes com strings para 
evitar colisões de nomes semelhantes. Este caso foram prefixadas com a 
palavra ESTACAO. 
• Os valores impressos não são informativos – Por serem constantes do tipo 
int estas constantes quando impressas não tem significado claro. Ao 
imprimi-la teremos um int e não um nome. 
 
Com enums o mesmo código acima ficaria da seguinte maneira: 
enum Estacao { INVERNO, PRIMAVERA, VERAO, OUTONO } 
Código 5-48: Definindo uma enumeration 
 
Tipos enum são cosiderados como objetos, acima temos a definição de um tipo 
“Estacao”. Uma enumeration herda da classe java.lang.Enum possuindo desta 
forma vários métodos para se poder manipular a estrutura. Métodos de Object 
também estão presentes em uma Enum. Comparable e Serializable são interfaces 
implementadas pelas enumerations, permitindo que as mesmas portanto possam 
ser comparadas e serializadas. 
Aprofundando o estudo sobre classes 
 5-44 
Veja abaixo uma versão completa de um código que utiliza enumerations: 
 enum Estacao { INVERNO, PRIMAVERA, VERAO, OUTONO } 
 
 public static void main(String[] args) { 
 foo( Estacao.INVERNO ); 
 } 
 
 public static void foo(Estacao x) { 
 out.println( x.ordinal() +" "+ x.name() ); // 0 INVERNO 
 } 
Código 5-49: Usando uma enumeration 
 
 
 Neste código acima observe que definimos um tipo “Estacao” e o mesmo 
é utilizado mais abaixo para passar valores ao método foo. Quando desejarmos 
imprimir o nome da estação passada como parâmetro através de enum 
podemos utilizar o método name(), a ordem dos valores é adicionada de forma 
automática e começa em 0. 
 
 É possível pegar de uma enumeration todos os seus valores através de um 
método estático values(). Este método facilita bastante a impressão dos valores 
quando desejarmos. Veja o código abaixo: 
 
 for(Estacao s : Estacao.values() ) { 
 out.println( s.name() + " " +s.ordinal() ); 
 } 
Código 5-50: Percorrendo uma enumeration 
 
 
Aprofundando o estudo sobre classes 
 5-45 
Espaço para anotações 
Aprofundando o estudo sobre classes 
 5-46 
Exercícios 
 
 1. Neste exercício você deve criar uma classe para representar um Curso. 
Esta classe terá métodos sobrecarregados (overloading) e redefinidos 
(overriding), bem como será uma classe filha da classe Produto e terá 
construtores para que seja possível criar objetos da mesma já passando 
informações na hora da criação. 
 
 Passo 1: Crie uma classe pública Curso no pacode com.targettrust.venda e 
faça com que esta classe extenda (herde) a classe Produto. Na classe Curso 
defina os seguines atributos e constante privados: 
 
 private int cargaHoraria; 
 private char turno; 
 private final float VALOR_HORA = 100f; 
 
Passo 2: Defina na classe Curso um método para calcular o preço do curso 
( public float getPreco() {...} ). Observe que este tem o mesmo nome do 
método que está sendo herdado da classe Produto. Na assinatura deste faça 
com que o mesmo possa receber um valor hora ( public float getPreco(float 
valorHora) {...} ) a ser levado em consideração no cálculo do preço do curso. 
O preço do curso deve ser calculado multiplicando-se a carga horária pelo valor 
hora passado como parâmetro no método. 
 
Passo 3: Crie outro método na classe Curso que seja capaz de redefinir o 
comportamento (overriding) do método public float getPreco() herdado da 
classe Produto. Esta operação deve retornar o preço levando em consideração 
o valor hora e a carga horária do curso, para isto utilize o valor hora da 
constante. 
 
Passo 4: Na classe Produto, bem como na classe Curso, defina um 
construtor que permita criar um objeto destas classes passando valores para 
todos os seus atributos. Isto irá fazer com que o construtor default não seja 
adicionado pelo compilador java. Desta forma adicione também ele a estas 
classes. 
 
Passo 5: No construtor da classe Curso faça com que o mesmo repasse os 
parâmetros que este receber e que devem ser atribuídos para os atributos da 
classe Produto para o construtor da classe Produto. Use para isto a referência 
super(...). 
 
Passo 6: Agora você irá modificar as classes que criou até o momento para 
que as operações set’s da classe Produto, ItemPedido e Curso possam receber 
parâmetros com o mesmo nome dos atributos. Use a referência this nestas classes 
para referenciar o atributo na hora da atribuição e defina o nome do parâmetro 
Aprofundando o estudo sobre classes 
 5-47 
com o mesmo nome do atributo. Gere novamente a documentação para estas 
classes e verifique as alterações. 
 
Passo 7: Na classe Curso defina o método destrutor finalize() e dentro deste 
faça a impressão de uma string sinalizando que o mesmo está sendo executado. 
 
public void finalize() { ... } 
 
Passo 8: Crie agora uma classe pública TestaCurso no pacote 
com.targettrust.venda, declare nesta classe o método main e dentro deste 
método crie um objeto da classe Curso. Atribua informações para este objeto 
através do método construtor. Logo em seguida mostre os dados do objeto 
através dos seus métodos de leitura, os get’s. 
 
Passo 9: Atribua null para a referência criada que representa o curso e logo 
em seguida chame o método System.gc() para ativar o coletor de lixo e 
constatar a execução do método destrutor. 
 
Passo 10: Na classe Curso crie um bloco estático de código para sinalizar 
quando a classe está sendo carregada pela JVM. Neste bloco estático imprimauma mensagem. 
Java Fundamentals 
 
 6-1 
66.. CCoolleeççõõeess,, AArrrraayyss,, SSttrriinnggss,, ee 
WWrraappppeerr CCllaasssseess
Coleções, Arrays, String e Wrapper Classes 
 6-2 
 Objetivos 
 
 
• Estudar a API Collection 
• Utilizar classes StringBuffer e StringBuilder 
• Converter e encapsular dados com Wrapper Classes 
• Utilizar arrays 
• Compreender o mecanismo de autoboxing 
• Utilizar generics 
Coleções, Arrays, String e Wrapper Classes 
 6-3 
Strings 
Assim como na maioria das linguagens de programação, strings são usadas 
intensivamente em Java. Desta forma, a API Java fornece uma classe String 
para ajudá-lo a manipular seqüências de caracteres. 
Literais de string são transformados pelo compilador Java em objetos 
String. Eles podem então ser usados diretamente, passados como argumentos 
para métodos ou atribuídos a variáveis do tipo String. 
 
Código 6-1: Manipulação de Strings. 
 
A classe String representa uma string imutável. 
Isto significa que, uma vez criado um objeto String, você não poderá mais 
alterá-lo. Se você quiser modificar o conteúdo de uma string, você deverá usar a 
classe StringBuffer. Esta classe será estudada logo adiante. 
System.out.println( "Hello World!" ); 
String str = "Matrix"; 
Coleções, Arrays, String e Wrapper Classes 
 6-4 
Criando Strings 
 
A maneira mais fácil de se criar uma string é a partir de uma constante 
colocada entre aspas duplas, como mostra o exemplo abaixo: 
Código 6-2: Atribuição de valor String. 
 
Você pode usar o operador mais (+) para concatenar dois objetos String. 
Isto é explicado em maiores detalhes adiante. Veja um exemplo do uso do 
operador mais (+) quando aplicado a objetos String: 
Código 6-3: Concatenação de Strings entre variáveis e String fixa. 
 
A classe String fornece vários construtores. Eis aqui alguns dos construtores 
mais úteis: 
• String() cria uma string vazia, com o valor "" 
• String(String str) cria uma cópia do objeto String referenciado por 
str 
• String(char[] arr) cria uma string a partir dos caracteres presentes no 
vetor arr 
 
Código 6-4: Criação de String utilizando o construtor da classe String. 
 
Você encontrará uma lista de construtores na documentação do JDK para 
a classe String. A classe String é parte do pacote java.lang. 
java.lang é um pacote automaticamente importado por todas as classes 
Java. Não é preciso, portanto, declarar um comando explícito de import para 
poder usar a classe String em seu código. 
String produto = "Caneta"; 
String nomeEmp = primeiroNome + " " + ultimoNome; 
// uso de construtores 
String nomeEmp = new String( "Maria Isabel" ); 
Coleções, Arrays, String e Wrapper Classes 
 6-5 
Concatenando Strings 
 
Java usa o operador + para concatenação de strings. O método concat() 
de String é outra forma de se concatenar strings. 
O seguinte código produz strings equivalentes: 
 
Código 6-5: Exemplos de concatenação de Strings. 
 
O exemplo abaixo mostra um tipo primitivo (no caso um int) sendo 
concatenado com uma String. 
O tipo primitivo é convertido implicitamente para String: 
Código 6-6: Conversão de tipos primitivos para String. 
 
Literais de string não podem se estender por mais de uma linha, mas você 
pode concatená-los e produzir o mesmo efeito: 
 
Código 6-7: Concatenação de Strings utilizando caracteres de escape. 
// Concatenação 
String nome = "Carlos Silva"; 
nome = "Carlos " + "Silva"; 
nome = "Carlos ".concat("Silva"); 
int codigo = getCodigo(); 
System.out.println("Código: " + getCodigo() + "."); 
String soneto = "De tudo ao meu amor serei atento\n" + 
 "Antes e com tal zelo, e sempre, e tanto\n" + 
 "Que mesmo em face de maior encanto\n" + 
 "Dele se encante mais meu pensamento."; 
Coleções, Arrays, String e Wrapper Classes 
 6-6 
Executando operações em objetos String 
 
O método length() retorna o número de caracteres de uma string: 
Código 6-8: Tamanho de uma String. 
 
O método charAt() retorna o caractere especificado pelo índice passado 
como argumento para o método (os índices sempre começam em 0). 
Código 6-9: Recebendo um caracter a partir de uma String. 
 
O método substring() retorna uma substring específica (dois argumentos 
são fornecidos a este método: o índice do primeiro caractere da substring e o 
índice do caractere após o último caractere da substring desejada). 
Código 6-10: Produzindo substrings. 
 
O método toUpperCase() retorna uma nova string contendo uma versão 
da anterior com todos os caracteres convertidos para a forma maiúscula. O 
método toLowerCase() retorna uma nova string contendo uma versão da 
anterior com todos os caracteres convertidos para a forma minúscula. 
Código 6-11: Transformando uma String para maiúsculo e minúsculo. 
 
O método trim() retorna uma nova string contendo uma cópia da string 
original com espaços em branco removidos tanto no início quanto no final. 
Código 6-12: Truncando espaços de uma String. 
String s = "Maria"; 
int tam = s.length(); // tam = 5 
// 01234 
String s = "Maria"; 
char c = s.charAt(2); // c = 'r' 
// 01234 
String s = "Maria"; 
String sub = s.substring(2,4); // sub = "ri" 
String sub = s.substring(2); // sub = "ria" 
String s = "Maria"; 
String M = s.toUpperCase(); // M = "MARIA" 
String m = s.toLowerCase(); // m = "maria" 
String s = " Cadastro de Clientes "; 
String t = s.trim(); // t = "Cadastro de Clientes" 
Coleções, Arrays, String e Wrapper Classes 
 6-7 
O método indexOf() retorna o índice de uma determinada substring. O 
método lastIndexOf() retorna o índice da última ocorrência de uma string 
determinada. 
 
Código 6-13: Busca índices de ocorrências de substring dentro de uma String. 
 
Há várias versões para cada um destes métodos. Dê uma olhada na 
documentação da classe String para maiores detalhes sobre cada uma delas. 
// 0 1 2 
// 012345678901234567890 
String s = "fábrica de brinquedos"; 
int iof = s.indexOf("bri"); // iof = 2 
int liof = s.lastIndexOf("bri"); // liof = 11 
Coleções, Arrays, String e Wrapper Classes 
 6-8 
Comparando duas Strings 
 
O método equals() retorna true se as strings especificadas contêm o 
mesmo texto. Caso a string passada como parâmetro seja null, equals() 
retorna false. 
Importante: o método equals() diferencia maiúsculas de minúsculas! 
 
Código 6-14: Comparação de Strings case sensitive. 
 
O método equalsIgnoreCase() é similar a equals(), exceto que ignora 
diferença entre maiúsculas e minúsculas. 
Código 6-15: Comparação de Strings case insensitive. 
 
Não use o operador == para comparar objetos String! O operador == retorna 
true dependendo da JVM quando ambas as variáveis referenciarem o mesmo 
objeto. 
String senha = getSenha(); 
if(senha.equals("brasil2010")) 
String cat = getCategoria(); 
if(cat.equalsIgnoreCase("Drama")) 
Coleções, Arrays, String e Wrapper Classes 
 6-9 
Obtendo strings a partir de objetos 
 
Se sua classe tem um método toString(), você pode incluir o seu objeto 
em expressões de concatenação de strings. E você pode imprimir seu objeto 
como se este fosse uma string. O método toString() é invocado 
automaticamente sempre que você usa um objeto em uma expressão de 
concatenação de strings ou passa este objeto para System.out.println(). 
No exemplo abaixo, a classe Produto fornece uma implementação de 
toString() que imprime o nome e o código do produto. 
Código 6-16: Produzindo String a partir de uma referência. 
 
O que acontece quando a classe não fornece o método toString()? Se a 
classe não fornece o método toString(),ela herda um da classe Object. 
A string produzida por Object.toString() não é muito amigável. Consiste 
do nome da classe da qual o objeto é uma instância e um número hexadecimal 
representando uma entrada hash. 
public class Produto { 
 public String toString() { 
 return getCodigo() + " - " + getNome(); 
 } 
} 
 ... 
Produto p1 = new Produto( 1, "DVD" ); 
System.out.println( "Produto: " + p1 ); // "1 – DVD" 
Coleções, Arrays, String e Wrapper Classes 
 6-10 
Convertendo tipos primitivos em strings 
A classe String fornece um método estático valueOf() que retorna uma 
string representando o tipo primitivo. Há uma versão de valueOf() para cada 
tipo primitivo. 
O exemplo abaixo usa duas versões: 
 
Código 6-17: Convertendo tipos primitivos em String. 
 
Quando um tipo primitivo é concatenado com uma string, ele é 
automaticamente convertido para String através de String.valueOf(). 
Quando um tipo primitivo é passado para System.out.println(), a versão 
apropriada de System.out.println() é chamada. Há uma versão para cada 
tipo primitivo. 
 
Na versão do J2SDK 1.5 é permitido a seguinte codificação: 
Código 6-18: Convertendo tipos primitivos em String utilizando printf no J2DSK 1.5. 
 
As expressões “%s” e “%d” formatam as saídas de “James Gosling” e “53”. 
String sete = String.valueOf(7); // chama valueOf(int) "7" 
String umPontoZero = String.valueOf(1.0f); // chama valueOf(float) "1.0" 
 
System.out.printf("Nome: "); 
String user = "James Gosling"; 
int total = 53; 
System.out.printf("%s possui %d anos.\n", user, total); 
Coleções, Arrays, String e Wrapper Classes 
 6-11 
Wrapper Classes 
Para cada tipo primitivo, Java fornece uma classe invólucro (wrapper class) 
correspondente. Estas classes permitem que um tipo primitivo seja manipulado 
como se fosse um objeto. 
Cada classe invólucro fornece um método estático para converter uma 
string para o tipo primitivo correspondente. 
Outros usos para Wrapper Classes 
• Wrapper Classes são úteis quando você precisa tratar um tipo primitivo 
como um objeto. Java, por exemplo, define uma classe Vector, que 
implementa um vetor dinâmico de objetos (o tamanho do vetor pode 
ser alterado dinamicamente). Você não pode armazenar tipos primitivos 
em Vector. Neste caso, você precisará usar uma classe invólucro. Para 
armazenar, por exemplo, variáveis do tipo int em um Vector, você 
precisará criar um Integer para cada int: a classe Integer possui um 
construtor que faz isto. 
• Wrapper Classes fornecem um local adequado para métodos de 
conversão relacionados ao tipo. A classe Integer, por exemplo, possui 
vários métodos, incluindo aí Integer.parseInt() para converter um 
tipo int em outro tipo. 
• Wrapper Classes fornecem um local adequado para variáveis 
relacionadas ao tipo. Em Integer, por exemplo, Integer.MAX_VALUE 
representa o maior valor que um inteiro pode alcançar. 
 
 Tabela 6-1: Tipos primitivos e Wrapper Classes de apoio. 
Tipo 
Primitivo 
Classe invólucro 
correspondente 
boolean Boolean 
char Character 
byte Byte 
short Short 
int Integer 
long Long 
double Double 
float Float 
Coleções, Arrays, String e Wrapper Classes 
 6-12 
Conversões com Wrapper Classes 
 
O exemplo abaixo mostra como usar os métodos de conversão para 
processar os campos de um formulário. Todos os campos textos guardam valores 
do tipo String. Temos, então, que ler os valores dos campos em variáveis do tipo 
String. No exemplo, é esperado um valor inteiro no primeiro campo e um valor 
real no segundo. 
Métodos de conversão são necessários para converter um valor String 
para int e float respectivamente. 
Observe que os métodos de conversão são chamados sem a necessidade 
de se instanciar um objeto Integer ou Float. As classes invólucros são um local 
adequado para métodos de conversão e não precisam ser instanciadas quando 
tais métodos são usados. 
 
 
 
 
Código 6-19: Convertendo String para o tipo primitivo correspondente de acordo com a Wrraper 
Class. 
 
O que acontece se o usuário entra com um valor não inteiro no primeiro 
campo? 
Caso isto aconteça, parseInt() irá falhar e levantar uma exceção. Para 
tratar esta situação, seria necessário colocar código adicional para capturar e 
tratar a exceção levantada, tanto por parseInt(), quanto por parseFloat(). 
Exceções serão estudadas mais adiante. O código acima poderia ser feito da 
seguinte forma: 
Código 6-20: Convertendo String para o tipo primitivo correspondente de acordo com a Wrraper 
Class. 
 
String qtdVal = qtdCampo.getText(); 
String prcVal = prcCampo.getText(); 
int qtd = Integer.parseInt(qtdVal); 
float prc = Float.parseFloat(prcVal); 
int qtd = Integer.parseInt(qtdCampo.getText()); 
float prc = Float.parseFloat(prcCampo.getText()); 
// Suprimimos a declaração de variáveis 
Quantidad
Preço: 
17 
425.00 
qtdCamp
prcCampo 
Coleções, Arrays, String e Wrapper Classes 
 6-13 
StringBuffer e StringBuilder 
 
StringBuffer e StringBuilder representam strings que podem ser 
modificadas e estendidas em tempo de execução. A primeira deve ser utilizada 
quando mais de uma thread estiver utilizando o objeto já a segunda quando 
somente uma thread estiver o utilizando pois o acesso a a mesma é mais rápida. 
Estas estruturas permitem você adicionar dados a um objeto sem que o mesmo 
precise ser recriado como é o caso da String. Estas estruturas são estruturas 
mutáveis ao contrário da String que é imutável. 
O seguinte exemplo cria três novos objetos String e copia todos os 
caracteres cada vez que um novo objeto String é criado. Isto gera um 
overhead grande e deixa muitos objetos na memória para que o garbage 
collector os recolha. 
 
Código 6-21: Concatenando Strings com o operador +. 
 
É mais eficiente usar um objeto StringBuffer e seu método append(): 
Código 6-22: Concatenando Strings utilizando um StringBuffer 
 
StringBuffer também fornece um comportamento semelhante a 
StringBuilder porém esta é uma estrutura que possui os seus métodos 
sincronizados, o que deixa o acesso aos mesmos mais lento quando temos 
somente uma thread acessando o objeto. 
Você deve procurar utilizar StringBuilder em vez de StringBuffer. Veja abaixo 
um exemplo de StringBuilder e observe que a forma de uso dos mesmos é igual. 
 
StringBuilder sb = new StringBuilder(); 
 
sb.append("Java J2EE\n"); 
sb.append("Oracle\n"); 
sb.append("PostgreSQL\n"); 
 
System.out.println(sb); 
Código 6-23: Utilizando StringBuilder 
String texto = "O texto começa com uma linha\n"; 
 texto = texto + "E ganha outra linha\n"; 
 texto = texto + "E mais uma...\n"; 
StringBuffer texto = new StringBuffer( "O texto começa com uma linha\n" ); 
texto.append( "E ganha outra linha\n" ); 
texto.append( "E mais uma...\n" ); 
Coleções, Arrays, String e Wrapper Classes 
 6-14 
Arrays 
Um vetor é uma coleção de variáveis do mesmo tipo. Cada elemento 
pode armazenar um único item. Os itens de um vetor podem ser de tipos 
primitivos ou referências para objetos. 
O comprimento de um vetor é fixo, quando criado. 
Vetores são úteis quando você deseja um grupo de objetos que possam ser 
manipulados como um todo. Caso você, por exemplo, escreva um programa 
para permitir a pesquisa por um filme, você provavelmente armazenará a lista de 
categorias em um vetor. 
 
 Figura 6-2: Estrutura de um vetor de Strings. 
 
 
Coleções, Arrays, String e Wrapper Classes 
 6-15 
 Arrays de tipos primitivos 
1. Declaração: Declare uma variável de referência para o vetor 
2. Criação: Crie um vetor de objetos do tipo e tamanho desejados, e 
armazene a referência para este vetor na variável de referência (do 
passo 1)3. Inicialização: Atribua os valores desejados para os elementos do vetor. Isto 
é opcional para um vetor de tipos primitivos porque os elementos 
recebem valores default quando o objeto vetor é criado. 
 
De maneira esquemática, temos: 
1. Declare a variável de referência que irá receber a referência para o 
objeto vetor 
 Figura 6-3: Referência inicial do vetor. 
 
2. Cria o vetor (alocação de memória e inicialização default dos elementos 
do vetor) 
 Figura 6-4: Referência com vetor padrão int. 
 
3. Atribuição de valores iniciais aos elementos do vetor 
 Figura 6-5: Referência com vetor padrão int inicializado. 
Coleções, Arrays, String e Wrapper Classes 
 6-16 
Declarando arrays de tipos primitivos 
Há duas maneiras de se declarar um vetor: (tanto faz!!!) 
 
 Tabela 6-2: Declaração de vetores. 
 
A maioria dos programadores Java usa o primeiro estilo porque ele separa o 
tipo da variável (no exemplo acima int) do nome da variável, tornando o 
código mais legível. 
Quando você declara uma variável de referência para vetor, ela 
inicialmente recebe o valor null, até que o vetor seja efetivamente criado 
usando new. 
 Figura 6-6: Declaração do vetor nums. 
Sintaxe Exemplo 
tipo[] nome; int[] nums; 
tipo nome[] int nums[]; 
Coleções, Arrays, String e Wrapper Classes 
 6-17 
Criando arrays 
Vetores devem ser criados usando o operador new. O tamanho do vetor 
deve ser especificado entre colchetes.O tamanho deve ser um inteiro, mas não 
precisa ser necessariamente uma constante. Pode ser uma expressão avaliável 
somente em tempo de execução. Uma vez que um vetor é criado, o seu 
tamanho permanece o mesmo por toda a existência do vetor. 
 
 Figura 6-7: Referência com vetor padrão int. 
 
Todos os elementos de um novo vetor de tipos primitivos recebem 
automaticamente o valor default para o tipo: 
• Elementos char recebem '\u0000'; 
• Elementos byte, short, int e long recebem 0; 
• Elementos float e double recebem 0.0; 
• Elementos boolean recebem false. 
Código 6-24: Contruções válidas de vetores. 
 
Código 6-25: Contruções inválidas de vetores. 
// CONSTRUÇÕES VÁLIDAS 
 
// exemplo 1: tamanho é uma constante 
final int TAM = 4; 
int[] nums = new int[TAM]; 
 
// exemplo 2: tamanho conhecido apenas em tempo de execução 
int[] notasExame; 
int n = getTotalAlunos(); 
notasExame = new int[n]; 
// CONSTRUÇÕES INVÁLIDAS 
 
// exemplo 1: o tamanho não faz parte da declaração do vetor 
int nums[4]; 
 
// exemplo 2: n não foi devidamente inicializada 
int n; 
int[] nums = new int[n]; 
Coleções, Arrays, String e Wrapper Classes 
 6-18 
Inicializando arrays 
Primeiro Método: Atribua um valor para cada elemento 
Para se referir a um elemento do vetor use um índice entre colchetes como 
mostrado no exemplo abaixo. 
Os elementos de um vetor são indexados de 0 a n-1, onde n é o número de 
elementos do vetor. Em outras palavras, o índice do primeiro elemento de um 
vetor é sempre 0 e não 1. 
 
 Figura 6-8: Atribuição de valor int para o vetor 
Segundo Método: Inicializadores de vetor 
Como mostrado no exemplo abaixo, há uma construção simplificada para a 
criação e inicialização de vetores de tipos primitivos. Aqui não há necessidade 
de usar o operador new e o comprimento do vetor é automaticamente 
detectado. 
Observe o uso de chaves e lembre-se de colocar o ponto e vírgula no final. 
 Figura 6-9: Declaração, criação e inicialização de vetor a partir de lista de valores int. 
 
Inicializadores de vetor são muito úteis para criar tabelas de pesquisa, como 
mostrado no seguinte exemplo: 
Código 6-26: Declaração, criação e inicialização de vetor a partir de lista de valores String. 
 
int [] diasMes = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 
Coleções, Arrays, String e Wrapper Classes 
 6-19 
Este método é útil quando o valor de cada elemento é conhecido quando 
o vetor é criado. 
Coleções, Arrays, String e Wrapper Classes 
 6-20 
Arrays de objetos 
Os passos para criar um vetor de referências são os mesmos que para criar 
um vetor de tipos primitivos, com uma única exceção: você deve sempre 
inicializar os elementos do vetor porque isto não é feito automaticamente. 
 
1. Declaração: A sintaxe é a mesma para vetores de tipos primitivos. Por 
exemplo: 
Código 6-27: Declaração de vetor String. 
 
2. Criação: A sintaxe é a mesma para vetores de tipos primitivos. Por 
exemplo: 
Código 6-28: Criação do vetor String com tamanho 3 
 
A linha acima cria um objeto vetor do tipo String e de tamanho 3. Todos os 
elementos, no início, recebem o valor null. 
3. Inicialização: Inicialize os elementos do vetor para o valor que desejar. Isto 
será visto com mais detalhes logo adiante. 
 
 
String [] nomes; 
 
nomes = new String [3]; 
Coleções, Arrays, String e Wrapper Classes 
 6-21 
Declarando arrays de objetos 
De maneira esquemática, temos: 
1. Declare a variável de referência que irá receber a referência para o 
objeto vetor 
 Figura 6-9: Referência de vetor null. 
 
2. Cria o vetor (alocação de memória e inicialização default dos elementos 
do vetor) 
 Figura 6-10: Criação do vetor de instâncias com tamanho 4 e 
valores null. 
 
3. Atribuição de valores iniciais aos elementos do vetor 
 Figura 6-11: Inicialização do vetor com Strings. 
Coleções, Arrays, String e Wrapper Classes 
 6-22 
Inicializando arrays de objetos 
Assim como para vetores de tipos primitivos, há duas maneiras de se 
inicializar um vetor de referências para objetos. 
Você pode inicializá-lo, atribuindo um valor para cada elemento do vetor, 
ou declarando um inicializador ao criá-lo. 
 
Código 6-29: Código para inicialização de vetor. 
 
Código 6-30: Criando vetor de String a partir de uma lista de Strings. 
 
A Propriedade length 
Cada vetor tem um atributo length que contém o número de elementos do 
vetor. Ao usar length, você evita ter de armazenar o tamanho do vetor em outra 
parte de seu código. 
A classe System fornece um método útil para copiar todo ou parte de um 
vetor para outro vetor. Para maiores informações, consulte System.arrayCopy() 
na documentação do J2SDK. 
// Inicializa elemento por elemento 
// Cria um vetor de 4 Strings vazias 
String[] array = new String[4]; 
for(int i=0; i<array.length; i++) { 
 arr[i] = new String(); 
} 
// Inicializadores 
String[] produtos = {"CD", "DVD", "VHS", "MP3"} 
Coleções, Arrays, String e Wrapper Classes 
 6-23 
Utilizando arrays de objetos 
Um vetor se comporta como objetos. Sendo assim, quando um vetor é 
passado para um método, na verdade, uma referência para este vetor é 
passada. Portanto, se o método altera o conteúdo do vetor, estas mudanças 
alterarão o vetor original (e não uma cópia). 
Qualquer elemento de um vetor pode receber um objeto do tipo correto, e 
também ser atribuído a uma variável de tipo compatível. Cada elemento de um 
vetor pode ser tratado como um objeto individual. 
Um elemento de vetor pode ser passado para um método, e neste caso, por 
ser um objeto, a referência para o objeto é que será passada. 
Código 6-31: Vetor de referência para objetos String. 
String[] produtos = new String[4]; 
// ... 
String produto = produtos[0]; 
produtos[1] = "Caneta"; 
 
System.out.println("Length: " + produtos[0].length()); 
Coleções, Arrays, String e Wrapper Classes 
 6-24 
Arrays e Exceções 
Exceções são levantadas dependendo de como vetores são manipulados. 
Caso você tente acessar uma posição inválida de um vetor, o programa será 
interrompido pela exceção ArrayIndexOutOfBoundsException. 
Caso tente acessar um elemento de umvetor que não tenha sido 
inicializado, a exceção NullPointerException será levantada. 
 
Código 6-32: Exceções comuns a partir de vetores. 
// Exceção ArrayIndexOutOfBoundsException 
String[] lista = new String[4]; 
System.out.println(lista[5]); 
 
// Exceção NullPointerException 
Produto[] listaProdutos = new Produto[3]; 
String nomeProduto = listaProdutos[0].getNome(); 
Coleções, Arrays, String e Wrapper Classes 
 6-25 
Arrays multidimensionais 
Java suporta vetores multidimensionais, isto é, vetor de vetores. 
Código 6-33: Declarando e criando uma matriz. 
 
A linha acima declara e cria uma matriz bidimensional: a matriz contém 
cinco linhas e cada uma das linhas possui quatro colunas. Elementos individuais 
podem ser acessados da seguinte maneira: 
Código 6-34: Esquema de acesso a uma matriz. 
 
O seguinte exemplo cria um vetor multidimensional com dez linhas, mas o 
número de colunas por linha é diferente. A primeira linha possui apenas um 
elemento, a segunda dois, a terceira três e assim por diante. 
Código 6-35: Criação de matriz com número de colunas diferentes. 
 
Exemplo de um vetor multidimensional: 
 Figura 6-12: Visão geral de estrutura e implementação de matrizes. 
 
 
 
 
int[][] matriz = new int[4][2]; 
matriz[indiceLinha][indiceColuna] = valor; 
int[][] a = new int[10][]; 
for(int i=0; i<a.length; i++) { 
 a[i] = new int[i+1]; 
} 
Coleções, Arrays, String e Wrapper Classes 
 6-26 
O método main(String[] args) 
Uma referência para um vetor pode ser passada para qualquer método. Um 
bom exemplo sito é o método main() usado nas aplicações Java. Quando você 
inicia uma aplicação Java, o sistema localiza e chama o método main() para 
esta classe. 
O método main() recebe um único parâmetro, que é uma referência para 
um vetor de objetos String. Cada objeto String guarda um parâmetro da linha 
de comando. 
O primeiro elemento do vetor contém o primeiro parâmetro da linha de 
comando, e não o nome do programa, como ocorre em C ou C++. 
É importante notar que os parâmetros da linha de comando são sempre 
representados por objetos String. Dentro do método main(), você pode 
converter os parâmetros para tipos primitivos. 
Se um dos parâmetros, por exemplo, representar um número, você deverá 
convertê-lo para um int para que possa realizar operações aritméticas com ele. 
Métodos de conversões foram vistos anteriormente. 
Na versão do J2SDK 1.5 temos a seguinte possibilidade de receber o vetor de 
Strings: 
Código 6-36: Recepção de parâmetros utilizando J2SDK 1.5. 
 
Utilizamos a expressão “...” para representar uma String dinâmica. 
public class Test { 
 public static void main(String... args) { 
 System.out.println(args.length + " argumentos"); 
 } 
} 
Coleções, Arrays, String e Wrapper Classes 
 6-27 
API Colletion 
 
Em Java a API Collection é referenciada como um framework. Este 
framework fornece um conjunto bem defindo de interfaces e classes para 
armazenar e manipular grupos de dados, conhecidos como coleções. Este 
framework fornece uma conveniente API para muitos dos tipos de dados 
abstratos das estruturas: Map, Set, List, Tree, Array, Hashtable e outras coleções. 
Este frameword está dentro do pacote java.util, desta forma este pacote 
deve ser sempre importado quando se desejar trabalhar com coleções. 
Uma simples collection não coloca nenhuma restrição sobre os tipos de 
elemento, ordem dos elementos, ou repetição dos elementos dentro da 
collection. 
Em java,a interface java.util.Collection define a collection básica de 
framework para todos tipos de collections. A Interface Collection possui métodos 
que permitem você adicionar itens, remover itens, pesquisar, e contar o número 
de elementos na collection. 
 
Principais métodos: 
 
- boolean add(Object element) 
- boolean remove(Object element) 
- void clear() 
- int size() 
- boolean isEmpty() 
- Object[] toArray() 
 
 
Coleções, Arrays, String e Wrapper Classes 
 6-28 
A interface Iterator 
 
Um Iterator é um objeto que pode ser utilizado para percorrer coleções. 
Com os métodos da interface Iterator, você pode percorrer uma collection do 
início ao fim e de forma segura remover os elementos da Collection. O iterator 
geralmente usa operações de busca. 
 
Métodos: 
- remove() 
- hasNext() 
- next() 
 
Veja abaixo o código exemplo para percorrer uma coleção do tipo 
ArrayList utilizando a interface iterator 
 
 ArrayList lista = new ArrayList(); 
 ... 
 Iterator it = lista.iterator(); 
 while ( it.hasNext() ) { 
 String s = (String)it.next(); 
 ... 
 } 
Código 6-37: Iterator 
Coleções, Arrays, String e Wrapper Classes 
 6-29 
A interface Enumeration 
 
A interface Enumeration permite você percorrer todos os elementos de 
uma collection. Percorrer uma collection com uma Enumeration é semelhante a 
percorrer com um Iterator. Emumeration não oferece suporte para remover 
elementos, coisa esta que você pode fazer com um Iterator. 
 
Métodos: 
- boolean hasMoreElements(); 
- Object nextElement(); 
 Veja abaixo um exemplo de código para percorrer uma Enumeration: 
 
 Hashtable tabela = new Hashtable(); 
 ... 
 Enumeration elementos = tabela.elements(); 
 while ( elementos.hasMoreElements() ) { 
 Produto p = (Produto)elementos.nextElement(); 
 ... 
 } 
Código 6-38 Enumeration 
 
Coleções, Arrays, String e Wrapper Classes 
 6-30 
Interfaces do framework 
 
 Neste framework existem várias interfaces que podem ser utilizadas, estas 
interfaces são estruturas que permitem armazenar objetos de formas específicas. 
Vamos ver algumas delas abaixo. 
 
 
Interface Set 
No conceito matemático, um conjunto é justamente um grupo de itens 
únicos, sem elementos duplicados. 
A interface Set estende a interface Collection. Set não permite duplicatas 
dentro da collection. Na implementação Set, null é uma entrada válida, mas 
permitida somente um por vez. 
 
Interface List 
 
Como o próprio nome já nos diz, representa uma lista que permite 
duplicatas. A interface List estende a interface Collection. Existem duas List 
implementations disponíveis na Collections Framework: ArrayList e LinkedList. 
 
A Interface Map 
Um map é um tipo especial de grupo sem duplicatas. Dentro da Collections 
API, java.util.Map define esta interface. Ele mapeia os valores chaves para os 
objetos armazenadao. O valores chaves são usados para procurar, ou indexar os 
dados armazenados. 
A interface Map não é uma extensão da interface Collection , ele possui 
sua própria hierarquia. Map não permite duplicatas dentro da collection. Na 
implemantação Map , null é uma entrada válida, mas só é permitido uma vez. 
Vamos estudar aqui uma implementação desta interface: Hashtable 
 
Coleções, Arrays, String e Wrapper Classes 
 6-31 
A classe ArrayList 
 
Implementa a interface java.util.List e usa array para armazenamento. Um 
armazenamento de array é geralmente mais rápido, mas possui limitações como, 
não poder inserir, e apagar entradas no meio da lista. Para realizar este tipo de 
adição e exclusão precisamos de um novo array, e isto gera portanto um 
overhead muito grande. Você pode acessar qualquer elemento 
aleatoricamente. 
Esta estrutura não é sincronizada, devendo ser utilizada quando o acesso a 
um objeto desta classe tiver uma única thread. 
 
Código 6-39: Exemplo de ArrayList 
 
package com.targettrust.exemplos; 
 
import java.util.*; 
 
/** 
 * - Elementos não ordenados 
 * - Permite duplicados 
 * - null É permitido 
 * - Semelhante a classe Vector 
 * - Acesso aleatório 
 */public class ArrayListExemplo { 
 public static void main(String[] args) { 
 List lista = new ArrayList(); 
 lista.add("Java J2EE"); 
 lista.add("Microsoft Net"); 
 lista.add("Linux"); 
 lista.add("Oracle"); 
 lista.add("Web Designer"); 
 lista.add("Java J2EE"); 
 lista.add(null); 
 
 System.out.println( lista.get(0)+", "+lista.get(4) ); 
 // [Java J2EE, Web Designer] 
 } 
} 
Coleções, Arrays, String e Wrapper Classes 
 6-32 
A classe Vector 
Uma vez que o tamanho do array é definido você não pode mudar o 
tamanho do array. Mas em java isso é possivel utilizando o mecanismo de 
refleção do Java que foi introduzido no Java 1.1, mas ele possui suas próprias 
limitações. 
Esta classe possui os seus métodos sincronizados desta forma deve ser 
utilizada quando o acesso ao objeto for concorrente. Já se o acesso não tiver 
esta característica então deve ser utilizada a classe ArrayList que não é 
sicronizada e é, portanto, mais rápida. 
Para lidar com este tipo de situação em Java utilize Vector, ele cresce e 
reduz seu próprio tamanho automáticamente. Isso permite somente objetos que 
não são primitivos. Para enviar primitivas, converta as primitivas à um objeto e 
envie elas para o vector. 
O vector realoca e redefine o tamanho automáticamente . Veja o exempo 
seguinte. 
Vector vt = new Vector(3, 10); 
As linha acima representam a capacidade inicial de três, e cresce em 
aumento de 10 em cada realocação quando se tenta adicionar o quarto 
elemento. Depois de realocado a capacidade do vector se torna a capacidade 
inicial + a capacidade aumentada (capacity Increment). 
 
Construtores: 
- Vector(int initialCapacity); 
- Vector(int initialCapacity, int capacitIncrement); 
- Vector() 
 
Métodos: 
- void addElement(Object obj); 
- int size(); 
- void setSize(int n); 
- void trimToSize(); 
 
 
Coleções, Arrays, String e Wrapper Classes 
 6-33 
Vejamos agora abaixo um exemplo com a classe Vector: 
 
Código 6-40: Exemplo de Vector. 
package com.targettrust.exemplos; 
import java.util.*; 
/** 
 * - Elementos não ordenados 
 * - Permite duplicados 
 * - null É permitido 
 * - Acesso aleatório 
 */ 
public class VectorExemplo { 
 public static void main(String[] args) { 
 Vector lista = new Vector(); 
 lista.add("Java J2EE"); 
 lista.add("Microsoft Net"); 
 lista.add("Linux"); 
 lista.add("Oracle"); 
 lista.add("Web Designer"); 
 lista.add("Java J2EE"); 
 lista.add(null); 
 
 System.out.println( lista.get(0) ); 
 System.out.println( lista ); 
 // [Java J2EE] 
 // [Java J2EE, Microsoft Net, Linux, Oracle, Web Designer, Java J2EE, 
 null] 
 } 
} 
Coleções, Arrays, String e Wrapper Classes 
 6-34 
A classe Hashtable 
 
 Hashtable é uma estrutura que possui os elementos armazenados 
internamente baseados em chave. Todo objeto guardado dentro desta estrutura 
ficará associado a uma chave para posterior recuperação do mesmo. 
 
 Esta estrutura é uma das mais rápidas quando o assunto é pesquisa, uma 
vez que o acesso ao objeto armazenado é direto através de chaves. 
 
 Veja um exemplo abaixo: 
 
package com.targettrust.exemplos; 
import java.util.*; 
/** 
 * - Elementos não ordenados 
 * - NÃO permite duplicados 
 * - null NÃO é permitido 
 * - Acesso baseado em chave 
 */ 
public class HashtableExemplo { 
 public static void main(String[] args) { 
 Hashtable lista = new Hashtable(); 
 lista.put(new Integer(1), "Java J2EE"); 
 lista.put(new Integer(2), "Microsoft Net"); 
 lista.put(new Integer(3), "Linux"); 
 lista.put(new Integer(4), "Oracle"); 
 lista.put(new Integer(5), "Web Designer"); 
 lista.put(new Integer(6), "Java J2EE"); 
 
 System.out.println( lista.get(new Integer(1)) ); 
 System.out.println( lista.get(new Integer(4)) ); 
 // [Java J2EE] 
 // [Oracle] 
 } 
} 
Código 6-41: Hashtable 
 
Coleções, Arrays, String e Wrapper Classes 
 6-35 
A classe LinkedList 
 
 
Implementa a interface java.util.List e usa linked list para armazenamento. 
Uma linked list permite que elementos sejam adicionados, removidos da 
collection em qualquer posição dentro do container. Com esta implementação 
você somente pode acessar os elementos sequencialmente. 
Veja abaixo um exemplo de uso desta estrutura: 
 
 
Código 6-42: Exemplo de LinkedList. 
 
 
 
 
package com.targettrust.exemplos; 
 
import java.util.*; 
 
/** 
 * - Elementos não ordenados 
 * - Permite duplicados 
 * - null É permitido 
 */ 
 
public class LinkedListExemplo { 
 public static void main(String[] args) { 
 List lista = new LinkedList(); 
 lista.add("Java J2EE"); 
 lista.add("Microsoft Net"); 
 lista.add("Linux"); 
 lista.add("Oracle"); 
 lista.add("Web Designer"); 
 lista.add("Java J2EE"); 
 lista.add(null); 
 
 System.out.println( lista ); 
 // [Java J2EE, Microsoft Net, Linux, Oracle, Web Designer, Java J2EE, 
 // null] 
 } 
} 
Coleções, Arrays, String e Wrapper Classes 
 6-36 
Generics 
 
Os tipos genéricos representam uma das maiores modificações na 
linguagem java já feitas até os dias de hoje. Tipos genéricos trazem a facilidade 
de parametrizar o tipo de classes, variáveis ou métodos. Na API do JDK 5.0 todas 
as collection, por exemplo, foram parametrizadas. Esta parametrização tornou 
classes como, por exemplo, ArrayList capazes de armazenar elementos de um 
tipo “E” e não mais Object. A declaração de ArrayList, por exemplo, agora pode 
ser feita da seguinte forma: 
 
1 ArrayList<Aluno> alunos = new ArrayList<Aluno>(); 
2 
3 Aluno a = new Aluno("Rafael"); 
4 alunos.add( a ); 
5 
6 Aluno x = alunos.get( 0 ); 
7 System.out.println("Nome: "+ x.getNome() ); 
Código 6-43: Generics 
 
Observe o código acima e perceba que na linha 6 não foi preciso realizar 
um “casting” para converter o objeto retirado da coleção. O mesmo havia sido 
armazenado internamente como um objeto Aluno e não como sendo do tipo 
“Object”. 
 
Além de simplificar a codificação, os tipos genéricos também são uma 
grande melhoria de robustez, evitando a possibilidade de typecasts errados e, 
portanto a ocorrência de ClassCastException. Isto também, é claro, aumenta a 
produtividade, pois perde-se menos tempo com depuração e testes – se o 
código compila, é porque vai funcionar, pelo menos no que diz respeito a tipos. 
 
Com os tipos genéricos, o programador pode formalizar restrições 
adicionais dos tipos que constrói, por exemplo, determinar que determinada lista 
só possa conter instâncias de Produto, e não objetos quaisquer. Violações dessas 
regras de tipagem não são críticas para a linguagem (pois não possibilitam perda 
de dados nem corrupção de memória), mas são críticas para o desenvolvedor, 
pois poderão ocultar erros de lógica. O resultado pode ser uma 
ClassCastException, ou – ainda pior – o bug pode ficar oculto por muito tempo, 
pois o valor opaco (Object) é convertido para o tipo que deveria ter. 
 
import static java.lang.System.*; 
... 
... 
Aluno a = new Aluno("João", "(51) 3325-2596" ); 
Map<String, Aluno> hash = new HashMap<String, Aluno>(); 
 
// Adiciona um aluno na Hash 
hash.put(a.getNome(), a); 
 
// Recupera o Aluno 
Aluno x = hash.get( a.getNome() ); 
Coleções, Arrays, String e Wrapper Classes 
 6-37 
 
// Mostra dados 
out.printf( "Dados: %s %s", x.getNome(), x.getTelefone() ); 
Código 6-44: Usando generics 
 
Acima você tem um código onde criamosuma HashMap para adicionar 
objetos do tipo Aluno associados a chaves do tipo String. Na declaração de 
HashMap especificamos que a chave será do tipo String bem como os objetos a 
serem armazenados serão Alunos, isto evita qualquer necessidade de “casting” 
posterior para recuperar os dados da estrutura, bem como fortalece o sistema de 
tipos proibindo que sejam utilizados tipos diferentes dos especificados na 
declaração. A linha abaixo não compilaria pois o tipo da chave esta sendo 
violada. 
 
hash.put(new Integer(1), a); //ERRO ao compilar! 
Código 6-45: Adicionando inteiro como chave 
 
Podemos também cria uma classe com tipos parametrizados. A classe 
abaixo representa um grupo no qual podemos guardar objetos. Os objetos a 
serem armazenados neste grupo são sempre do tipo especificado no parâmetro 
“T” da classe Grupo. Veja o código da classe: 
 
public class Grupo<T> { 
 
 private ArrayList elementos; 
 
 public Grupo() { 
 elementos = new ArrayList(); 
 } 
 
 public void add(T obj) { 
 elementos.add( obj ); 
 } 
 
 public void remove(T obj ) { 
 elementos.remove( obj ); 
 } 
} 
Código 6-46: Criando uma classe de um determinado tipo 
 
Podemos criar um objeto da classe grupo da seguinte forma: 
 
 Grupo<String> g = new Grupo<String>(); 
 g.add( "Java J2ME" ); 
 g.add( "Java J2EE" ); 
 g.add( new Integer(3) ); // ERRO! 
Código 6-47: Criando grupo de Strings 
 
 
Observe que na linha onde tentamos adicionar um inteiro teremos 
problemas, pois o grupo foi criado como sendo capaz de armazenar somente 
Strings. O tipo do grupo pode ser trocado conforme o código abaixo: 
 
 Grupo<Aluno> g = new Grupo<Aluno>(); 
Coleções, Arrays, String e Wrapper Classes 
 6-38 
 Aluno a = new Aluno("João", "(51) 3325-2596" ); 
 g.add( a ); 
 g.add( "Java J2EE" ); // ERRO! 
 g.add( new Integer(3) ); // ERRO! 
Código 6-48: Violando acesso ao grupo 
 
O código acima foi alterado para receber objetos aluno e armazenar 
dentro do grupo. Veja que a linha onde adicionamos agora uma String ou um 
Integer irá sinalizar erro. 
Neste exemplo acima os parâmetros do método add(...) bem como do 
remove(...) estão parametrizados. Teríamos outra opção para não utilizar os 
parâmetros genéricos, bastaria definir o tipo dos métodos como Object. Desta 
forma poderia ser criado um grupo e passado qualquer tipo de objeto para ele, 
mas isto permitiria que o grupo pudesse armazenar tipos diferentes de objetos. 
Para evitar isto você também poderia tornar os tipos dos parâmetros doa 
métodos fixos (String, por exemplo), mas desta forma você teria somente um 
grupo de strings e não poderia criar grupos de outros objetos. Observe que neste 
caso o objetivo é justamente permitir que se possa criar um grupo de tipos 
variáveis, mas uma vez definido um grupo como sendo de um tipo, o mesmo não 
poderá receber elementos de outros tipos. 
 
Coleções, Arrays, String e Wrapper Classes 
 6-39 
Autoboxing 
 
Autoboxing diz respeito a uma conversão automática que é feita entre os 
tipos primitivos da linguagem java (int, float, long, byte, etc...) e suas wrapper 
classes (Integer, Float, Long, Byte, Character, etc...). O programador não precisa 
mais se preocupar com estas conversões ficando a cargo agora da linguagem. 
Este recurso é interessante e simplifica a escrita de códigos porém introduz alguns 
efeitos colaterais listados mais abaixo. Deve desta forma ser utilizado de forma 
controlada. 
 
Integer i = 10; 
System.out.println( i ); 
Código 6-49: Autoboxing 
 
O código acima atribui um valor primitive (10) a um objeto do tipo Integer. 
Logo em seguida o objeto integer é impresso. 
 Um exemplo: 
 
 Quando trabalhamos com Collections sabemos que à uma coleção pode 
ser adicionado somente objetos, não sendo possível portanto adicionar um tipo 
primitivo a esta. Para isto o tipo primitivo deve ser encapsulado em uma wrapper 
class e então o objeto desta wrapper adicionado a Collection. Veja código 
abaixo: 
 
 
ArrayList lista = new ArrayList(); 
 
// Criando os objetos 
Integer um = new Integer(1); 
Integer dois = new Integer(2); 
Integer tres = new Integer(3); 
 
// Adicionando os objetos a Collection 
lista.add ( um ); 
lista.add ( dois ); 
lista.add ( tres ); 
Código 6-50: Adicionando dados em uma coleção 
 
 
A mesma dificuldade de manipulação ocorre quando temos que retirara o 
valor da coleção, pois se precisarmos manipular o valor como um tipo primitivo 
isto exigirá, além de um casting, uma chamada a um método do objeto retirado 
para o transformar novamente em um tipo primitivo. Todo este processo de 
encapsular e desencapsular é conhecido como: boxing e unboxing. Isto deixa o 
código maior e mais complicado de ser escrito. 
 
Coleções, Arrays, String e Wrapper Classes 
 6-40 
Veja abaixo a versão do mesmo agora para retirar os elementos: 
 
// Retira os objetos da coleção 
Integer x = (Integer)lista.get(0); 
Integer y = (Integer)lista.get(1); 
Integer z = (Integer)lista.get(2); 
 
// Mostrar os valores em formato int 
System.out.println( x.intValue() ); 
System.out.println( y.intValue() ); 
System.out.println( z.intValue() ); 
Código 6-51: Mostrando dados da coleção sem autoboxing 
 
 Podemos utilizar autoboxing para resolver e simplificar a escrita deste 
código. Veja abaixo a versão do código que adiciona os três valores dentro da 
collection. Observe que utilizamos para isto um tipo de collection que comporta 
somente Integer. Esta forma de representação de collection faz uso de Generics. 
 
ArrayList<Integer> lista = new ArrayList<Integer>(); 
 
// Adicionando dados a Collection 
lista.add ( 1 ); 
lista.add ( 2 ); 
lista.add ( 3 ); 
 
// Retira os dados da collection 
int x = lista.get(0); 
int y = lista.get(1); 
int z = lista.get(2); 
 
// Mostra os dados da collection 
System.out.println( x ); 
System.out.println( y ); 
System.out.println( z ); 
Código 6-52: Utilizando autoboxing para mostrar dados 
 
 
 
Comparando valores encapsulados: 
 
 Ao compararmos valores que foram encapsulados através do recurso de 
autoboxing, temos que tomar muito cuidado. Veja o código abaixo e os tipos de 
retorno. 
 
 
int i = 2; 
int j = 2; 
 
ArrayList <Integer> lista = new ArrayList<Integer>(); 
 
lista.add(i); 
lista.add(j); 
 
System.out.println( (i==j) ); 
System.out.println( lista.get(0)==lista.get(1) ); 
Coleções, Arrays, String e Wrapper Classes 
 6-41 
System.out.println( lista.get(0).equals( lista.get(1) ) ); 
Código 6-53: Comparando dado s de uma coleção 
 
As saídas para o código acima são as seguintes: 
 
true 
true 
true 
 
 
A primeira comparação esta comparando tipos primitivos e como já 
sabemos a saída deveria ser true. Já no segundo caso são comparados os 
valores que foram enpasulados (“autoboxed”), retornando também true. No 
terceiro caso são comparados os valores dos objetos criados através de 
autoboxing. 
 
Se o valor das variáveis inteiras forem alteradas para um valor superior a 
127, o retorno para a comparação lista.get(0)==lista.get(1) será false! Note 
que estamos neste caso comparando os valores enpasulados como objetos e 
não os valores primitivos diretamente. Para as demais comparações o retorno 
continua sendo true. Abaixo a saída para os valores alterados e superiores a 127: 
 
true 
false 
true 
Coleções, Arrays, String e Wrapper Classes 
 6-42 
Espaço para anotações 
Coleções, Arrays, String e Wrapper Classes 
 6-43 
Exercícios 
 
1. Neste exercício você irá criar uma classe nova para representar um 
pacote de cursos. Um pacote de cursos contém várioscursos. Teremos que saber 
quantos há neste pacote, bem como o valor total do pacote. Este valor será a 
soma do preço de todos os cursos. Veja abaixo os passos para isto: 
 
 
Passo 1: Crie uma classe pública chamada PacoteCurso no pacote 
com.targettrust.java e defina os seguintes atributos: 
 
 private ArrayList<Curso> cursos 
 private Date dataCriacao 
Coleções, Arrays, String e Wrapper Classes 
 6-44 
 Observe no atributo acima o uso de generics para definir o tipo de objetos 
da coleção 
Passo 2: Crie no método construtor o ArrayList. 
Passo 3: Defina nesta classe uma operação que possa receber objetos da 
classe curso e os adiciona a coleção cursos. Quando esta coleção atingir um 
número de 10 cursos deve ser impresso um aviso. 
Passo 4: Crie nesta classe uma operação capaz de calcular o valor total do 
pacote. Para fazer este cálculo você deverá percorrer a coleção e obter o 
preço de cada curso adicionado a ela. Use for-each para percorrer o ArrayList. 
Passo 5: Crie uma operação na classe PacoteCurso para que a mesma 
retorne uma StringBuilder contendo o nome de todos os curos que fazem parte 
do pacote. 
 
 
2. Agora você irá praticar o mecanismo de autoboxing do java. Vamos criar 
um ArrayList com números inteiros e percorrer o mesmo somando estes valores. 
 
Passo 1: Crie uma classe chamada ExemploAutoboxing no pacote 
com.targettrust.java e declare nesta classe o método main. 
Passo 2: Na classe declare um atributo privado, chamado lista, estático, do 
tipo ArrayList. Utilize Generics na declaração do atributo ( ArrayList<Integer> ) No 
método main crie este objeto que representa a lista e adicione no mesmo 5 
números do tipo int. 
Passo 3: Percorra a lista com um for-each e some todos os números da lista 
mostrando o total ao término do laço. Observe que não haverá casting para a 
soma dos números!
Java Fundamentals 
 
 7-1 
77.. TTrraattaammeennttoo ddee EExxcceeççõõeess 
Tratamento de Exceções 
 7-2 
Objetivos 
• Compreender as Vantagens do tratamento de Exceções em Java; 
• Manipular, Tratar, Propagar, Capturar e Criar Exceções. 
 
Tratamento de Exceções 
 7-3 
Introdução 
Uma exceção é um evento que ocorre durante a execução de um 
programa que interrompe o fluxo normal das instruções. Muitos tipos de erros 
podem causar exceções, tais como tentar acessar um elemento de um vetor 
fora dos limites ou tentar dividir um número por zero. 
Quando uma exceção ocorre dentro de um método Java, o método cria 
um objeto Exception e deixa que o ambiente de execução (runtime system) se 
encarregue do assunto. Na terminologia Java, este processo é chamado levantar 
uma exceção (throwing an exception). 
O objeto Exception criado contém informações sobre a exceção, tais 
como seu tipo e o estado do programa quando o erro ocorreu. 
Após o método levantar uma exceção, o ambiente de execução é então 
responsável por encontrar um código que manipule o erro. Para isso, o ambiente 
de execução entra em ação procurando o código de tratamento para o erro no 
conjunto de métodos da pilha de chamada do método em que o erro ocorreu. 
O ambiente de execução procura de trás para frente na pilha de chamada, 
começando com o método onde o erro ocorreu, até encontrar um método que 
contenha a manipulação apropriada da exceção. 
Uma manipulação de exceção é considerada apropriada se o tipo de 
exceção levantada é o mesmo tipo de exceção manipulada pelo manipulador 
(pelo código de tratamento da exceção). 
Assim, a exceção cruza a pilha de chamadas até que uma manipulação 
apropriada é encontrada e um dos métodos chamados trata a exceção. Na 
terminologia Java, se diz que o manipulador escolhido para tratar a exceção 
capturou (catch the exception) a exceção. 
Se o ambiente de execução procura exaustivamente em todos os métodos 
da pilha de chamadas sem descobrir um manipulador de exceções apropriado, 
o ambiente de execução (e conseqüentemente, o programa Java) termina. 
A utilização de exceções para manipular erros tem as seguintes vantagens 
sobre as técnicas de gerenciamento de erros tradicionais: 
1. Separa o código para manipular erros do código regular (do fluxo 
normal) do programa 
2. Propaga erros na pilha de chamadas 
3. Agrupa tipos de erros e os diferencia 
4. Não podem ser ignoradas 
Tratamento de Exceções 
 7-4 
1a Vantagem: Separação de Código 
Na programação tradicional, a detecção e manipulação de erros tornam o 
código freqüentemente mais difícil de compreender. Como exemplo, suponha 
que se tenha uma função que leia a primeira linha de um arquivo. 
Um esquema do código para esta função seria: 
Código 7-1: Exemplo de código estruturado para tratamento de arquivos. 
 
Esta função poderia ter diversos erros potenciais, tais como erro na abertura 
do arquivo, erro na leitura da primeira linha, erro no fechamento do arquivo. 
No modo de programação tradicional para detectar os potenciais erros 
para esta função, cada erro deve ser testado e atribuído para um código de 
erro. Isto leva a uma grande quantidade de código adicional para a detecção e 
manipulação dos possíveis erros. 
Por exemplo, a função anterior se tornaria uma função tal como: 
 
Código 7-2: Exemplo de código condicional para tratamento de arquivos com retorno de valor. 
 
 
 
Na linguagem Java, o problema de tratamento de erros é realizado a partir 
exceções. 
As exceções permitem que o programador escreva o código do fluxo 
principal e manipule os casos excepcionais em outro local. 
int leituraArquivo { 
 abre o arquivo; 
 le o arquivo; 
 fecha o arquivo; 
} 
int leituraArquivo { 
 int codigoErro = 0; 
 abre o arquivo; 
 if (erroAberturaArquivo) 
 codigoErro = -1; 
 else { 
 le o arquivo; 
 if (erroLeituraArquivo) codigoErro = -2; 
 fecha o arquivo; 
 if (erroFechamentoArquivo) codigoErro = -3; 
 } 
 return codigoErro; 
} 
 
Tratamento de Exceções 
 7-5 
 
 
A função exemplo anterior se tornaria uma função tal como: 
Código 7-3: Exemplo de código estruturado para tratamento de arquivos utilizando Java. 
 
Como pode ser visto, as exceções não dispensam a detecção e 
manipulação dos erros. 
O que elas fornecem são meios de separar da lógica principal todos os 
detalhes do que fazer quando algum evento fora do normal ocorre. Com isso, o 
código se torna mais claro e menos propenso a erros. 
leituraArquivo { 
 try { 
 abre o arquivo; 
 le o arquivo; 
fecha o arquivo; 
 } 
 catch (erroAberturaArquivo) { 
 manipula erro 
 } 
 catch (erroLeituraArquivo) { 
 manipula erro 
 } 
 catch (erroFechamentoArquivo) { 
 manipula erro 
 } 
} 
Tratamento de Exceções 
 7-6 
2a Vantagem: Propagação de Erros 
A segunda vantagem do uso de exceções é a habilidade de propagar a 
informação do erro através dos métodos da pilha de chamadas. 
Uma exceção em Java é enviada imediatamente para o manipulador 
apropriado, sem a necessidade do comando if em cada nível para transmitir o 
erro acima na pilha de chamadas. 
Suponha que o método do exemplo anterior, leituraArquivo, é o quarto 
método em uma série de chamadas de métodos aninhados feitas pelo 
programa principal: metodo1 chama o metodo2, que chama o metodo3, que 
chama leituraArquivo. 
O metodo1 é o único método interessado nos erros que ocorrem dentro do 
método leituraArquivo, e é o método que manipula estes erros. Na técnica de 
programação tradicional, o metodo2 e o metodo3 teriam que propagar os 
códigos de erros retornados por leituraArquivo adiante na pilha de 
chamadas até que os códigos de erros finalmente atingissem metodo1, o único 
método interessado nestes erros. 
Assim, na programação tradicional, seria necessário: 
1. leituraArquivo tenta executar sua função e retorna um códigode 
erro para metodo3 
2. metodo3 verifica a existência de erros e transmite o código de erro para 
metodo2 
3. metodo2 verifica a existência de erros e transmite o código de erro para 
metodo1 
4. metodo1 verifica a existência de erros e trata os erros ocorridos. 
Na manipulação de exceções em Java, contudo, o ambiente de execução 
procura de trás para frente na pilha de chamadas, procurando descobrir algum 
método que está interessado em manipular uma exceção em particular. 
Um método Java pode levantar qualquer exceção dentro dele, permitindo 
assim que um método adiante na pilha de chamadas possa capturar esta 
exceção. Com isso, apenas os métodos interessados devem se preocupar em 
detectar erros. 
Deste modo, manipulando exceções, é necessário: 
1. leituraArquivo levanta uma exceção 
2. metodo1 captura a exceção 
Tratamento de Exceções 
 7-7 
Além disso, as exceções que podem ser levantadas dentro de um método 
são parte da interface de programação pública do método e devem ser 
especificadas na cláusula throws do método. 
Com isso, o método informa aos seus chamadores sobre as exceções que 
ele pode levantar e estes métodos podem decidir de modo inteligente o que 
fazer com tais exceções. 
O trecho a seguir demonstra como ficariam os métodos metodo1, metodo2 e 
metodo3 manipulando exceções. Como pode ser visto, este código é mais 
compacto que na programação tradicional. 
 
Código 7-4: Propagação de exceções utilizando a cláusula throws. 
public void metodo1() { 
 try { chamada de metodo2; } 
 catch (exception) { trata erro; } 
} 
 
public void metodo2() throws exception { 
 chamada de metodo3; 
} 
 
public void metodo3() throws exception { 
 chamada de lePrimeiraLinhaArquivo; 
} 
 
Tratamento de Exceções 
 7-8 
3a Vantagem: Agrupar Tipos de Erros 
As exceções freqüentemente se enquadram em categorias ou grupos. Por 
exemplo, os erros que podem ocorrer na manipulação de um vetor (tais como 
índice fora do intervalo do tamanho do vetor e inserção de elemento de um tipo 
errado) podem ser facilmente imaginados como um grupo de exceções, cada 
exceção representando um dos tipos de erro. 
Do mesmo modo, os erros que podem ocorrer em operações de E/S (tais 
como tentar abrir um arquivo com nome inválido e interrupção da operação de 
E/S) são facilmente imaginados como um grupo de exceções. 
Além disso, é fácil imaginar que alguns métodos queiram fazer o tratamento 
das exceções que se enquadrem numa categoria (por exemplo, todas as 
exceções referentes a vetores), e outros métodos queiram manipular apenas 
exceções específicas (por exemplo, apenas a inserção de um elemento de tipo 
errado no vetor). 
Todas as exceções que são levantadas dentro de um programa Java são 
objetos first-class. Deste modo, o agrupamento de exceções é um resultado 
natural da hierarquia de classes. As exceções em Java devem ser instâncias de 
Throwable, ou qualquer descendente de Throwable. 
Assim como em outras classes, subclasses da classe Throwable podem ser 
criadas. Cada classe sem subclasses (folha) representa um tipo específico de 
exceção e cada classe com uma ou mais subclasses (nodo) representa um 
grupo de exceções. 
No esquema abaixo, IOException é uma subclasse de Exception (uma 
subclasse de Throwable) e possui duas subclasses: 
• FileNotFoundException 
• InterruptedIOException. 
A classe IOException é uma classe geral de exceções produzidas por falha 
ou interrupção de operações de E/S. As suas duas subclasses representam dois 
tipos de erro específicos que podem ocorrer em operações de E/S. 
 
Tratamento de Exceções 
 7-9 
 Figura 7-1: Hierarquia de classes para tratamento de arquivos. 
 
Um exemplo de manipulador de exceção que trata somente exceções 
geradas ao tentar abrir um arquivo com nome inválido 
(FileNotFoundException) é: 
 
Código 7-5: Bloco catch para tratamento de exceção específica. 
 
Um método pode também capturar uma exceção baseada em seu grupo 
ou tipo geral. Isto é feito especificando qualquer uma das superclasses de 
exceções no comando catch. Para capturar todas as exceções de E/S, 
independente do seu tipo, a manipulação de exceções poderia especificar o 
argumento IOException, como no exemplo abaixo. 
Esta manipulação iria capturar todas as exceções deste grupo. Para 
descobrir exatamente que tipo de exceção ocorreu, o parâmetro e poderia ser 
usado. 
Código 7-6: Bloco catch para tratamento de exceção de grupo (IOException). 
 
É possível também utilizar um manipulador de exceções que trate qualquer 
exceção: 
Código 7-7: Bloco catch para tratamento de qualquer exceção. 
 
Manipuladores de exceções que são muito genéricos, como o mostrado 
acima, podem tornar o código mais propenso a erros por capturar e tratar 
exceções que não foram previstas e que, portanto, não serão corretamente 
tratadas dentro do manipulador. 
Deste modo, manipuladores de exceções gerais não devem ser utilizados 
como uma regra. 
catch (FileNotFoundException e) { 
 tratamento da exceção 
} 
catch (IOException e) { 
 tratamento 
} 
catch (Exception e) { 
 tratamento 
} 
Tratamento de Exceções 
 7-10 
4a Vantagem: Exceções não são Ignoradas 
Após um método levantar uma exceção, ela não pode ser ignorada: ela 
precisa ser capturada e manipulada em algum local. 
Tratamento de Exceções 
 7-11 
Manipulando Exceções 
A classe Throwable é a superclasse de todos os erros e exceções na 
linguagem Java, possuindo duas subclasses: Error e Exception. 
 Figura 7-2: Hierarquia de erros Java. 
 
Subclasse Error 
Erros são extensões da classe Error, subclasse de Throwable. Subclasses de 
Error, diferente das subclasses de Exception, geralmente não devem ser 
capturadas, e geralmente causarão o término do programa. 
Exemplos deste tipo de erro são falta de memória durante a execução ou 
não estar apto a carregar uma classe. 
Exceções não verificadas (Unchecked Exceptions) 
Exceções não verificadas (exceções de execução) são extensões da classe 
RuntimeException. Estas exceções são aquelas que ocorrem dentro do 
ambiente de execução Java (JVM). Possíveis exemplos são exceções aritméticas 
(tal como divisão por zero), exceções de ponteiro (tal como tentar acessar um 
objeto utilizando uma referência nula) e exceções de indexação (tal como tentar 
acessar um elemento de um vetor utilizando um índice muito grande). 
As exceções de execução podem ocorrer em qualquer local do programa 
e o custo para testar se elas realmente ocorrerão é freqüentemente maior que o 
benefício de capturá-las. Assim, o compilador não requer que o programador 
capture estas exceções, embora isso seja possível. 
Porém, embora estas exceções não precisem ser capturadas, elas não 
podem ser ignoradas. Se uma exceção de execução ocorre e o código não as 
Tratamento de Exceções 
 7-12 
manipula, a máquina virtual irá terminar o programa e imprimir o nome da 
exceção e um rastro da pilha. 
Exceções Verificadas (Checked exceptions) 
Exceções verificadas são extensões da classe Exception. Estas exceções 
não são exceções de execução e são verificadas pelo compilador, que se 
certifica de que tais exceções serão capturadas e manipuladas em algum outro 
local no programa. Exceções criadas pelo programador devem estender a classe 
Exception. 
Tratamento de Exceções 
 7-13 
Tratando Exceções 
Quando um método utilizado pelo programa levantar uma exceção, o 
programador possui três opções: 
- Capturar a exceção e tratá-la; 
- Capturar a exceção e levantar uma exceção diferente, que será 
manipulada em outro local; 
- Deixar a exceção passar através do método; algum manipulador deve 
então capturá-la em outro local. 
Para identificar se um método em particular de uma classe padrão doJava 
pode levantar uma exceção, a documentação do JDK pode ser utilizada. Todas 
as classes padrão do Java são documentadas e uma parte da documentação 
de cada método é a lista das exceções que este método pode levantar. 
Por exemplo, na classe Integer, para o método parseInt (que transforma 
um argumento String em um número decimal com sinal): 
public static int parseInt(String s) throws NumberFormatException 
 
Tratamento de Exceções 
 7-14 
Manipulando Exceções 
O mecanismo para manipulação de exceções em Java é formado pelos 
comandos try/catch/finally. 
Para manipular uma exceção, o código deve ser organizado nos seguintes 
blocos: 
- Incluir as chamadas dos métodos que podem levantar exceções em um 
bloco try; 
- Inserir um ou mais blocos catch, onde cada um irá capturar uma 
exceção em particular; 
- Adicionar um bloco finally se desejado. O bloco finally é 
executado sempre, mesmo que nenhuma exceção tenha sido 
levantada. 
O exemplo a seguir demonstra a sintaxe para manipular três exceções 
(excecaoTipo1, excecaoTipo2 e excecaoTipo3) que poderiam ser levantadas 
por método chamado. 
 
Código 7-8: Tratamento de exceções utilizando os blocos try/catch/finally. 
 
try { 
 ... 
 chamada do método que pode levantar exceção 
 ... 
}catch (excecaoTipo1){ 
 trata excecaoTipo1 
}catch (excecaoTipo2){ 
 trata excecaoTipo2 
}catch (excecaoTipo3){ 
 trata excecaoTipo3 
}finally { 
 ... 
} 
Tratamento de Exceções 
 7-15 
O Bloco try 
O comando try delimita o bloco de código que contem as chamadas para 
os métodos que podem levantar exceções. Se uma exceção ocorre dentro de 
um bloco try, esta exceção é capturada pelo manipulador de exceções 
apropriado associado a este bloco try. 
O Bloco catch 
Um bloco try pode ser seguido por zero ou mais blocos catch, que 
especificam como tratar os vários tipos de exceções. Cada cláusula catch é 
declarada com um argumento, que deve ser do tipo Throwable ou uma 
subclasse deste. 
Quando uma exceção ocorre, o primeiro catch que possui o argumento do 
tipo apropriado é ativado. Este argumento deve ser o tipo da exceção do objeto 
ou uma superclasse da exceção, e é valido somente dentro do bloco catch. 
Não é necessário que haja um bloco catch para todas as exceções 
possíveis. Em alguns casos, o tratamento correto é permitir que a exceção seja 
propagada acima e possa ser capturada por outro método que esteja na pilha. 
O Bloco finally 
O bloco finally contém o código responsável pela finalização do método 
(tais como fechamento dos arquivos, liberação dos recursos) antes que o 
controle seja transferido para outra parte do programa. 
O código dentro deste bloco é sempre executado se uma porção do bloco 
try é executada, independente de como o código no bloco try é completado. 
Em um fluxo normal, o controle atinge o final do bloco try e passa então ao 
bloco finally que executa a finalização necessária. 
Se o controle deixa o bloco try pelo uso de um comando return ou break, 
o conteúdo do bloco finally é executado antes do controle ser transferido 
para o novo destino. 
Se uma exceção ocorre no bloco try e há um bloco catch local para 
manipular esta exceção, o controle é transferido para o bloco catch e 
posteriormente para o bloco finally. Se a exceção ocorre e não há um bloco 
catch para manipular a exceção, o controle é transferido para o bloco finally 
e então propagado para a cláusula catch mais próxima que manipula esta 
exceção. 
É possível existir um bloco finally sem um ou mais blocos catch anteriores. 
Contudo, um bloco try deve sempre existir antes do bloco finally. 
Tratamento de Exceções 
 7-16 
Manipulando Exceções: Exemplo Prático 
O código a seguir apresenta um exemplo de uma classe, converteNumero, 
onde são capturadas duas exceções: ArrayIndexOutOfBoundsException e 
NumberFormatException. Esta classe converte o argumento lido no formato 
String para um inteiro. 
Código 7-9: Exemplo de método utilizando tratamento de exceções. 
 
 
Observe o código acima e descreva o que é impresso na tela nas seguintes 
situações: 
1. A classe é chamada utilizando: C:\java ConverteNumero 38 
2. A classe é chamada utilizando: C:\java ConverteNumero palavra 
3. A classe é chamada utilizando: C:\java ConverteNumero 
 
 Imagine agora o exemplo acima sem o bloco catch que trata a exceção 
ArrayIndexOutOfBoundsException. O que aconteceria se a classe fosse 
chamada utilizando apenas converteNumero? 
 
public class ConverteNumero { 
 public static void main(String argv[]) { 
 int num; 
 try { 
 System.out.println("String lida: " + argv[0]); 
 num = Integer.parseInt(argv[0]); 
 System.out.println("Numero: " + num); 
 }catch (ArrayIndexOutOfBoundsException e) { 
 System.out.println("Não foi fornecido argumento."); 
 return; 
 }catch (NumberFormatException e) { 
 System.out.println("Não foi possível converter a string" + 
 "para inteiro. Verifique a string fornecida."); 
 }finally { 
 System.out.println("Bloco finally."); 
 } 
 System.out.println("Encerrando método"); 
 } 
} 
Tratamento de Exceções 
 7-17 
Propagando Exceções 
Quando uma exceção não pode ser tratada localmente ou se deseja que 
ela seja tratada em outro local, ela pode ser propagada para o código que 
chamou o método. 
Para propagar uma exceção para o método acima, a exceção deve ser 
indicada na declaração do método chamado. Isto é feito utilizando o comando 
throws. 
Código 7-10: Propagação de exceções utilizando a cláusula throws. 
 
Observe o exemplo abaixo. O método converteStringParaNumero não 
trata a exceção NumberFormatException localmente. Ao invés disso, a exceção 
passa automaticamente para o método que chamou 
converteStringParaNumero. 
O método que chamou converteStringParaNumero pode capturar a 
exceção NumberFormatException ou propagar a exceção para um método 
acima. Caso ele deseje propagar a exceção, ele deve também conter throws 
NumberFormatException em sua declaração. 
 
Código 7-11: Tratamento de exceções utilizando a cláusula throws para o contexto anterior. 
 
 
 
 
tipo metodo(parametros) throws excecaoTipo1 { 
... 
} 
private void converteStringNumero(String str) throws NumberFormatException { 
 int num; 
 try { 
System.out.println("String lida: " + str); 
 num = Integer.parseInt(str); 
 System.out.println("Numero: " + num); 
 }finally { 
 System.out.println("Bloco finally método converteStringNumero."); 
 } 
 System.out.println("Encerrando método converteStringNumero"); 
} 
Tratamento de Exceções 
 7-18 
Lançando Exceções 
O programador pode lançar exceções em seu código para indicar alguma 
condição anormal. Estas exceções podem ser exceções padrões do sistema ou 
exceções criadas pelo programador. 
Ao levantar uma exceção, o que está sendo feito na realidade é a criação 
de um objeto e a transmissão deste para um método superior. Assim, o objeto 
exceção deve ser criado usando o operador new. 
O exemplo a seguir apresenta um método que lança uma exceção do tipo 
ArrayIndexOutOfBoundsException se verificar que o índice não é válido. 
 
Código 7-12: Antecipando uma exceção e criando a exceção correspondente. 
 
private void testaArgumento(int indice, String vetor[]) throws 
 ArrayIndexOutOfBoundsException { 
 if (indice >= vetor.length) { 
 throw new ArrayIndexOutOfBoundsException(); 
 } 
} 
Tratamento de Exceções 
 7-19 
Criando Exceções 
Para criar as suas próprias exceções, o programador deve estender a classe 
Exception. A classe RuntimeException não deve ser estendida, pois esta classe 
é utilizada para exceções comuns quenão precisam ser verificadas. 
O exemplo a seguir cria uma exceção chamada 
ExcecaoArgumentoInvalido. Esta exceção possui um único construtor que 
apenas chama o construtor da superclasse. 
Código 7-13: Criando uma classe do tipo Exception. 
 
public class ExcecaoArgumentoInvalido extends Exception { 
 public ExcecaoArgumentoInvalido (String message) { 
 super(message); 
 } 
} 
Tratamento de Exceções 
 7-20 
Capturando Exceções e Levantando Exceções 
Diferentes 
Quando uma exceção é levantada, o método pode capturá-la e levantar 
uma exceção diferente para outros métodos. 
O trecho a seguir exemplifica esta situação. 
Neste método, a exceção ArrayIndexOutOfBounds é capturada e uma 
nova exceção do tipo ExcecaoArgumentoInvalido é criada. 
Código 7-14: Capturando exceções e lançando uma exceção diferente (exceção particular). 
public void testaArgumento(int indice, String strvet[]) throws 
 ExcecaoArgumentoInvalido { 
 try { 
 String str = strvet[indice]; 
 } 
 catch (ArrayIndexOutOfBoundsException e) { 
 throw new ExcecaoArgumentoInvalido("# elementos incorretos!"); 
 } 
} 
Tratamento de Exceções 
 7-21 
Espaço para anotações 
Tratamento de Exceções 
 7-22 
Exercícios 
 
 
1. Neste exercício você irá criar uma exceção personalizada para tratar 
erros de validação que podem ser então lançados quando estiver 
executando a aplicação e um valor incorreto for passado, por exemplo, 
para o método que atribui valores a um produto. 
 
Passo 1: Crie uma classe pública chamada ValidacaoException, esta 
classe deve ser criada em um arquivo fonte novo e deve extender a 
classe RuntimeException. 
 
Passo 2: Defina um método construtor nesta classe que possa receber 
uma String como parâmetro e repasse esta string para a classe pai. 
 
Passo 3: Nas operações de modificação do atributo preco da classe 
Produto bem como na operação que atribui um produto a um 
ItemPedido faça uso desta classe para se a validação der algum erro 
você lançar uma exceção com uma mensagem personalizada para 
quem chamou esta operação. 
 
 
Java Fundamentals 
 
T@rgetTrust Treinamento e Tecnologia 8-1 
88.. CCllaasssseess aabbssttrraattaass ee IInntteerrffaacceess 
 
 
 
 
 
 
 
 
 
Classes abstratas e interfaces 
 8-2 
Objetivos 
 
 
• Criar classes abstratas 
• Definir interfaces 
Classes abstratas e interfaces 
 8-3 
Abstração 
Em Java você pode definir classes que representem, na definição de um 
projeto, um nível mais alto de abstração. Ao usar estas classes o projetista terá 
uma visão melhor de como as subclasses devem se parecer e mesmo quais 
métodos são obrigatórios em todas as subclasses. 
 Figura 8-1: Definindo a classe Produto como abstrata para não ser instanciada. 
 
Classes Abstratas 
Uma classe abstrata é simplesmente uma classe que não pode ser 
instanciada. Somente suas subclasses podem ser instanciadas. Por exemplo, 
Produto não contém detalhes suficientes para fornecer algo útil para o negócio. 
Um item deve ser um CD ou um DVD. Produto serve, no entanto, como uma 
coleção de dados e comportamentos que são comuns a todos os itens 
disponíveis para alugar. 
Métodos Abstratos 
Métodos abstratos vão um passo além da herança padrão. Um método 
abstrato definido dentro de uma classe abstrata deve ser implementado pelas 
subclasses destas. Esta técnica permite que o projetista de classes decida 
exatamente quais comportamentos as subclasses devem ter. 
O projetista de uma classe abstrata não consegue determinar como estes 
comportamentos serão implementados, mas somente que eles serão 
implementados. 
Interfaces 
Interface é a especificação de um conjunto de métodos, similares a uma 
classe abstrata. Além do que uma classe abstrata pode oferecer, uma interface 
pode efetivamente permitir herança múltipla. 
Uma classe pode implementar um número ilimitado de interfaces, mas pode 
estender somente uma única superclasse. 
Classes abstratas e interfaces 
 8-4 
Definindo classes abstratas 
Java fornece a palavra reservada abstract que indica que uma classe é 
abstrata. Por exemplo, a classe Produto no exemplo abaixo foi declarada como 
sendo abstrata: 
 Figura 8-2: Definições das classes Produto, DVD e CD. Herança e Abstração da classe Produto. 
 
Produto é declarado como uma classe abstrata porque não possui 
informação ou comportamento suficientes para representar um objeto 
autônomo. 
O usuário não deveria ser capaz de criar objetos Produto, porque Produto 
é apenas uma classe parcial e intermediária. Produto existe somente para que 
possa ser estendida por classes mais especializadas, tais como CD ou DVD. 
O que acontece se você tentar instanciar uma classe abstrata? 
 
Código 8-1: Erro de compilação na criação de uma instância de uma classe abstrata. 
 
Se você tentar criar um objeto Produto em seu programa, o compilador 
acusará um erro. O usuário pode criar somente objetos de subclasses concretas: 
Código 8-2: Criação com sucesso de instâncias especializadas. 
 
O modificador abstract pode ser aplicado somente a classes e métodos. 
Classes abstratas provem um modo de adiar a implementação de métodos para 
Produto produto = new Produto(); // Erro de compilação 
CD cd = new CD(); // Herdando Produto 
DVD dvd = new DVD(); // Herdando Produto 
Classes abstratas e interfaces 
 8-5 
subclasses. Uma classe abstrata não pode ser instanciada, ou seja, não podemos 
chamar seus construtores. 
Classes abstratas e interfaces 
 8-6 
Métodos Abstratos 
Ao projetar uma hierarquia de classes, há provavelmente algumas 
operações que todas as classes deverão ter, cada qual de sua própria maneira. 
Por exemplo, em um negócio de aluguel de fitas, o vendendo deve saber se um 
item pode ser alugado ou não. 
Cada tipo de item, entretanto, determina se pode ser alugado de uma 
maneira específica. 
Para representar este conceito em Java, o método “este item pode ser 
importado” é definido na classe Produto. Entretanto, não há uma 
implementação sensata para este método em Produto, porque cada tipo de 
item tem suas próprias exigências. 
Uma abordagem, seria deixar o método vazio na classe Produto: 
Código 8-4: Definindo métodos concretaos em classes abstratas. 
 
Esta abordagem não é boa o suficiente porque não força cada uma das 
subclasses concretas a sobrescrever o método. Suponha, por exemplo, que a 
classe DVD se esqueça de sobrescrever o método isImportado(), o que 
aconteceria se o usuário chamasse este método a partir de uma referência para 
DVD? 
O método isImportado() definido em Produto seria chamado e retornaria 
true. Este não é o resultado desejado. A solução é declarar o método como 
abstrato, como mostrado logo a seguir. 
public abstract class Produto { 
 public boolean isImportado() { 
 return true; 
 } 
} 
Classes abstratas e interfaces 
 8-7 
Definindo métodos abstratos 
Para declarar um método abstrato em Java, você deve colocar antes do 
nome do método a palavra reservada abstract. Veja o exemplo: 
Código 8-5: Definindo métodos abstratos em classes abstratas. 
 
Ao declarar um método abstrato, você deve fornecer somente a assinatura 
do método, que compreende: o nome do método, a lista de parâmetros 
esperados e o tipo de retorno. Você não fornece um corpo para o método. 
Cada subclasse concreta deverá sobrescrever este método e fornecer o seu 
próprio corpo. 
Agora que o método é declarado abstrato, todas as subclasses devem 
fornecer uma implementação para ele. 
Subclasses abstratas podem conter métodos que não são declarados 
abstratos. Estes métodos podem ser sobrescritos pelas subclasses, mas isto não pé 
necessariamenteobrigatório. 
public abstract class Produto { 
 public abstract boolean isImportado(); 
} 
Classes abstratas e interfaces 
 8-8 
Interfaces 
Uma interface é similar a uma classe abstrata, exceto que ela não possui 
nenhum método concreto ou variáveis de instância. É apenas uma coleção de 
declarações de métodos abstratos e constantes  isto é, variáveis declaradas 
como static public final. 
Uma interface é como um contrato que a subclasse deve obedecer. 
Qualquer classe que implemente uma interface deve implementar todos os 
métodos especificados na interface. Uma classe pode implementar muitas 
interfaces, mas pode estender apenas uma única classe. Java não suporta 
herança múltipla, mas permite a implementação de múltiplas interfaces. 
Como já foi dito anteriormente, CD herda todos os atributos e 
comportamentos de Produto. Além disto, deve fornecer implementação para 
cada um dos métodos definidos em cada interface que implementar. 
Estes métodos podem ser usados por outras classes para implementar 
comportamentos específicos como, por exemplo, uma rotina de ordenamento. 
Classes abstratas e interfaces 
 8-9 
Exemplos de interfaces 
Interfaces descrevem um aspecto de comportamento que muitas classes 
possuem. O nome de uma interface é geralmente um comportamento como: 
Compra, Venda, etc. Difere, portanto, do nome de uma classe, que é usualmente 
um substantivo, como cliente ou produto. 
A interface java.sql.Connection possui os métodos a seguir: 
- void commit() 
- void rollback() 
- void close() 
- void clearWarnings() 
- Statement createStatement() 
- void setAutoCommit(boolean) 
- boolean isClosed() 
 
Qualquer classe que precise trabalhar com conexão de bando de dados 
pode implementar a interface Connection. 
As classes que implementam uma interface podem ser completamente 
distintas e não ter uma nada a ver com as demais. 
A única coisa que devem ter necessariamente em comum é a necessidade 
de todas serem móveis. 
Classes abstratas e interfaces 
 8-10 
Definindo Interfaces 
 
Você pode definir uma interface usando a palavra reservada interface. 
Todos os métodos especificados em uma interface são implicitamente públicos e 
abstratos (public e abstract). Quaisquer variáveis definidas em uma interface 
são implicitamente públicas, estáticas e constantes (public, static e final). 
Código 8-6: A interface Conncetion do pacote java.sql. 
 
Portanto, a definição acima equivaleria à seguinte definição: 
Código 8-7: A interface Conncetion do pacote java.sql equivalente. 
 
Porque os métodos de interface são implicitamente públicos e abstratos é 
prática geralmente aceita não especificar estes modificadores de acesso. O 
mesmo é verdade para variáveis. 
Como são implicitamente públicas, estáticas e finais, geralmente estes 
modificadores não são especificados. Cada interface pode ser representada em 
um arquivo Java separado com o nome da interface. (neste caso poderíamos 
criar um arquivo chamado Connection.java do pacote java.sql) 
public interface Connection { 
 public void commit(); 
 public void rollback(); 
 public void close(); 
 public void clearWarnings(); 
 public Statement createStatement(); 
 public void setAutoCommit(boolean b); 
 public boolean isClosed(); 
 
 // entre outros métodos ... 
} 
public interface Connection { 
 public abstract void commit(); 
 public abstract void rollback(); 
 public abstract void close(); 
 public abstract void clearWarnings(); 
 public abstract Statement createStatement(); 
 public abstract void setAutoCommit(boolean b); 
 public abstract boolean isClosed(); 
 
 // entre outros métodos ... 
} 
Classes abstratas e interfaces 
 8-11 
Implementando Interfaces 
O exemplo abaixo mostra o exemplo da classe OracleConn que implementa 
a interface Conncetion. OracleConn deve implementar todos os métodos de 
todas as interfaces que ele declare implementar (interfaces presentes na cláusula 
implements). 
Neste caso, OracleConn deve implementar os métodos contidos na 
interface Connection. 
Código 8-8: A classe OracleConn deve implementar TODOS os métodos da interface Conncetion. 
 
Uma classe pode implementar mais de uma interface se ela desejar, 
bastando para tal especificar uma lista de interfaces separadas por vírgula. 
Considere o seguinte exemplo: 
Código 8-9: A classe Aplicacao pode implementar mais de uma interface. 
 
Aqui, Aplicacao implementa duas interfaces: InterfaceI e InterfaceII. 
Isto significa que a classe Aplicacao deve implementar todos os métodos 
declarados em InterfaceI e InterfaceII. A classe Aplicacao terá o 
comportamento definido nas duas interfaces. 
public class OracleConn implements Connection { 
 
 public void commit() { 
 //... código 
 } 
 
 public void rollback() { 
 //... código 
 } 
 
} 
public class Aplicacao extends JFrame implements InterfaceI, InterfaceII { 
 
} 
Classes abstratas e interfaces 
 8-12 
Espaço para anotações 
Classes abstratas e interfaces 
 8-13 
Exercícios 
 
 
 1. Crie uma interface para representar uma fila de impressão 
 
 Passo 1: Declare uma interface em um arquivo novo com os seguintes 
comportamentos: 
 
 boolean imprimir() 
 void parar() 
 boolean remover(Documento doc) 
 void refresh() 
 void pausa() 
 
 Passo 2: Crie uma classe para implementar esta fila de impressão e 
codifique as operações nela 
 
 
 
 2. Trabalhando com classes abstratas 
 
 Passo 1: Torne a classe Produto abstrata adicionando a palavra reservada 
abstract na assinatura da classe. 
 
 Passo 2: Tente criar um objeto desta classe agora. É possível? 
 
 Passo 3: Transforme a operação que retorna o preço abstrata uma vez que 
a forma de calcular o preço irá depender de cada uma das subclasses.

Mais conteúdos dessa disciplina