Buscar

289S TOP ESP PROGR ORIENT OBJETOS

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 78 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 78 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 78 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

289S - TOP ESP PROGR ORIENT OBJETOS 
Introdução ao Java 
Um breve histórico 
A Sun Microssystems, em 1991, financiou um projeto de pesquisa corporativa interna 
com o codinome Green, que resultou no desenvolvimento de uma linguagem baseada 
em C++ que seu criador, James Gosling, chamou de Oak. Descobriu-se mais tarde que 
já havia uma linguagem de programação com este nome. Uma equipe da Sun, em uma 
visita a uma cafeteria local que servia café cuja origem era da ilha de Java na 
Indonésia sugeriu este nome e ele acabou pegando. 
O projeto passou por dificuldades e quase foi cancelado. Mas em 1993 a World Wide 
Web explodiu em popularidade e a equipe da Sun viu um grande potencial para utilizar 
o Java par adicionar conteúdo dinâmico, como interatividade e animações, às páginas 
da Web, o que deu nova vida ao projeto. 
O Java foi anunciado formalmente em 1995, ganhando muito interesse da comunidade 
do World Wide Web. Hoje o Java é popular no desenvolvimento de software para 
diversos aplicativos, como aplicativos corporativos de grande porte, aplicativos 
governamentais, no aprimoramento da funcionalidade de servidores Web assim como 
aplicativos para o consumo popular em microcomputadores pessoais e dispositivos 
móveis. 
Arquitetura de um programa em Java 
Um dos aspectos mais marcantes do Java e que esteve presente desde sua 
concepção é o fato desta linguagem ser ​multiplataforma​. Plataforma é o conjunto 
formado por um computador e o sistema operacional instalado neste computador. 
Podemos, então, ter as seguintes plataformas como exemplo: 
• Computador padrão PC-Intel executando Windows; 
• Computador padrão PC-Intel executando Linux; 
• Computador padrão iMac executando Mac OS; 
• Computador padrão workstation executando Solaris; 
• etc. 
Dizer que o Java é multiplataforma significa dizer que um programa feito em Java e 
compilado em uma determinada plataforma, poderá ser executado nesta plataforma ​e 
também em todas as demais plataformas​ que dão suporte ao Java. 
Diversas linguagens, como o C++ por exemplo, estão disponíveis para diversas 
plataformas. Entretanto, um código escrito em C++ que seja compilado em uma 
determinada plataforma só poderá ser executado nesta mesma plataforma. Para que o 
código seja executado em uma outra plataforma, ele deverá ser compilado novamente, 
mas dessa vez na plataforma em que se deseja executar o código. 
Mas como é possível que um programa compilado em Java em uma determinada 
plataforma possa ser executado em outras plataformas? 
Um computador só consegue executar programas que estejam escritos em linguagem 
de máquina. Quando um programa é escrito em uma linguagem de alto nível, o código 
deste programa deve ser compilado (traduzido) para a linguagem de máquina da 
plataforma que irá executar o programa. 
O Java realiza esta façanha porque ele não é compilado diretamente para a linguagem 
de máquina de uma plataforma específica. Em vez disso, ele é compilado para uma 
linguagem de máquina de um computador fictício, uma ​máquina virtual​. Para que o 
programa possa ser então executado, um computador deve utilizar um emulador deste 
computador fictício, que então, ​interpreta​ o código compilado Java. Em outras 
palavras: Um programa em Java é ​semi-compilado​, o que significa que o código fonte 
é compilado para uma linguagem intermediária, conhecida como ​bytecode​. Este 
bytecode ​é um código de computador escrito em linguagem de máquina da ​Máquina 
Virtual Java​ (Java Virtual Machine – JVM). A Máquina Virtual Java, então, interpreta o 
bytecode e executa o programa. 
 
Com esta estrutura, um programa compilado em Java pode ser executado diretamente 
em qualquer sistema que possua uma Máquina Virtual Java disponível. 
O que é necessário para se programar em Java 
O Java é disponibilizado por seu atual desenvolvedor, a Oracle, em diversas 
distribuições. Algumas delas são: 
• Java Standard Edition (Java SE); 
• Java Enterprise Edition (Java EE); 
• Java Micro Edition (Java ME); 
• Java Card; 
• Java TV; 
• etc. 
A mais importante distribuição é o Java SE (Java Edição Padrão). É nesta distribuição 
que estão as bibliotecas básicas do Java e as principais ferramentas de 
desenvolvimento, como o compilador Java. 
As demais distribuições são complementos ao Java SE que disponibilizam outras 
capacidades à linguagem. Por exemplo, o Java EE (Java Edição Corporativa) inclui 
bibliotecas e servidores capazes de permitir a criação e operação de sistemas 
corporativos distribuídos, o uso de persistência automatizada e a criação de páginas 
dinâmicas de Internet entre outras funcionalidades. O Java ME (Java Edição Micro) 
oferece a base para a programação de dispositivos móveis, como celulares, PDAs, 
receptores de TV, TVs inteligentes, etc. No caso de dispositivos como TVs, DVDs e 
Blu-Rays, há uma distribuição específica, o Java TV, que é uma especialização do 
Java ME para estas aplicações particulares. 
Para se desenvolver em qualquer tecnologia Java, a única distribuição obrigatória é o 
Java SE. Este kit de desenvolvimento (SDK – Software Development Kit) é a única 
distribuição que contém o compilador Java. Qualquer outra distribuição é um acessório 
que deve ser instalado junto ao SDK Java SE. 
Tendo o SDK Java SE (também conhecido como JDK – Java Development Kit) 
instalado, já é possível escrever programas usando algum editor de arquivos texto e 
usando o compilador Java por meio de linha de comando. 
O SDK Java SE pode ser obtido da página de seu desenvolvedor: 
Java SE. Disponível em 
http://www.oracle.com/technetwork/java/javase/overview/index.html 
Apesar do SDK Java SE ser suficiente para se programar em Java, a maioria dos 
estudantes e programadores admitem que o uso de um Ambiente Integrado de 
Desenvolvimento (IDE – Integrated Development Environment) torna o trabalho do 
desenvolvedor mais fácil. Um IDE é um sistema que reúne em um único pacote 
diversas ferramentas como: 
• Editor de código fonte; 
• Gerenciador de arquivos; 
• Corretor de sintaxe; 
• Ferramenta de automação de compilação; 
• Ferramenta de automação de depuração; 
• etc. 
Assim, mesmo sendo um opcional, vamos adotar uma IDE para desenvolver os 
exemplos deste livro-texto. Existem diversas IDEs disponíveis, tanto de código aberto 
quanto de código proprietário. Várias delas podem ser utilizadas, mas para não 
gastarmos tempo discutindo as diferenças entre elas, vamos utilizar o Eclipse 
(​http://www.eclipse.org​). 
O Eclipse não é o único IDE de código aberto de grande popularidade. Outro IDE 
bastante conhecido é o NetBeans (​https://netbeans.org​), mantido principalmente pela 
Oracle, mesmo desenvolvedor do Java. Há algumas diferenças entre ambos, mas não 
é possível dizer se um é melhor do que o outro. O que pode ser dito é que ambos são 
equivalentes, ou seja, tudo o que é feito com um pode ser feito com o outro. 
 
Programando em Java 
Vamos criar nosso primeiro programa, o famoso Olá mundo! Comece iniciando o 
Eclipse. Caso nunca o tenha iniciado antes, ele deve apresentar uma página de boas 
vindas semelhante à da seguinte figura: 
 
 
 
Esta janela pede para que você indique qual é a pasta que deseja utilizar para guardar 
os seus projetos Java. Utilize o local padrão ou indique o local que deseja utilizar. Se 
marcar a check box, o Eclipse não irá mais fazer esta pergunta ao inciciá-lo. 
A seguir, o Eclipse inicia. De novo, caso seja a primeira vez que o esteja executando, 
ele deve apresentar uma tela de boas vindas como vista na figura a seguir. 
 
Clique no ícone Workbench para exibir a área de trabalho. 
 
 
Vamos criar um projeto. Clique no menu File → New → Java Project. O seguinte 
assistente surge: 
 
Na caixa de texto Project name digiteo nome do seu projeto, “Ola mundo”. 
Certifique-se de que na área JRE você esteja usando alguma máquina virtual Java SE. 
Se por algum motivo a JRE padrão em seu computador não for um Java SE, selecione 
o primeiro botão de rádio e escolha uma versão J2SE ou Java SE (qualquer versão 
destas deve ser suficiente). 
Em qualquer linguagem de programação, sempre é recomendado não utilizar 
caracteres acentuados ou especiais. Ainda é possível (mesmo que incomum) que haja 
problemas tanto na compilação quanto na execução de códigos que utilizem tais 
símbolos. A única exceção é quando escrevemos algum texto em um String, por 
exemplo. Se desejamos escrever a mensagem “Olá mundo!” na tela, podemos usar 
acentos e caracteres especiais. 
 
 
As demais opções não precisam ser modificadas. Você já pode clicar no botão Finish. 
Neste momento, o Eclipse criou uma pasta chamada “Ola mundo” na pasta que você 
indicou como pasta de trabalho. Dentro dela serão armazenados seus códigos-fonte, 
classes compiladas, arquivos de configuração entre outros. Note que no Package 
Explorer (Explorador de Pacotes) agora há o seu projeto “Ola mundo”. Clique no sinal à 
esquerda do projeto para expandir sua estrutura interna. 
 
 
Agora vamos criar o arquivo onde será escrito o código-fonte do programa. Note que 
dentro do projeto “Ola mundo” há uma pasta chamada src. Ela é uma abreviação de 
source (fonte) e é nela que iremos colocar todos os códigos fonte de um projeto. Com o 
botão direito do mouse, clique na pasta src e selecione new → package. Package 
(pacote) é um conceito da orientação a objetos que permite que o desenvolvedor 
agrupe suas classes em pacotes. Os conceitos de classe e pacote serão vistos em 
maiores detalhes mais adiante. 
 
 
Na caixa para definir o nome do pacote, digite “primeiroPrograma”. Note que em Java, 
nomes devem ser compostos de apenas uma palavra. Clique em Finish. 
Em linguagens que derivam do C, como o C++, C# e Java, os nomes de classes, 
variáveis, métodos, atributos e demais elementos devem ter como nome um termo 
composto de uma única palavra. 
Recomenda-se que os nomes sejam sempre mnemônicos, ou seja, o próprio nome 
deve indicar qual é a natureza ou finalidade do elemento que ele batiza. Por exemplo, 
uma variável não mnemônica chamada “xpto12” não dá nenhuma indicação ao 
programador de sua finalidade. Já se ela for chamada de “contadorDeIterações”, sua 
finalidade torna-se evidente. Quando utiliza-se mais de uma palavra como nome, 
recomenda-se que a primeira letra de cada palavra, a partir da segunda palavra seja 
escrita em maiúscula. Esta notação é conhecida como camel case. Em Java, 
recomenda-se que a primeira letra da primeira palavra seja maiúscula se o nome for de 
uma classe ou de uma interface. Ela deve ser minúscula para os demais casos. A 
exceção à notação camel case ocorre quando criamos o nome de uma constante. 
Neste caso, recomenda-se que o nome seja escrito com todas as letras maiúsculas, 
utilizando o símbolo do sublinhado para separar as palavras. Por exemplo, os 
seguintes nomes são apropriados para constantes: NOTA_MINIMA, 
TAXA_MINIMA_DE_CRESCIMENTO, PI, CONSTANTE_GRAVITACIONAL. 
Dentro do pacote “primeiroPrograma” vamos criar a classe “OlaMundo”. Clique com o 
botão direito no pacote e selecione new → Class. 
 
 
Na caixa para definir o nome da classe, digite o nome “OlaMundo”. Clique em Finish. 
Neste momento, o Eclipse cria o arquivo OlaMundo.java e o exibe no editor. Já há um 
pouco de código escrito no arquivo, a declaração do pacote e da classe. A seguir, 
basta escrever o código do método principal main() como mostrado a seguir: 
 
 
A seguir, para compilar e executar seu programa, clique no botão indicado pela 
primeira seta (ou selecione o menu run → run). O Eclipse irá executar o compilador 
Java sobre seu código e executar o programa compilado. A saída do console é exibida 
na aba destacada pela segunda seta. 
Caso a janela para o seu código esteja pequena demais, você pode dar um duplo 
clique na aba da janela, o que faz com que ela seja maximizada. Para voltar à 
visualização anterior, basta dar um duplo clique na aba novamente. 
As abas também podem ser fechadas definitivamente, clicando no símbolo “X”. Caso 
você tenha fechado acidentalmente uma aba e não saiba como fazer com que ela seja 
reapresentada, você pode pedir ao Eclipse para restaurar a configuração padrão das 
janelas. Para tanto, chame o menu Window → Perspective → Reset Perspective... e 
responda Yes quando lhe for perguntado se quer realmente retornar as janelas para a 
configuração padrão. 
 
Entrada e saída de dados usando JOptionPane 
No exemplo anterior, utilizamos um método para criar uma saída de texto no console. 
Também é possível receber dados do usuário pelo console. Mas para tornar este 
livro-texto mais enxuto, vamos deixar de lado esta forma de interação homem-máquina 
e priorizar o uso de interfaces gráficas. 
 
O Java nos oferece uma ferramenta pronta para criar caixas de diálogo. As caixas de 
diálogo são um tipo especial de janela em ambiente gráfico. Elas servem para 
apresentar informações e também para receber dados do usuário. Estas 
funcionalidades estão disponíveis na classe JOptionPane que está definida no pacote 
javax.swing, como ilustrado na figura a seguir. 
 
 
Na figura acima, a classe JOptionPane é representada em um diagrama de classes, 
tendo seus atributos omitidos e apenas dois de seus métodos representados. A classe 
está definida no pacote swing que por sua vez está definido no pacote javax. 
A UML (Unified Modeling Language – Linguagem Unificada de Modelagem) define 
diversos diagramas úteis para a documentação, modelagem, análise e projeto de 
sistemas orientados a objetos. O diagrama de classes, um dos mais importantes da 
UML, representa as classes de um sistema em um retângulo dividido em três partes. 
Na primeira é anotado o nome da classe, na segunda seus atributos e na terceira seus 
métodos. 
O método showMessageDialog() permite a exibição de uma caixa de diálogo onde uma 
informação é exibida para o usuário. A sobrecarga mais simples deste método é: 
 
 
Este método requer dois parâmetros: o primeiro, chamado pai, recebe um objeto que 
representa o elemento gráfico pai da caixa de mensagem. Este pai costuma ser uma 
janela do aplicativo. Entretanto, ainda não sabemos como criar qualquer elemento 
gráfico, por isso, vamos utilizar a palavra reservada null para indicar que a caixa de 
diálogo não irá possuir qualquer componente gráfico como pai. Isto também fará com 
que a caixa de diálogo seja apresentada centralizada na tela. A palavra reservada null 
indica um objeto que não foi instanciado, um objeto nulo. O segundo parâmetro é a 
mensagem que será apresentada dentro da caixa de diálogo. 
Assim, em um programa, poderíamos utilizar o método showMessageDialog() da 
seguinte forma e obter o resultado exibido abaixo: 
 
O método showInputDialog() permite criar uma caixa de diálogo que apresenta uma 
pergunta e exibe um espaço para que o usuário digite sua resposta. Quando o método 
é encerrado, ele retorna um String contendo o texto digitado pelo usuário. A declaração 
de sua sobrecarga mais simples é: 
 
Note que o método showInputDialog() não requer a indicação de um componente pai. 
Entretanto, se você desejar, pode indicar um, mesmo que seja null. O trecho de código 
abaixo mostra como podemos usar este método para receber um texto do usuário. O 
texto digitado pelo usuário é armazenado na variável resposta: 
 
No exemplo abaixo, mostramos um programa inteiro que utiliza a classe JOptionPane 
para realizar entrada e saída de dados usando as caixas de diálogo. Note que, para se 
utilizar esta classe, é necessário importar a classe para que o programa possa 
utilizá-la. Isto é feito coma palavra reservada import, que deve ser inserida logo abaixo 
da palavra package. 
 
 
Assumindo-se que, ao executar o programa acima, o usuário digite o nome Maria, ele 
irá obter as seguintes mensagens: 
 
 
 
Recomendações de estilo 
Podemos dar nomes a diversos elementos de nossos programas, como variáveis, 
atributos, métodos, parâmetros, etc. Em Java e em linguagens orientadas a objeto em 
geral, recomenda-se o uso de nomes mnemônicos, ou seja, nomes que já indicam qual 
é a finalidade do elemento que ele batiza. Por exemplo, pode ser difícil saber qual é a 
finalidade de uma variável chamada xpto12. Por outro lado, se a mesma variável 
receber o nome contadorDeIteracoes, sua finalidade torna-se bastante clara. 
Para que se criem nomes mnemônicos, muitas vezes, como no exemplo anterior, 
desejamos usar mais de uma palavra. Mas um nome deve ser uma única palavra, sem 
espaços. A recomendação, neste caso, é escrever todas as palavras juntas, sem 
espaço. Para se marcar a separação entre as palavras, a partir da segunda palavra, a 
primeira letra deve ser grafada com letra maiúscula. Esta notação é conhecida como 
camel case. Exemplo: 
• contadorDeIteracoes; 
• respostaDoUsuario; 
• mediaFinal. 
O Java recomenda que a primeira letra do nome seja maiúscula caso o nome seja de 
uma classe ou de uma interface. Exemplos: 
• OlaMundo 
• ProgramaPrincipal 
• String 
Não confunda interface com interface gráfica. A interface gráfica é um recurso de 
entrada e saída de dados utilizando elementos gráficos e dispositivos de interação 
humana, como mouse e teclado. Já a interface é um conceito de orientação a objetos 
que será abordado mais adiante, mas que você já pode estar familiarizado caso já 
tenha estudado Análise Orientada a Objetos. Uma interface pode ser entendida, 
resumidamente, como uma classe sem atributos e que apenas declara as assinaturas 
dos métodos, sem implementar qualquer um deles. 
A exceção ao camel case está na declaração de nomes de constantes. Constantes são 
atributos cujo valor não pode ser alterado. O Java recomenda que constantes sejam 
escritas com todas as letras maiúsculas, separando as palavras pelo símbolo do 
sublinhado. Exemplos: 
• NOTA_MINIMA; 
• TAMANHO_PADRAO; 
• PI 
• CONSTANTE_GRAVITACIONAL; 
Tipos primitivos 
Tipos são a natureza dos dados que podem ser armazenados em uma variável, um 
atributo, que podem ser transferidos por um parâmetro ou retorno de método. Tipo 
primitivo é o tipo de dado que está definido na própria linguagem Java. Por isso, esses 
tipos têm um excelente desempenho tanto em economia de memória quanto em 
desempenho de processamento. Estes tipos são: 
Tipo Tamanho em 
bits 
Natureza Valores 
booleanDepende da JVM 
de cada 
plataforma 
Booleanos true ou false 
char 16 Caractere 
alfanumérico 
‘\u0000’ a ‘\uffff’ (0 a 65535) 
byte 8 Número 
inteiro 
-128 a 127 
short 16 Número 
inteiro 
-32.768 a 32.767 
int 32 Número 
inteiro 
-2.147.483.648 a 
2.147.483.647 
long 64 Número 
inteiro 
-9223372036854775808 a 
9223372036854775807 
float 32 Número em 
ponto 
flutuante 
Intervalo negativo: 
-3,4028234663852886E+38 
a 
-1,40129846432481707e-45 
Intervalo positivo: 
1,40129846432481707e-45 a 
3,4028234663852886E+38 
double 64 Número em 
ponto 
flutuante 
Intervalo negativo: 
-1,7976931348623157E+308 
a 
-4,94065645841246544e-324 
Intervalo positivo: 
4,94065645841246544e-324 
a 
1,7976931348623157E+308 
Na figura a seguir, criamos algumas variáveis e atribuímos a elas valores definidos por 
literais, ou seja, valores definidos no próprio código fonte: 
 
 
Quando se define um literal numérico inteiro, ele é tratado como sendo um inteiro. Já 
quando se define um literal numérico com um ponto decimal, ele é tratado como um 
double. Para se definir um literal caractere, ele deve ser circundado por aspas simples. 
Um literal booleano só pode assumir os valores representados pelas palavras 
reservadas true ou false. 
Quando se deseja definir um literal inteiro maior do que a capacidade de representação 
do int, deve-se indicar que o literal é um long, adicionando-se o sufixo L ou l. 
Analogamente, ao se representar um literal como um float, deve-se adicionar o sufixo F 
ou f: 
 
Conversão de tipos 
Quando se trabalha com mais de um tipo primitivo, podemos atribuir o valor 
armazenado em uma variável de tipo de menor capacidade em uma variável de maior 
capacidade. De uma certa forma, podemos entender que um tipo menor “cabe” dentro 
de um tipo maior. 
 
 
Desta forma, o seguinte método, se executado, irá gerar a mensagem representada na 
Figura 25. 
 
Na linha 10 é declarado o método atribuicoesSemCast(), o qual realiza o exemplo. Na 
linha 11 é declarada a variável b do tipo byte com o valor 8. Da linha 12 até a linha 16, 
o valor da variável b é transferido sucessivamente para variáveis de maior capacidade. 
Na linha 18 é declarada uma variável do tipo String chamada valores. A esta variável é 
atribuído o retorno do método format() da classe String. O método format() recebe pelo 
menos dois parâmetros. O primeiro é um String de formatação. Este String é composto 
de caracteres que são simplesmente retornados, como “b = “ e parâmetros de 
formatação que são compostos de um sinal % e uma letra. Esta letra indica se o 
parâmetros será substituído por um número decimal (d) ou um número de ponto 
flutuante (f). A seguir, o método format() recebe os valores que serão inseridos nos 
parâmetros do String de formatação. As sequências “\n” indicam que será inserido no 
String uma quebra de linha. Por fim, para que o código não fique demasiadamente 
largo, pode-se quebrar uma linha no meio do String. Para tanto, ele deve ser encerrado 
na primeira linha fechando as aspas e, na linha seguinte, deve ser concatenado com o 
segundo String usando o operador +. 
 
 
Já para se fazer as atribuições na direção oposta é necessário realizar um cast, ou 
conversão de tipo. Um cast é representado pelo tipo de destino entre parênteses antes 
do valor a ser convertido. O programa da Figura 24 foi alterado para realizar atribuições 
de variáveis de maior capacidade a variáveis de menor capacidade. 
 
 
Na figura acima está representado o mesmo programa Atribuicoes. Repare que na 
linha 11 há um sinal + e a próxima linha é a 24. Este sinal indica que a implementação 
do método atribuicoesSemCast() foi ocultada. Este recurso está disponível no Eclipse 
(e em praticamente qualquer IDE moderna). Para se exibir novamente o código oculto, 
basta clicar no sinal +. Para se ocultar um trecho de código, clica-se no sinal -. A outra 
modificação está no método main(), que agora chama também o método 
atribuicoesComCast(). 
Na linha 26 é declarada uma variável double com um valor em ponto flutuante. Nas 
linhas 27 a 31, este valor é convertido sucessivamente em tipos cada vez de menor 
capacidade. O resultado pode ser visto na figura a seguir. 
 
 
Note como os valores, ao serem convertidos para tipos de menor capacidade, foram 
perdendo precisão, como se estivessem sendo corrompidos. Isto ocorre porque o cast 
não faz arredondamento, ele faz truncamento em binário. Isso significa que, quando um 
número é convertido para um tipo de capacidade menor em bits, apenas os bits menos 
significativos são mantidos. Os bits excedentes do número são desprezados, o que 
causa a perda de informação. 
A partir de agora, os exemplos apresentados neste livro-texto não serão mais 
programas inteiros. Para poupar espaço, os exemplos serão apresentados como 
métodos que podem simplesmente ser inseridos em um programa qualquer que você 
já tenha criado. Basta chamar o método a partir do seu método main(). 
Classes wrapper (invólucro) 
Cada tipo primitivopossui uma classe wrapper associada. Uma classe wrapper pode 
ser utilizada para instanciar um objeto que armazena um valor do tipo primitivo 
associado a ela. Além disso, estas classes apresentam diversos métodos para se fazer 
a conversão de e para diversos tipos. As classes wrapper são: 
Tipo primitivo Classe wrapper 
boolean Boolean 
char Character 
byte Byte 
short Short 
int Integer 
long Long 
float Float 
double Double 
Estas classes podem ser utilizadas para se instanciar objetos com um valor do tipo 
primitivo associado a elas: 
 
 
A partir do Java 5 (Java versão 1.5), o valor de uma variável de tipo primitivo pode ser 
atribuído diretamente a um objeto de sua classe wrapper associada e vice-versa. Este 
recurso é chamado de autoboxing: 
 
 
As classes wrapper oferecem métodos parse que são úteis para se converter um String 
em um valor de tipo primitivo associado. Cada classe wrapper possui um método 
parse: 
 
 
As classes wrapper numéricas (todas exceto Boolean e Character) possuem métodos 
value para converter o valor armazenado no objeto para outros tipos primitivos 
numéricos. Desta vez, a conversão é feita com arredondamento, não mais com 
truncamento como o que ocorre quando se utiliza um cast. O exemplo a seguir utiliza 
os métodos value para converter de um objeto Integer para diversos outros tipos, mas 
o mesmo pode ser feito com qualquer outro wrapper numérico. 
 
 
Repare que na primeira linha, foi usado um construtor da classe Integer que recebe um 
String e não um int. Todas as classes wrapper possuem um construtor que recebe um 
String. Este construtor faz a conversão apropriada (usando um método parse 
adequado) antes de terminar a instanciação do objeto. 
Veja o programa a seguir que utiliza uma classe wrapper para receber dois números do 
usuário e, a seguir, realizar um cálculo matemático: 
 
 
 
 
 
Orientação a Objetos 
Uma das diferenças mais óbvias entre uma linguagem estruturada e uma linguagem 
orientada a objetos são justamente as classes e objetos. Pode-se entender, de maneira 
bastante simplificada, que uma classe é um trecho de código de computador que 
modela algum conceito útil para o sistema que se está desenvolvendo. Este conceito 
pode ser algo tangível, como um cliente, um funcionário, um produto, uma venda, mas 
também pode ser um conceito mais abstrato, como um conjunto de ferramentas de 
cálculo ou um conjunto de funcionalidades de acesso a banco de dados. 
Quando se faz a análise de um sistema, deve-se modelar classes que encapsulem, 
isolem, coloquem uma “cápsula” em torno deste conceito. Para tanto, deve-se ter em 
mente as seguintes regras para um bom projeto de classe: 
• Uma classe deve modelar apenas um conceito; 
• Uma classe não deve modelar qualquer aspecto de outro conceito; 
• Não deve haver em nenhuma outra parte do sistema qualquer aspecto do conceito 
modelado pela classe. 
Uma classe modela um determinado conceito reunindo em um único elemento os 
dados que definem este conceito e os comportamentos que este conceito pode 
apresentar. Uma boa maneira de se representar classes é usando o Diagrama de 
Classes da UML (Linguagem Unificada de Modelagem em inglês). Neste diagrama, 
uma classe é representada com um retângulo dividido em três partes. Na primeira parte 
é registrado o nome da classe. Na segunda, os atributos da classe que armazenam os 
dados da classe. Na terceira parte, os métodos da classe que implementam os 
comportamentos da classe. 
 
 
A figura acima registra uma classe em UML. Esta classe tem o nome Pessoa, possui 
dois atributos: nome e telefone. O primeiro atributo armazena dados do tipo String 
enquanto que o segundo armazena dados do tipo int. A classe também apresenta o 
método apresente() que será usado para exibir as informações armazenadas nos 
atributos. Este método não recebe parâmetros, pois não há nenhum parâmetro 
representado entre os parêntesis. Ele também não devolve nenhum valor, pois seu tipo 
de retorno é void. Esta classe pode ser codificada em Java da seguinte maneira: 
 
Nas linhas 7 e 8 estão declarados os atributos nome e telefone. Eles são declarados 
como se fossem variáveis, mas são atributos por não estarem dentro de qualquer 
método. Suas declarações são precedidas pela palavra reservada public, representada 
pelo sinal + no diagrama UML da Figura 34. Esta palavra reservada indica que estes 
atributos podem ser acessados por qualquer parte do sistema que tenha acesso à 
classe Pessoa. Na linha 10 é declarado o método apresente() que imprime em uma 
caixa de diálogo os dados armazenados nos atributos. 
Os modificadores de acesso serão abordados em maiores detalhes mais adiante neste 
livro-texto. 
Uma classe é uma definição de um conceito, como o simples cadastro de uma pessoa 
apresentado no exemplo acima. Mas um programa não pode utilizar esta definição 
diretamente, ele precisa instanciar esta classe em um objeto. Imagine que uma classe 
seja uma receita de bolo. Com esta receita pode-se preparar vários bolos e todos 
acabarão sendo mais ou menos parecidos. Desta mesma forma, uma classe é usada 
para se instanciar vários objetos. É o objeto que realmente possui os dados e os 
comportamentos modelados. O programa abaixo instancia um objeto da classe 
Pessoa, atribui valores aos seus atributos e chama o método apresente(). O resultado 
de sua execução também é apresentado: 
 
 
 
Na linha 7 é criada uma variável chamada p cujo tipo é Pessoa. Nesta variável é 
armazenado um objeto da classe Pessoa. O objeto é instanciado com o uso da palavra 
reservada new seguida do “nome da classe”. Na verdade, o termo Pessoa() que segue 
a palavra new não é o nome da classe, mas um método construtor. Métodos 
construtores serão apresentados logo a seguir. 
Nas linhas 9 e 10 os atributos nome de p e telefone de p têm seus valores atribuídos. 
Note que o objeto p têm seus próprios atributos nome e telefone. Caso um outro objeto 
fosse instanciado, ele poderia ter valores diferentes em seus atributos nome e telefone. 
Na linha 12 é chamado o método apresente() de p, o qual faz ser exibida a caixa de 
mensagem com as informações armazenadas no objeto p. 
Instruções de controle 
Note que, da maneira que a classe Pessoa no item anterior foi escrita, qualquer valor 
pode ser atribuído aos atributos da classe, mesmo que eles sejam inválidos. Há uma 
maneira de se evitar que isso aconteça: nós podemos encapsular os atributos, ou seja, 
torna-los privados e oferecer acesso a eles por métodos acessores que fazem a 
validação dos dados, de forma que apenas dados válidos sejam armazenados. Abaixo, 
modificamos a classe Pessoa para que só possam ser armazenados telefones com 
pelo menos oito dígitos. Vamos também encapsular o atributo nome, mesmo que 
nenhuma validação seja feita: 
 
 
Nas linhas 7 e 8, os atributos nome e telefone foram alterados para privados, o que 
significa que agora eles só podem ser acessados de dentro da própria classe Pessoa. 
Para permitir que eles tenham seus valores lidos, foram criados os métodos getters, 
nas linhas 10 e 18. Estes métodos, quando executados, retornam o valor armazenado 
no atributo correspondente. 
Na linha 14 é criado o método setNome(), que recebe como parâmetro um nome e o 
atribui ao atributo nome. Como tanto o parâmetro quanto o atributo possuem o mesmo 
nome, o programa não teria como saber qual é o atributo e qual é o parâmetro. Para 
resolver este problema, utiliza-se a referência this na linha 15. Desta forma, pode-se ler 
a linha 15 como sendo “o nome deste objeto recebe o valor de nome”. Assim, 
this.nome é o atributo do objeto enquanto que nome é o parâmetro. 
Já no método setTelefone() na linha 22, só é feita a atribuição se o valor do parâmetrotelefone tiver ao menos oito dígitos. Esta verificação é feita com o desvio condicional if. 
Sua sintaxe completa é: 
 
A condição pode ser qualquer expressão que tenha como valor final um booleano. Isso 
significa que a condição pode ser uma simples variável booleana ou uma expressão 
booleana, que é o resultado de alguma operação lógica. As operações lógicas são: 
== igual a 
!= diferente de 
< menor que 
> maior que 
<= menor ou igual a 
>= maior ou igual a 
! não (inverte o resultado de uma expressão booleana) 
Quando se deseja realizar vários testes, pode-se encadear outro if dentro do conjunto 
de instruções da cláusula else. Mas também pode-se utilizar a estrutura switch-case, a 
qual tem a sintaxe abaixo: 
 
 
A estrutura switch-case usa como cláusula de teste uma variável que pode ser dos 
tipos primitivos char, int, short ou byte. Cada cláusula case define um conjunto de 
instruções que será executado caso seu valor corresponda ao valor da variável de 
teste. A cláusula default, que é opcional, é executada se nenhuma outra cláusula case 
foi executada. 
A classe Pessoa ainda não teve um método construtor definido explicitamente. Método 
construtor é um método que é executado sempre que um objeto é instanciado. Este 
método deve possuir exatamente o mesmo nome da classe e não deve apresentar 
nenhum tipo de retorno, nem mesmo void. Quando não criamos um construtor em uma 
classe, o próprio compilador cria um para nós, é o construtor padrão. O método 
construtor padrão é um construtor sem parâmetros e que não executa nenhuma ação 
em sua implementação. Quando escrevemos “Pessoa p = new Pessoa();”, o termo 
Pessoa(), na verdade, é o construtor padrão da classe. Nós podemos criar os nossos 
próprios construtores. Uma vez que a classe tenha um construtor qualquer, o 
compilador não irá criar o construtor padrão. Caso queiramos um construtor sem 
parâmetros, devemos declará-lo explicitamente, como do exemplo abaixo: 
 
 
Na linha 28 é declarado o método construtor sem parâmetros. Note que o método deve 
ter exatamente o mesmo nome da classe e não deve apresentar nenhum tipo de 
retorno. Na linha 32 é criado um segundo método construtor, desta vez ele recebe 
como parâmetros o nome e o telefone da pessoa. Em sua implementação, ele faz a 
atribuição dos valores utilizando a validação de dados por meio dos métodos acessores 
que já foram criados na classe. 
A classe TestaPessoa pode ser modificada da seguinte maneira para refletir as 
mudanças feitas na classe Pessoa: 
 
 
 
Na linha 7, é instanciado o objeto p1 utilizando o construtor sem parâmetros. Nas linhas 
8 e 9, os valores dos atributos agora precisam ser definidos utilizando os métodos 
acessores. Já não é mais possível acessar os atributos diretamente pois eles foram 
definidos como privados. 
Na linha 12, um outro objeto, p2, é instanciado, desta vez utilizando o construtor que 
recebe como parâmetros os valores do nome e do telefone. Durante a instanciação os 
valores são armazenados nos atributos e o objeto já está pronto para exibir suas 
informações. 
Agora, digamos que queiramos que o programa leia e exiba os dados de dez pessoas. 
Nós poderíamos simplesmente repetir a lógica do programa anterior dez vezes, mas 
esta não é a melhor escolha. 
O computador existe para realizar o trabalho árduo para nós. Sempre que nos 
pegamos pensando algo como “vou ter que fazer a mesma coisa de novo”, muito 
provavelmente há algo errado em nosso algoritmo. Sempre há alguma maneira de 
fazer como que o programa faça a tarefa repetitiva para nós. 
Abaixo vamos modificar o programa TestePessoa para repetir dez vezes a rotina de 
receber e exibir os dados de dez pessoas: 
 
 
O método recebePessoa() entre as linhas 7 e 19 recebe do usuário os dados de uma 
pessoa, instancia um objeto da classe Pessoa com estes dados e o retorna. 
O método main() entre as linhas 21 e 30 utiliza o método recebePessoa() para receber 
os dados de dez pessoas. Na linha 25 é iniciado um laço de repetição for para repetir 
dez vezes a rotina definida nas linhas 26 e 27. O laço for tem três parâmetros: o 
primeiro é uma definição de uma variável contadora; o segundo é a condição que, se 
verdadeira, permitirá que o laço seja repetido mais uma vez; o terceiro é a lógica de 
incremento (ou decremento) da variável contadora. 
O Java ainda define os laços while e do-while, que possuem a seguinte sintaxe: 
 
O laço while inicia testando a condição de parada. Se ela for verdadeira, ele irá 
executar o conjunto de instruções de repetição. Em algum momento durante a 
execução, a condição de parada deve ser alterada para falsa, de modo a fazer com 
que o laço encerre. 
O laço do-while inicia executando uma vez o conjunto de instruções de repetição. A 
seguir ele verifica a condição de parada. Se ela estiver verdadeira, o loop reinicia. 
Novamente, em algum momento a condição de parada deve ser alterada para falsa 
para que o laço termine. 
Arrays 
O programa do exemplo anterior conseguia ler e exibir os dados de dez pessoas, mas 
não era capaz de armazená-los. Para tanto, deveríamos ter criado dez variáveis. 
Entretanto, criando dez variáveis, seria muito difícil continuar utilizando o laço for para 
automatizar o processo. Para resolver este problema, podemos utilizar um array 
(vetor). Um array é um conjunto de variáveis de mesmo tipo. Vejamos como o 
programa pode ser modificado para utilizar um array de Pessoa: 
 
Na linha 22 é declarada a variável p, que desta vez é um array de objetos da classe 
Pessoa. Isto é indicado pelo símbolo []. Um array deve ser instanciado como se fosse 
um objeto, o que é feito na linha 23 com o operador new, seguido do tipo de dado de 
cada elemento do vetor (Pessoa) e da quantidade de elementos do vetor ([10]). 
Na linha 25 é declarada a variável contadora que será usada nos dois laços for a 
seguir. 
Na linha 27 é iniciado o laço de leitura das dez pessoas. Na linha 28, cada pessoa é 
lida pelo método recebePessoa() e é armazenada no elemento de ordem i do vetor p 
(p[i]). Note que os índices de vetores em Java iniciam com o valor 0. 
Na linha 31 é iniciado o laço de apresentação das dez pessoas. Cada elemento do 
vetor p é um objeto da classe Pessoa e, por isso, possui o método apresente(). Assim, 
na linha 32, cada elemento do vetor tem o seu método apresente() chamado. 
Coleções 
O uso de arrays foi útil para armazenar uma quantidade definida de objetos da classe 
Pessoa. Entretanto, para utilizar arrays deve-se saber de antemão quantos elementos 
serão necessários para se criar o vetor. Quando não se sabe quantos elementos serão 
necessários, podemos utilizar estruturas dinâmicas de armazenamento de dados. O 
Java nos oferece um conjunto de estruturas deste tipo, as coleções. Uma coleção é um 
conjunto de variáveis semelhante a um array, mas que pode ter o seu tamanho 
modificado conforme a necessidade. 
Vamos modificar o programa TestaPessoa para receber uma quantidade indefinida de 
pessoas. Este programa irá armazenar objetos da classe Pessoa enquanto o usuário 
desejar: 
 
Na linha 24 é declarada a estrutura dinâmica de armazenamento de dados pessoas, 
que é um ArrayList que irá armazenar elementos da classe Pessoa. Na mesma linha, a 
estrutura pessoas é instanciada. Por enquanto, a estrutura já existe, mas ainda não 
possui nenhum elemento dentro dela. 
Nas linhas 27 a 32 é feita a leitura de uma quantidade não conhecida de pessoas. Na 
linha 27 é declarada a variável que irá conter a resposta do usuário quando lhe for 
perguntado se ele deseja continuar cadastrando pessoas. Sua resposta será na forma 
de um número inteiro, como será visto adiante. Na linha 28 é iniciado o laço do-while, o 
que significa que o laço será executado ao menos uma vez. Nalinha 29, o método 
recebePessoa() é executado para ler os dados de uma pessoa. Ele devolve um objeto 
da classe Pessoa, este objeto é, então, passado como parâmetro para o método add() 
do ArrayList pessoas. Este método adiciona seu parâmetro como um novo elemento do 
vetor dinâmico pessoas. Na linha 30 é usado o método showConfirmDialog da classe 
JOptionPane. Este método exibe uma caixa de diálogo onde o usuário pode dar sua 
resposta por meio de botões. A versão do método utilizada pede quatro parâmetros: o 
primeiro é a janela pai (continuamos usando nenhuma); o segundo é a pergunta que 
será exibida para o usuário; o terceiro é o título da caixa de diálogo; o quarto define 
quais são os botões exibidos. As opções são YES_NO_CANCEL_OPTION e 
YES_NO_OPTION. Na linha 32, a resposta do usuário é verificada. Para que não 
tenhamos que decorar qual é o valor de cada resposta, utilizamos uma das constantes 
disponíveis para a resposta: YES-OPTION, NO_OPTION ou CANCEL_OPTION. 
Nas linhas 35 a 37 um novo laço é feito, desta vez para exibir os dados de todas as 
pessoas cadastradas. A linha 35 utiliza uma forma alternativa do laço for. Esta forma 
recebe dois parâmetros separados por dois pontos (ao invés de ponto e vírgula): O 
primeiro é uma definição de cada elemento da estrutura definida pelo segundo 
parâmetro. Esta linha pode ser lida como “para cada Pessoa p em pessoas”. O 
segundo parâmetro pode ser uma coleção ou um vetor. Este laço, então, irá percorrer 
todos os elementos dentro de pessoas, irá chamar cada um de p e irá executar a linha 
36, onde é chamado o método apresenta() de p. 
Tratamento de exceções 
Se você esteve testando os programas discutidos até aqui, deve ter encontrando 
algumas situações em que o programa parou abruptamente devido a alguma situação 
inesperada. Por exemplo, em qualquer um dos programas que cadastra o telefone de 
uma Pessoa, se o usuário digitar uma letra (ou nada) no lugar de um número inteiro 
quando lhe é pedido para digitar o número de um telefone, o programa é encerrado 
informando uma mensagem de erro. Experimente fazer isso agora e observe a 
mensagem de erro que é apresentada na janela do Console. Na primeira linha da 
mensagem de erro é dito que ocorreu uma exceção do tipo NumberFormatException 
(em inglês). Isso indica que foi tentada a conversão para inteiro de um String que não 
representava um número inteiro. 
Nós podemos modificar o programa para que ele perceba esta exceção e peça ao 
usuário para inserir novamente o número de telefone até que um número válido seja 
inserido. Isto é feito com o tratamento de exceções, que é composto de blocos try-catch 
ou try-catch-finally. 
No bloco try é implementado o código que pode provocar uma exceção. No bloco catch 
é implementado o código que será executado caso uma exceção ocorra. No bloco 
opcional finally é implementado o código que deve ser executado tendo ocorrido uma 
exceção ou não. Ele é útil para fechar recursos que estavam sendo usados no bloco 
try, como arquivos, conexões com bancos de dados, conexões de rede, etc. 
Vamos modificar o método recebePessoa() da classe TestaPessoa para que ele se 
recupere de uma entrada de dados errada no número do telefone. 
 
O trecho que recebe o número de telefone de uma pessoa agora está entre as linhas 
19 e 29. Na linha 19 é definida uma variável booleana que é verdadeira enquanto o 
usuário precisa inserir um número de telefone válido. Na linha 20 é iniciado o laço que 
será repetido enquanto o usuário insere caracteres inválidos para um número de 
telefone. Na linha 21 é iniciado o bloco try, que é o trecho de código que pode causar 
uma exceção. A exceção de formatação numérica pode ocorrer na linha 22, quando o 
método parseInt() tenta converter um String inválido para um número inteiro. Se a 
conversão for bem sucedida, a linha 24 é executada e armazena o valor false na 
variável repete. Caso uma exceção de formatação numérica tenha sido lançada no 
bloco try, ela será capturada pelo bloco catch na linha 25. Na linha 26 é exibida uma 
mensagem informativa ao usuário e a variável repete não terá seu valor alterado. Na 
linha 29 o laço do-while decide se ele deve reiterar ou não, dependendo do valor 
armazenado pela variável repete. Ela contém o valor true se ocorreu uma exceção, 
false caso contrário. 
As principais exceções são: 
• ArithmeticException: erro aritmético, como uma divisão por zero; 
• ArrayIndexOutOfBoundsException: foi acessado um índice de vetor fora do seu 
limite; 
• NullPointerException: foi acessado um objeto que ainda não foi instanciado; 
• NumberFormatException: foi tentada a conversão de um String em um formato 
numérico inválido. 
Também é possível fazer o tratamento de mais de uma exceção em um mesmo bloco 
try: 
 
Nas linhas 16 e 18 é feita a conversão da entrada de dados do usuário para int, o que 
pode causar uma exceção NumberFormatException, a qual é tratada pela cláusula 
catch da linha 23. 
Na linha 20 é feita a divisão de dois números inteiros, o que pode causar uma exceção 
ArithmeticException, a qual é tratada pela cláusula catch da linha 26. 
Programação orientada a objetos 
No item anterior nós conhecemos a tecnologia Java e vimos, de maneira bastante 
superficial, que esta tecnologia é orientada a objetos. Nesta unidade, vamos abordar 
em maiores detalhes como o Java implementa os recursos que tornam o paradigma 
orientado a objetos o principal paradigma de desenvolvimento de sistemas. 
O aspecto mais importante da orientação a objetos é o polimorfismo. O termo 
polimorfismo origina-se do grego e significa muitas formas (poli = muitas, morphos = 
formas). As principais manifestações deste recurso são a sobrecarga, a sobrescrita e o 
polimorfismo de objetos. 
Sobrecarga 
A sobrecarga de métodos já foi vista rapidamente na unidade anterior, quando 
abordamos os métodos construtores de uma classe. Naquela ocasião, apenas 
dissemos que uma classe pode apresentar mais de um método construtor, desde que 
estes tenham uma lista de parâmetros diferentes. 
A sobrecarga pode ser feita com qualquer método, ou seja, podemos criar quantos 
métodos queiramos em uma classe com o mesmo nome, desde que eles tenham uma 
lista de parâmetros que seja diferente em quantidade, em tipo ou em quantidade e tipo. 
Quando sobrecarregamos um método, estamos dizendo que todos os métodos 
sobrecarregados realizam a mesma tarefa, mas de maneiras diferentes. Considere a 
seguinte classe: 
 
Note que a classe da Figura 48 define quatro versões do método soma(), cada uma 
com uma lista de parâmetros diferentes. A primeira sobrecarga recebe dois int; a 
segunda três int; a terceira dois double e a quarta três float. Note que não faz a menor 
diferença os nomes dos parâmetros, apenas os seus tipos. Se na classe acima for 
criada uma nova sobrecarga como mostrado abaixo, o código apresenta erros e não 
pode ser compilado. 
 
O próprio editor de código indica que há um erro na declaração dos métodos nas linhas 
5 e 21. Ao se flutuar o mouse por cima do erro (flutuar significa mover o cursor sobre o 
erro e não clicar) o editor indica que o método soma(int, int) está duplicado, mesmo que 
os nomes dos parâmetros sejam diferentes. 
Ao se flutuar o mouse sobre um erro no código, pode ser apresentada uma solução 
automática para o erro. Cuidado! Apenas execute a solução automática se você 
entende o que ela está fazendo. Caso não saiba o que o editor está fazendo, a 
situação pode até piorar! Isto ocorre porque a solução automática realiza alguma 
mudança no código para que ele possa ser compilado, mas a mudança pode não ser a 
que você espera. Neste caso, encontrar o erro pode ser ainda mais difícil, pois você já 
não terá mais uma indicação visual do erro. 
Herança 
Um dos recursos maisimportantes da orientação a objetos é a herança. Ela é um 
mecanismo que permite que uma classe “herde” os atributos e métodos de uma outra 
classe. No jargão de programação, chamamos a classe que herda de classe filha, 
enquanto que chamamos a classe da qual a filha herda de classe pai. Outros nomes 
para classe pai são superclasse e classe geral. A classe filha também pode ser 
chamada de subclasse e classe especializada. 
Considere a classe Pessoa vista na unidade I. Ela é útil para armazenar os dados de 
uma pessoa genérica. Agora considere que desejamos armazenar os dados de um 
aluno. Muitos dos elementos da classe Aluno serão os mesmos da classe Pessoa. 
Sempre que passar pela sua cabeça a sensação de que algo que você está 
programando é igual a algo que já programou, tenha certeza de que há uma maneira 
melhor de realizar a mesma tarefa. Em orientação a objetos, sempre que um 
programador repete um código, ele está errando! Não se repete código em orientação 
a objetos! 
Ao se criar a classe Aluno, pode-se aproveitar o que já foi feito na classe Pessoa, 
herdando da classe Pessoa. A partir daí, a classe Aluno já possui todos os atributos e 
métodos da classe Pessoa. Ela só precisa declarar atributos e métodos que são 
específicos de um aluno. 
 
Na linha 3, a classe Aluno é declarada com a palavra reservada extends, que indica 
que a classe herda da classe Pessoa. A partir daqui, a classe já possui todos os 
atributos e métodos da classe Pessoa. Note que só foram declarados os atributos e 
métodos que pertencem apenas a um aluno. 
Na linha 12, o método setRa() agora faz consistência do seu parâmetro, para ter 
certeza de que ele não é um String vazio. Entretanto, não se pode escrever a 
comparação ra != “”, pois os operadores lógicos não funcionam como se espera 
quando os operandos são objetos, apenas quando eles são de tipos primitivos. Quando 
a comparação é feita com objetos, como é o caso de Strings, utilize o método equals(), 
que retorna verdadeiro se o objeto que executa o método tem o mesmo conteúdo que o 
objeto no parâmetro do método. Na linha 15, caso o parâmetro recebido pelo método 
não seja válido, o método irá lança uma exceção do tipo IllegalArgumentException com 
a mensagem de erro “RA inválido”. Desta forma, o método que tentou atribuir o RA 
inválido pode tratar a exceção e tentar obter um valor válido para o RA. 
É uma boa prática de programação lançar uma exceção quando alguma rotina de 
validação de dados não for bem sucedida. Modifique a classe Pessoa para que ela se 
comporte desta maneira. 
A partir de agora, pode-se instanciar um objeto da classe Aluno, atribuir valores ao seu 
nome, telefone e RA e executar o método apresente(). 
Sobrescrita 
Note que o método apresente() apenas informa o nome e o telefone do aluno. Desta 
forma, ele deve ser modificado. Nós podemos sobrescrever, ou seja, modificar o 
método na classe filha para que ele se comporte da maneira desejada. Esta é mais 
uma modalidade de polimorfismo. 
 
O método apresente() na linha 21 possui exatamente a mesma assinatura do método 
herdado da superclasse, ou seja, ele possui o mesmo nome, os mesmos parâmetros e 
o mesmo tipo de retorno. Isso caracteriza uma sobrescrita do método. Note também 
que, na linha 23, não podemos mais acessar diretamente os atributos nome e telefone, 
pois ambos são privados na classe Pessoa. Por isso, fazemos o acesso por meio de 
seus métodos acessores. 
Nas linhas 27 a 30 é definido o construtor da classe que recebe três parâmetros, o 
nome, o telefone e o Ra. Na linha 28 poderíamos ter feito a atribuição dos valores do 
nome e telefone diretamente usando os métodos acessores dos atributos. Mas a classe 
Pessoa já realiza esta tarefa em um de seus construtores. Nós podemos invocar 
diretamente tal construtor de dentro de nosso construtor, na primeira linha, usando a 
palavra reservada super, que referencia a superclasse. Esta referência funciona de 
maneira análoga à referência this, mas enquanto this referencia o próprio objeto, super 
referencia a superclasse. 
O programa abaixo ilustra a instanciação e uso de um objeto da classe Aluno. 
 
 
Polimorfismo 
O polimorfismo de classes é o aspecto mais importante da orientação a objetos. Com 
este recurso, quando bem utilizado, podemos criar soluções simples e eficientes para 
problemas que teriam soluções grandes, trabalhosas e ineficientes se fosse utilizado 
apenas o paradigma estruturado de programação. 
O polimorfismo de classes é um recurso que permite que um objeto de uma classe seja 
tratado como se fosse de outra classe. Para que isto seja possível, ambas as classes 
devem estar na mesma estrutura hierárquica e, além disso, uma delas deve ser um 
ancestral da outra. 
Considere o seguinte exemplo: Uma loja de rua permite a entrada de qualquer pessoa 
por sua porta principal. A loja não faz distinção se a pessoa que entra é um aluno, um 
professor, um funcionário, motorista ou qualquer outra especialização de pessoa. Por 
outro lado, uma escola possui catracas que só permitem a entrada de alunos. Outros 
tipos de pessoas não têm a sua entrada permitida. Em termos de orientação a objetos, 
a catraca da escola pode ser considerada como um método que recebe apenas objetos 
da classe Aluno como parâmetro. Já a entrada da loja é um método que recebe como 
parâmetro objetos da classe Pessoa. Como Aluno é uma subclasse de Pessoa, é uma 
especialização, é um tipo de Pessoa, o Aluno também pode ser enviado como 
parâmetro para a loja por polimorfismo. 
 
 
 
 
Nas linhas 7 a 10 é definido o método catracaDaEscola() que recebe como parâmetro 
um objeto da classe Aluno. 
Nas linhas 12 a 15 é definido o método entradaDaLoja() que recebe como parâmetros 
um objeto da classe Pessoa. Por polimorfismo, como Aluno é um tipo de Pessoa, ele 
também pode ser passado como parâmetro para este método. 
Nas linhas 17 a 25 é feito o código de teste. Nas linhas 18 e 19 são instanciados 
objetos das classes Aluno e Pessoa respectivamente. Na linha 21, o aluno é passado 
para o método catracaDaEscola(). Na linha 22, a pessoa é passada para o método 
entradaDaLoja(). Já na linha 24 é que ocorre o polimorfismo: o aluno é passado para o 
método entradaDaLoja(). Mesmo que este método receba como parâmetro um objeto 
da classe Pessoa, ele aceita o objeto aluno, pois ele é um tipo de Pessoa. Repare que 
na terceira saída do programa, o aluno Joaquim é tratado como uma pessoa, não como 
um aluno. 
Modificadores de acesso 
Agora que já abordamos os principais aspectos da orientação a objetos, podemos dar 
mais atenção aos modificadores de acesso. 
Utilizamos os modificadores de acesso private e public para encapsular atributos, ou 
seja, protegemos os atributos tornando-os inacessíveis, permitindo o acesso a eles por 
métodos acessores públicos que fazem a consistência de dados. 
A orientação a objetos define quatro modificadores de acesso para os membros 
(atributos e métodos) da classe, os quais são adotados pela linguagem Java. Eles são: 
• public (público): Qualquer classe que tenha acesso à classe onde o membro está 
declarado terá acesso ao membro. 
• protected (protegido): Apenas a própria classe e suas subclasses têm acesso ao 
membro. Em Java, o modificador protected também permite acesso ao membro por 
classes do mesmo pacote, mesmo que não sejam subclasses. 
• padrão (ou pacote): Membros definidos sem nenhuma palavra reservada são de 
acesso padrão ou pacote, ou seja, a própria classe e qualquer classe do mesmo pacote 
têm acesso ao membro. 
• private (privado): Apenas a própria classe onde o membro é declarado tem acesso a 
ele. 
É uma boa prática de programação definir todos os membros inicialmente com o 
modificador mais restritivo (privado). Conforme a necessidadede acesso ao membro 
vai surgindo, o modificador de acesso deve ser alterado gradativamente na direção do 
modificador público. 
 
Escopo 
Os membros de uma classe normalmente pertencem aos seus objetos. Por exemplo, o 
atributo nome da classe Pessoa pertence aos objetos da classe Pessoa. Cada um dos 
objetos pode ter um valor diferente para o atributo nome. Da mesma maneira, o método 
apresente() só pode ser chamado de um objeto. Isto é chamado de escopo de objeto. 
Um membro pode, por outro lado, pertencer à classe, não aos seus objetos, 
caracterizando o escopo de classe. O escopo de classe é definido pela palavra 
reservada static. Um método de classe pode ser chamado diretamente da sua classe, 
não sendo necessário instanciar nenhum objeto da classe. Os métodos 
showMessageDialog(), showInputDialog() e showConfirmDialog() puderam ser 
chamados diretamente da classe JOptionPane, sem a necessidade de instanciar um 
objeto da classe para executar estes métodos. 
Da mesma forma o método main() também é de classe, porque para executar um 
programa, a máquina virtual não irá instanciar qualquer objeto, ela irá simplesmente 
executar o método da classe onde ele foi declarado. 
Um atributo de escopo de classe terá o mesmo valor para a classe e para todos os 
seus objetos. Se o seu valor for modificado em qualquer um deles, o valor será 
modificado em todos. 
Um método de escopo de objeto é executado em um objeto. Por isso, ele terá acesso a 
qualquer método e qualquer atributo da classe, sejam eles de qualquer um dos dois 
escopos. 
Por outro lado, um método de escopo de classe, quando executado, não tem acesso a 
qualquer objeto, pois ele só “conhece” a sua classe. Por isso, ele não consegue 
acessar membros que sejam de escopo de objeto, ele só pode acessar membros de 
classe como ele próprio. 
O exemplo a seguir utiliza um atributo de classe para contar quantas vezes ele foi 
instanciado. 
 
Na linha 5 é declarado o atributo contador de escopo de classe, com o valor inicial 0. 
Nas linhas 7 a 9 é definido o construtor da classe. O construtor é executado toda vez 
que um objeto da classe é instanciado, e quando isso acontece, o atributo contador é 
incrementado. 
Nas linhas 11 a 13 é definido um método acessor para o atributo contador. 
 
 
Nas linhas 9 a 11 a classe Contador é instanciada 100 vezes. Nas linhas seguintes ela 
é instanciada mais duas vezes. O conteúdo do atributo contador é apresentado nas 
linhas 15 a 17. 
Classes abstratas e interfaces 
Considere que estamos desenvolvendo um programa de desenho por computador. 
Este programa usa figuras geométricas como o retângulo, o triângulo e o círculo. Uma 
das funcionalidades deste programa é calcular a área de todas as figuras no desenho. 
Para aproveitar o polimorfismo, vamos criar uma estrutura hierárquica de classes para 
modelar as figuras geométricas do sistema. Assim, as classes Retangulo, Triangulo e 
Circulo serão todas subclasses da classe FiguraGeometrica. A classe 
FiguraGeometrica irá definir o método calculaArea() que será sobrescrito por todas as 
subclasses. As sobrescritas do método, então, irão realizar o cálculo correto da área de 
cada figura. Para que o código não fique muito extenso, não vamos encapsular os 
atributos. 
 
Nas linhas 6 a 8 é definido o método calculaArea(), o qual existe apenas para permitir o 
polimorfismo. Como não é possível calcular a área de uma figura geométrica genérica, 
o método retorna um valor negativo para indicar que ele não deve ser usado. 
O mesmo ocorre com o método getNome() entre as linhas 7 e 9, que irá retornar o 
nome da figura geométrica. 
 
 
 
As três subclasses sobrescrevem o método calculaArea() entre as linhas 7 e 9, cada 
uma com a equação apropriada. Note que na classe Circulo, o cálculo é feito com a 
ajuda da classe Math, a qual define uma constante com o valor de π (pi) e o método 
pow(), o qual realiza a potência de raio elevado a 2. 
O método getNome() entre as linhas 11 e 13 retorna o nome da figura geométrica 
apropriada. 
As subclasses também definem seus construtores, os quais já fazem a atribuição de 
valores aos seus atributos. 
A seguir, o programa de teste: 
 
 
Entre as linhas 7 e 11, o método formataFigura() recebe como parâmetro um objeto da 
classe FiguraGeometrica e de qualquer uma de suas especializações. Na linha 9 é feita 
a formatação de um String com o nome da figura e sua área. 
No método main(), entre as linhas 13 e 27, é feita a rotina de teste. Na linha 14 é 
declarado e instanciado um vetor de três posições de FiguraGeometrica. Nas linhas 16 
a 18, cada uma das posições recebe um objeto de uma de cada das classes de figuras 
geométricas especializadas. Neste ponto já ocorre polimorfismo. Entre as linhas 22 e 
24 é feito um laço for aprimorado para percorrer o vetor e obter a sua representação 
em texto. Cada representação é anexada à variável mensagem, com o caracter de 
escape \n, que representa uma quebra de linha. Na linha 26 é exibida a caixa de 
diálogo. 
O programa acima realiza a sua tarefa, mas não muito bem. O problema está na classe 
FiguraGeometrica, a qual define métodos que não pode implementar e, por isso, faz 
uma implementação propositalmente errada. A orientação a objetos oferece uma 
alternativa: nós podemos declarar métodos abstratos, ou seja, métodos sem 
implementação. Quando se criam métodos abstratos em uma classe, esta classe 
também deve ser abstrata. Assim, podemos modificar a classe FiguraGeometrica da 
seguinte forma e o restante do programa pode permanecer inalterado. 
 
Nas linhas 5 e 7, as declarações dos métodos são agora de métodos abstratos. Por 
isso, eles agora não possuem implementação e são terminados com ponto-e-vírgula. A 
classe agora também deve ser abstrata. 
Uma classe abstrata pode definir métodos e atributos concretos (não abstratos). Mas 
por conter métodos sem implementação, uma classe abstrata não pode ser 
instanciada. Ela só pode ser usada com polimorfismo, como foi feito neste exemplo. 
Além disso, as classes que herdam de uma classe abstrata devem implementar todos 
os seus métodos abstratos se quiserem ser classes concretas, caso contrário, elas 
também serão abstratas. Isto é útil para garantir que as subclasses implementaram 
todos os métodos que deveriam ser sobrescritos, caso eles fossem concretos, como na 
primeira versão deste exemplo. 
Considere agora uma classe abstrata que só declara métodos abstratos (como no 
exemplo acima). Uma classe desse tipo pode ser melhor modelada como uma 
interface. Uma interface é uma classe abstrata que só define métodos abstratos. Uma 
classe que realize uma interface (não se usa o termo herdar de uma interface) deve 
implementar todos os seus métodos. Assim, poderíamos ter: 
 
Na linha 3 estamos declarando uma interface, não mais uma classe. 
Como não se pode herdar de uma interface, apenas realiza-la, as classes Retangulo, 
Triangulo e Circulo devem ser alteradas, trocando a palavra reservada extends por 
implements: 
 
 
Interfaces Gráficas 
As interfaces gráficas em Java são normalmente criadas utilizando as bibliotecas AWT 
e SWING. A biblioteca AWT foi a primeira a ser desenvolvida e diversos de seus 
componentes continuam em uso até hoje. Entretanto, alguns componentes dessa 
biblioteca utilizam recursos do ambiente gráfico no qual o aplicativo esteja sendo 
executado (como o Windows, o Linux e o MacOS). Isso faz com que aplicativos que 
utilizem estes componentes do AWT tenham comportamentos ligeiramente diferentes 
em cada plataforma. Para resolver este problema, a biblioteca SWING foi desenvolvida 
para oferecer componentes gráficos que não dependem do ambiente de execução. 
Assim, aplicativos Java com interfaces gráficas costumam usar essas duas bibliotecas.Há duas maneiras principais para se escrever uma interface gráfica em Java. A 
primeira é escrever o código todo no editor de códigos, como vínhamos fazendo até 
agora. Inicialmente isso pode parecer difícil, mas com um pouco de experiência e 
conhecimento das bibliotecas você vai acabar percebendo que isso não é tão difícil. 
Ainda bem, pois há situações em que devemos escrever manualmente o código de 
uma interface gráfica. 
A outra maneira de se criar uma interface gráfica é usando algum editor de GUI 
(Graphical User Inteface - Interface Gráfica com o Usuário). Enquanto o Eclipse 
normalmente não vem equipado com uma, é possível instalar algum plug-in que 
ofereça esta funcionalidade. Existem vários na loja de plug-ins do Eclipse. Já o 
NetBeans é equipado com um editor de interfaces gráficas. Por isso, para este módulo 
vamos utilizar esta IDE. 
Um aplicativo simples com interface gráfica 
Vamos criar um pequeno aplicativo separado em classes de estereótipos entity, 
boundary e controller com acoplamento por interface. Este aplicativo terá a arquitetura 
representada pelo diagrama de classes abaixo: 
 
Vamos criar três pacotes, o pacote entidades, controle e fronteira. A interface será 
criada no pacote controle. 
Vamos iniciar codificando as classes de entidade Endereco e Pessoa, as quais são as 
mesmas já usadas no último laboratório. Elas apenas foram refatoradas ao serem 
declaradas no pacote entidades: 
 
 
A seguir, vamos codificar a interface ICadastroPessoa, a qual define qual é o método 
que a interface gráfica irá chamar quando for pressionado o botão para o cadastro de 
uma nova pessoa: 
 
Uma interface pode ser entendida como um cardápio de métodos disponíveis em uma 
determinada classe. Quando uma classe realiza uma interface, temos certeza de que a 
classe oferece os serviços definidos pelos métodos declarados na interface. No nosso 
exemplo, a interface gráfica irá utilizar o método cadastraPessoa() definido acima e que 
será implementado por outra classe. 
O método cadastraPessoa() recebe como parâmetros um objeto que representa a 
janela ativa do usuário (pai) e um objeto da classe Pessoa com os dados a serem 
cadastrados. Abaixo, vamos criar a classe CadastroPessoa, a qual realiza a interface 
acima e implementa seu método: 
 
Neste momento, vamos usar o editor de GUI incorporado do NetBeans. Note que o 
mesmo pode ser feito ao se baixar um plug-in editor de GUI para o Eclipse. 
No pacote fronteira, clique com o botão direito e selecione Novo -> Outros e então 
selecione Forms GUI Swing -> Form JFrame: 
 
Dê o nome TelaCadastroDePessoa à sua classe e clique em Finish. 
 
O assistente cria uma nova classe que implementa uma janela. Desta vez, o editor de 
código também possui uma aba que permite a edição gráfica da janela. Clique na aba 
Design: 
 
A seguir, clique em JLabel na palheta de componentes e adicione o rótulo na janela. 
Digite “Nome:” em sua propriedade text. 
 
Altere o nome do objeto JLabel para lblNome: 
 
Repita o processo e crie os rótulos para telefone, rua e número: 
 
Insira agora os componentes JTextFields para receber os dados. Não se esqueça de 
trocar os nomes dos objetos: 
 
Insira agora o botão “Cadastrar”: 
 
Até este momento, criamos a aparência básica da janela. Vamos preparar a janela para 
que ela possa executar o método cadastraPessoa da classe CadastroPessoa. Clique 
na aba Código-Fonte e modifique o código da janela inserindo três novas linhas de 
importação e um novo atributo. Vamos tornar o construtor sem parâmetros privado para 
que a janela só possa ser instanciada com um tratador de cadastro.Vamos criar 
também um novo construtor que já atribui um objeto com o método definido pela 
interface que criamos: 
 
Vamos criar um método que será chamado quando o botão “Cadastrar” for clicado: 
 
Volte para o editor de design e dê um clique duplo no botão “Cadastrar”. O editor irá 
criar um método que será chamado quando o botão for clicado. Inclua na 
implementação do método btnCadastrarActionPerformed() uma chamada ao método 
cadastrar() que acabamos de criar: 
 
No código fonte, mude o modificador de acesso do método main() para privado, pois 
não queremos que este método seja mais utilizado: 
 
Agora só falta criar o método main() na classe Programa que irá iniciar a janela da 
maneira correta: 
 
Agora o programa pode ser executado: 
 
 
Você pode baixar este aplicativo compilado e o código fonte a partir do GitHub no 
endereço ​https://goo.gl/Ww5RGH​. Se ao clicar em sua cópia local de 
AplicativoTresCamadas.jar o aplicativo não for iniciado, abra uma linha de comando na 
pasta onde o aplicativo foi gravado e execute o comando java -jar 
AplicativoTresCamadas.jar.

Outros materiais