P. 1
Java Use a Cabeça

Java Use a Cabeça

5.0

|Views: 4.370|Likes:

More info:

Published by: Fernando Souza Dos Anjos on Jun 15, 2012
Direitos Autorais:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

08/31/2015

pdf

text

original

Use a Cabeça!

~
f'\

Aprenda como os segmentos (threads) podem mudar sua vida

(\

banho no

..;.ct;.Çf )-i : ;ãj~

'"

I

Faça os conceitos de Java se incorporarem ..,..---- à sua mente

/"'.

Evite erros embaraçosos

--- - de-OO------ .--

/"'.

Bote-a cabeça - a:ca--p ~ funcionar com os 42 '" quebra-cabeças em Java
~

.,I

o que estão dizendo sobre Use a Cabeça!
A Amazon escolheu Use a Cabeça! Java como Top Ten Editor's Choice for . _. Compll!er Books of 2©3(primeira edição) A Software Development Magazine indicou Use a CabeçaFlava para finalista do 14'h Annual Jolt ColaIProduct Excellence Awards

"O livro ' Use a Cabeça! Java', de Kathy e Bert, transfonnará a página impressa na coisa mais próxima de uma QUI que você jamais viu. De uma maneira divertida e moderna, os autores tornam o aprendizado de Java uma experiência envolvente do tipo 'o que eles vão inventar agora?'."

- Warren Keuffel, Software Development Magazine

r'\ '

" .. . a única maneira de saber valor de um tutorial é comprovar se ele é eficiente em ensinar. Use a Cabeça! Java sobressai-se ao ensinar. Certo, achei infantil, porém percebi que estava entendendo completamente os tópicos enquanto percorria o livro."
" O estilo de Use a Cabeça! Java tornou o aprendizado, digamos, mais fácil."

o

- slashdot (resenha de um alternativo sério)

"Além do estilo atraente que o conduzirá de leigo ao status de defensor exaltado da Java, Use a Cabeça! Java aborda várias questões práticas que outros livros deixam de lado, como o temível 'exercício para o leitor... ' . É inteligente, ousado, moderno e prático - não existem muitos livros que conseguem alegar isso e sustentar a alegação enquanto ensinam a serialização deobjetos e . protocolos de inicialização de rede."

.- Dr. Dan Russell, Diretor do Use r Sciences and Experience Research mM Almaden Research Center (e que ensina Inteligência Artificial na Universidade de Stanford)

"É rápido, irreverente, divertido e interessante. Tome cuidado - você pode realmente aprender algo!"
.. '.'
~

.....-."

- Ken Arnold, ex-engenheiro sênior da Sun Microsyst~ms Co-autor de "A Linguagem de Programação Java" (com James Gosling, criador do Java)

I

"I

"A tecnologia Java está em todos os lugares - se você for desenvolvedor de softwares e não tiver aprendido Java, definitivamente 'chegou a hora de mergulhar - de cabeça."

- Scott McNealy, Presidente, conselheiro e CEO da Sun Microsystems

"Use a Cabeça! lava é como o Monty Python encontrando a gangue dos quatro ... O texto é tão bem dividido por quebra-cabeças e histórias. testes e exemplos, que você abordará terreno como em nenhum outro livro de computação." - Douglas Rowe, Grupo de Usuários Java de Columbia

11111111m~ 11111 111m 11011l1li1111 gll
LlV 33661 Reg.100289 Use a cabeça ! Java '005.133 JAVA S571u 2005 2.ed.
"f
,,~

~
~

--éx.2S--·

."';
.

~ .h

.I

........__________________________________ ________
~

t\

....
Elogios a Use a Cabeça! Java

sÊscÊ- ----1 S!8L10TECA -I

"Leia Use a Cabeça! Java e você passará a experimentar novamente a diversão ao aprender... Para pessoas que gostam de aprender novas linguagens, e não têm experiência em ciência da computação e programação, este livro é uma jóia.. . É um livro que torna divertido o aprendizado de uma linguagem de computador complexa. Espero que haja mais autores querendo deixar o velho molde dos estilos de escrita 'tradicionais'. Apreuder linguagens de computação deve ser divertido e não difícil."
- Judith Taylor, Southeast Ohio Macromedia User Group

"I
r-.. I
' --'"

"Se você quer aprender Java, não procure mais: bem-vindo ao primeiro livro técnico baseado em GUls! Este formato inovador e bem-elaborado fornece benefícios que outros textos sobre Java simplesmente não conseguem .. . Prepare-se para uma jornada · realmente notável pelo universo do Java."
- Neil R. Bauman, Capitão & CEO, Geek Cruises (www.GeekCruises.com)

=1
~ I1
" I

"Se você for relativamente iniciante em programação e estiver interessado em Java, aqui está seu livro ... Abordando tudo, dos objetos à criação de interfaces gráficas de usuário (GUI, graphical user inteiface), da manipulação de exceções (erros) às redes (soquetes) e segmentação múltipla, e até mesmo o empacotamento de sua pilha de classes em um arquivo de instalação, este livro é bem completo .. . Se você aprecia esse estilo, estou certo de que amará o livro e, como eu, desejará que a série Use a Cabeça! se estenda a muitos outros assuntos! "
- LinuxQuestions.org

"Fiquei viciado nos contos, códigos comentados, entrevistas engraçadas e exercícios mentais."
- Michael Yuan, autor, Enterprise J2ME

" 'Use a Cabeça! Java' ... dá um novo sentido à frase de marketing 'Há sempre um O'Reilly para isso'. Adquiri este livro porque várias pessoas que respeito o descreveram com termos como 'revolucionário' , dizendo que era uma abordagem totalmente diferente para um livro. O resultado é engraçado, irreverente, atual, interativo e brilhante ... Ler este livro é como sentar na sala de espera de uma conferência, aprendendo - e rindo - com colegas ... Se você quiser ENTENDER Java, compre-o."
- Andrew Pollack, www.thenorth.com

"Se há alguém no mundo familiarizado com o conceito de 'Use a Cabeça! ', provavelmente sou eu. Este livro é tão bom, que me casmia com ele na TV! "
- Rick Rockwell, comediante noivo original do programa de televisão da Fox "Who wants to marry a millionaire"

°

"Esse negócio é tão estranhamente bom que me faz querer CHORAR! Estou perplexo."
- Floyd Jones, autor sênior de textos técnicoslPoolboy, BEA

"A lguns dias atrás recebi minha cópia de Use a Cabeça! Java de Kathy Sierra e Bert Bates. Li apenas parte do livro, mas o que me surpreendeu é que, mesmo não tendo conseguido dormir naquel a primeira noite, me vi pensando: 'Certo só mais uma página, ent.ão irei para a cama. '"
- Joe Litton

a introdução

Elogios a outros livros da série Use a Cabeça! de co-autoria de Kathy e Sert
A Amazon escolheu Use a Cabeça! Servlets como Tap Ten Editor's Choice for Computer Books of 2004 (prim~ira edição) A Software Development Magazine indicou Use a Cabeça! Servlets e Use a Cabeça! Design Patterns como finalistas do lS'hAnnual Product Excellence Awards

'" .
"Sinto-me como se milhares de livros tivessem sido tirados de cima de minha cabeça."

- Ward Cunningham, inventor do Wiki e fundador do Hillside Group

"Ri, chorei, fiquei comovido."

- Dan Steinberg, editor-chefe, java.net

"Minha primeira reação foi rolar no chão de tanto rir. Depois de me refazer, percebi que este livro não é apenas altamente preciso, e sim que se trata da melhor obra de introdução já publicada sobre padrões de projeto."

- Dr. Timothy A. Budd, professor associado de ciência da computação na Universidade do Estado do Oregon e autor de vários livros, inclusive C++ for Java programmers
.........

"O tom preciso para o codificador genial e casual guru que existe em todos nós. A obra de referência certa para estratégias práticas de desenvolvimento - este livro me fez acompanhar o assunto sem a necessidade de agüentar a ultrapassada e cansativa ladainha acadêmica."

- Travis Kalanick, fundador do Scour and Red Swoosh e membro do MIT TRIOO

"FINALMENTE - um livro sobre Java escrito da maneira que eu escolheria se eu fosse eu mesmo . Falando sério - este livro definitivamente deixa para trás qualquer outro livro sobre s01tware que já li ... Um bom livro é muito difícil de escrever; é preciso muito tempo para deixar as coisas se desdobrarem em uma seqüência natural, "orientada ao leitor". É muito trabalhoso. A maioria dos autores claramente não está à altura do desafio. Parabéns à equipe do Use a Cabeça! EJB por um trabalho de primeira classe!

- Wally Flint

"Não poderia imaginar uma pessoa sorrindo ao estudar um livro de TI! Usando os materiais do Use a Cabeça! ElB, acertei bastante (91 %) e consegui um recorde mundial como o mais jovem SCBSD, 14 anos."

- Afsah Shafquat (SCBCD mais jovem do mundo)

"O livro Use a Cabeça! Servlets é tão bom quanto o Use a Cabeça! ElB , que me fez rir E acertar 97% do exame!"

- Jef Cumps, consultor de J2EE, Cronos

- --

- - -----

--

-

,~

~

-------..

r
Use a Cabeça! Java

Do original Head First Java Copyrigh t © 2005 da Prii tora.AJt9. Boe-b-I=t-da. . - . - --Authorized translation Irom English language editiol1, enfitled Head First Java, ISBN 0-596-00920-8, by Kathy Sierra and Berf Bates, published by O 'ReiUy Media, Inc., Copyright © 2003, 2005 by O 'Rei!!)' Media, lnc. PORTUGUESE language edition published by Editora Alta Books, Copyright © 2005 by Editora Alta Books. Todos os direitos reservados e protegidos pela Lei 5988 de 14/12/73. Nenhuma parte deste livro, sem autorização prévia por escrito da editora, poderá ser reproduzida ou transmitida sejam quais forem os meios empregados: eletrônico, mecânico, fotográfico, gravação ou quaisquer outros. Todo o esforço foi feito para fornecer a mais completa e adequada informação, contudo a editora e o(s) autor(es) não assumem responsabilidade pelos resultados e usos da informação fornecida. Recomendamos aos leitores testar a informação, bem como tomar todos os cuidados necessários (como o backup), antes da efetiva utilização. Este livro não contém CD-ROM, disquete ou qualquer outra mídia.
Erratas e atualizações: Sempre nos esforçamos para entregar a você, leitor, um livro livre de erros técnicos ou de conteúdo; porém, nem sempre isso é conseguido, seja por motivo de alteração de software, interpretação ou mesmo quando alguns deslizes constam na versão original de alguns livros que traduzimos. Sendo assim, criamos em nosso site, www.altabooks.com.br. a seção Erratas, onde relataremos, com a devida correção, qualquer erro encontrado em nossos livros. Avisos e Renúncia de Direitos: Este livro é vendido como está, sem garantia de qualquer tipo, seja expressa ou implícita. Marcas Registradas: Todos os termos mencionados e reconhecidos como Marca Registrada e/ou comercial são de responsabilidade de seus proprietários. A Editora informa não estar associada a nenhum produto e/ou fornecedor apresentado no livro. No decorrer da . obra, imagens, nomes de produtos e fabricantes podem ter sido utilizados, e desde já a Editora informa que o uso é apenas ilustrativo e/ou educativo, não visando ao lucro, favorecimento ou desmerecimento do produto/fabricante.

---,
,--..

,

I

r---. I

Produção Editorial Editora Alta Books Preparação e Coordenação: Fernanda Silveira Tradução: Aldir José Coelho Revisão: Gustav Schmid Revisão Técnica: Késsia Nina - Licenciatura em Computação pela Universidade de Brasília (UNB) Diagramação: Eduardo Rodrigues Rio
I ,-.

Impresso no Brasil

o código de propriedade intelectual de r de Julho de 1992 proíbe expressamente o uso coletivo sem autorização dos detentores do direito autoral da obra, bem como a cópia ilegal do original. Esta prática generalizada nos estabelecimentos de ensino, provoca uma brutal baixa nas vendas dos livros a ponto de impossibilitar os autores de criarem novas obras.

Av. Nil o Peçanha. 155, ejs. 110 1 a 11 06 - Castelo Rio de Janeiro - RJ . CEP : 20020- 100 Tel: 2 1 2532-6556/ Fax: 2215-0225
www.aII Llhooks.coOl.br

e-mail : altabooks@altabooks.eom.br

a introdução

Use a Cabeça! Java™
Java que fosse mais interessante do que esperar na fila do DETRAN para renovar sua carteira de habilitação? Talvez seja apenas um sonho .. .

Tradução da segunda edição

Kathy Sierra Bert Bates

a introdução

. À nossa mente, por estar sempre presente
(apesar de .qualquer prova em contrário)

~-~------------------------------------------------------------------

Criadores da série Use a
C~bE3ça!

Bert

Kathy tem interesse no ensino de teoria desde quando era projetista de jogos (criou jogos para a Virgin, MGM e Amblin'). Ela desenvolveu grande parte do formato Use a Cabeça! enquanto ensinava Criação em Nova Mídia no programa de extensão em Estudos de Entretenimento da UCLA. Recentemente foi instrutora mestre na Sun Microsystems, preparando os professores da Sun para ensinar as tecnologias Java mais novas, e foi a principal criadora de vários exames de certificação da Sun para programadores e desenvolvedores Java. Junto com Bert Bates, tem usado ativamente os conceitos do Use a Cabeça! lava para instruir centenas de professores, desenvolvedores e até nãoprogramadores. Também foi a fundadora de um dos maiores sites Web de comunidade Java do mundo, o javaranch.com, e do blog Creating Passionate Users.
Além deste livro, Kathy foi co-autora de Use a Cabeça! Servlets, Use a Cabeça.' ElE e Use a Cabeça! Design Patterns. Em seu tempo livre ela aprecia seu novo cavalo islandês, gosta de esquiar, correr e da velocidade da luz.

Bert é desenvolvedor e projetista de softwares, mas a experiência de uma década em inteligência artificial direcionou seu interesse para o ensino de teoria e para treinamentos baseados em tecnologia. Desde então tem ensinado programação para clientes. Recentemente, foi membro da equipe de desenvolvimento de vários exan1es de certificação em Java da Sun.
Ele passou a primeira década de sua caITeira em softwares viajando pelo mundo para ajudar clientes de radiodifusão como a Radjo New Zealand, o Weather Channel e a Arts & Entertainment Network (A & E). Um de seus projetos favoritos foi construir a simulação completa de um sistema de ferrovias para a Union Pacific Railroad. Bert é um adepto inveterado do player GO e há muito tempo trabalha em um programa Go . Ele é um guitarrista razoável que agora passou para o banjo e gosta de se divertir esquiando, correndo e tentando adestrar (ou ser adestrado por) seu cavalo islandês Andi. Bert foi co-autor dos mesmos livros que Kathy e está trabalhando muito na próxima remessa (consulte o blog para ver as atualizações). Você pode encontiá-Io no servidor Go IGS (sob o login jackStraw).
I

kathy@wickedlysmart:.com

.~.'~

terrapin@wickedlysmart.com

.L
Embora Karh y e Ber! renre m respo nd er o má xim o possível de men sagens el e correio ele trt)nico , () vo lum e ue corres pomJ é nci a e sua agencia ele v iage ns lorn<Í isso Jifíci!. A melh or (mais ráp iJ a) maneira de obter ajuda técn ica com reiação ~() li vro e no ha .\'lunf{' ati vo fórum ue iniciantes Ja va em j avaranch. coll1.

~h
~-

L
.,;: "--'"

iJ

..

----. ...
'""

a introdução

Sumário
Introdução
Il!l

I

Seu cérebro e o Java. Aqui está você tentando aprender algo, enquanto o seu cérebro está lhe fazendo o favor de garantir que o aprendizado não vingue. Seu cérebro está pensando "É melhor deixar espaço para coisas mais importantes, como que animais selvagens evitar e se praticar snowboard pelado é uma má idéia". Portanto, como você fará o seu cérebro pensar que sua vida depende do que você conhecer a respeito do Java?
Para quem é este livro? xxii No que seu cérebro está pensando xxi ii Metaconhecimento xxv Faça o seu cérebro se curvar xxvii Requisitos para ler este livro xxviii Editores técnicos xxx Agradecimentos xxxi xviii xv iii xx xxi xxii xxiv xxv

Aprofu ndando-se

1
Method Party { }

O Java o levará a novas fronteiras. No humilde lançamento para o público como a (suposta) versão 1.02, o Java seduziu os programadores com sua sintaxe amigável , recursos orientados a objetos, gerenciamento de memória e, o melhor de tudo - a promessa de portabilidade. Examinaremos isso rapidamente e escreveremos, compilaremos e executaremos alguns códigos. Falaremos sobre a sintaxe, loops, ramificações e o que torna o Java tão interessante . Mergulhe.
Como a Java funciona Estrutura do código em Java Anatomia de uma classe O método main( ) Loops Ramificação condicional (testes if) Codificando o aplicativo "99 garrafas de cerveja " Parafraseando
Máquinas virtuais

2
5

o

aload_ O

1 invokespecial U <Method java. lang.Object{»

6
6 8
9

1Ir----=;....--

4 return
Bytecode compilado

10 12
13

Bate-papo na fogueira: compilador vs. JVM Exercícios e quebra-cabeças

15

Uma viagem até Objetópolis

"
.........

2
Cão
tamanho raça nome

Ouvi dizer que haveria objetos. No Capítulo 1, colocamos todo o código no método main( ).
Essa não é exatamente uma abordagem orientada a objetos. Portanto, agora temos que deixar esse universo procedimental para trás e começar a criar alguns objetos por nossa própria conta. Examinaremos o que torna o desenvolvimento orientado a objetos (00, object-oriented) em Java tão divertido. Discutiremos a diferença entre uma classe e um objeto. Examinaremos como os objetos podem melhorar sua vida.

r"-

uma classe

Guerra nas Cadeiras (Brad O Adepto de 00 vs. Larry O Usuário de Procedimentos) Herança (uma introdução) Sobrepondo métodos (uma introdução) O que existe em uma classe (métodos, va ri áveis de instância)? Criando seu primeiro objeto Usando main( )
- -- _ ...

-----

muitos objetos

Código do Jogo de Adivinhação . Exe rcícios e quebra-cabeças

20 22 23 24 26 27 28
31

ix

,. . .,.

Conheça suas

variªy~~i~L

.

Existem duas versões de variáveis: primitivas e de referência. Deve haver mais coisas
na vida além de inteiros, strings e matrizes. E se você tiver um objeto DonodeAnimal com uma variável de instância Cão? Ou um Carro com um Motor? Neste capítu lo desvelaremos os mistérios dos tipos usados no Java e examinaremos o que você pode declarar como uma variáve l, o que pode inserir em uma variável e o que pode fazer com ela. E para concluir discutiremos o que acontece realmente na pilha de lixo coletável.

Declarando uma variável (no Java há a preocupação com o tipo) Tipos primitivos ("Quero um duplo com espuma, por favor") Palavras-chave no Java Variáveis de referê ncia (controle remoto de um objeto) Declaração atribuição de objeto Objetos na pilha de li xo coletável

36 36
38

39

41
42

referência de objeto

Matrizes (uma introdução) Exercícios e quebra-cabeças

43
47

Como os objetos se comportam
O estado afeta o comportamento, o comportamento afeta o estado. Sabemos que os objetos têm estado e comportamento, representados pelas variáveis de instância e métodos. Agora examinaremos como o estado e o comportamento estão relacionados. O comportamento de um objeto usa um estado exclusivo dele. Em outras palavras , os métodos usam os valores das variáveis de instância. Por exemplo "Se o cão pesar menos de 27 qui los, grite de alegria, caso contrário .. .". Alteremos alguns estados!
Os métodos usam o estado do objeto (latir diferente) Os argumentos e tipos de retorno do método Passar por valor (a va riável é sempre copiada) Métodos de captura e config uração Encapsulamento (use-o ou arrisque-se a ser humilhado)

r-

I

~J

'I

Passar por va1.or significa

=1

52

53
55 56 57

int
foo.go(x) ;

int
void go(intz) { }

Usando referências em uma matriz Exercícios e quebra-cabeças

60 63

Métodos extra fortes

x
J,

5
A

Aumentemos a força de nossos métodos. Você apredeu sobre as variáveis, brincou com
algun s objetos e escreveu um pequeno código. Mas precisa de mais ferramentas . Como os operadores. E os loops. Pode ser útil gerar números aleatórios. E converter uma string em um inteiro, sim, isso seria avançado. E por que não aprender tudo através da criação de algo real , para vermos como é escrever (e testar) um programa a partir do zero. Talvez um jogo, como o Sink a Dot Com (semelhante à Batalha Naval).

'J~ ,

Construi remos o jogo sink a Dot Com
Construindo o jogo Sink a Dot Com Come ça ndo com o jogo Sin k a Dot Com simp·les (uma versão mais simples)
B

70

71
74 76
77 79 83 84

E
tJ

Escrevendo o código preparatório (pseudocódigo do jogo) Código de teste do Dot Com simples Codifica ndo o jogo Dot Com simples

c
D

N

Cl

P ts.Cpm

Código fin al do Dot Com simples Gerando números aleatórios com Math.random( ) Código predefinido para obtenção de entradas do usuário a parti r da linha de comando Iterando com loops for

E

F

85
88 88

G

As~

Me. om

Convertendo tipos primitivos extensos para um tam anho menor Exercícios e quebra-cabeças

' f:], ;-.........,
-

a introdução

Usando a biblioteca Java

6

Java vem com centenas de classes predefinidas. Você não terá que reinventar a roda se souber como encontrar o que precisa na biblioteca Java, normalmente conhecida como APl Java. Há coisas melhores a fazer. Se você pretende escrever códigos, pode escrever somente as partes que forem exclusivas de seu aplicativo. A principal biblioteca Java consiste em uma piiha gigante de classes apenas esperando para serem usadas como blocos de construção.
Analisando o erro do jogo DotCom simples ArrayList (beneficiando-se da APl Java) Corrigindo o código da classe DotCom Construindo o jogo real (Sink a Dot Com) Código preparatório do jogo real Código do jogo real Expressões booleanas Usando a biblioteca (APl Java) Usando pacotes (instruções importantes, nomes totalmente qualificados) Usando os documentos e livros de referência do APl HTML Exercícios e quebra-cabeças

o

"Bom saber que há uma ArrayList no pacote java.util. Mas como poderia descobrir isso sozinha?"

94 97
102 103 107 108 112 114 114

manual

117
120

Melhor viver em Objetópolis

7

Planeje seus programas com o futuro em mente. E se você pudesse escrever códigos que outra pessoa conseguisse estender, facilmente? E se pudesse escrever códigos que fossem flexíveis, para aquelas irritantes alterações de último minuto nas especificações? Quando chegar ao Plano de Polimorfismo, você aprenderá as 5 etapas para a obtenção de um projeto de classes mais adequado, os 3 truques do polimorfismo, as 8 maneiras de criar um código flexível e, se agir agora - uma lição bônus sobre as 4 dicas para a exploração da herança .
Entendendo a herança (relacionamentos da superclasse e subclasse) Projetando uma árvore de herança (a simulação da classe Animal) Evitando a duplicação de código (usando a herança) / Sobrepondo métodos É-UM e TEM-UM (garota na banheira) O que você herdará de sua superclasse? O que a herança lhe fornecerá realmente? Polimorfismo (usando a referência de um supertipo a um objeto da subclasse) Regras da sobreposição (não mexa nesses argumentos e tipos de retorno!) Sobrecarga do método (nada mais do que a reutilização do nome do método) Exercícios e quebra-cabeças 125 127

127
128 130 133 134 135 138

139
140

Polimorfismo real

8
Object o
Dog d

A herança é apenas o começo. Para explorar 9 polimorfismo, precisamos de interfaces.
Temos que ir além da simples herança e alcançar a flexibilidade que você só conseguirá projetando e codificando em interfaces. O que é uma interface? Uma classe 100% abstrata . O que é uma classe abstrata? Uma classe que não pode ser instanciada, Em que isso é útil? Leia o cap ítulo ...
Con't'erta a class"e
Object em uma ~ cl~sse Cào que vaca sabe ql.! &

= al . get(index ) ;
o;

= (Dog)

Algumas classes simplesmente não devem ser instanciadas Classes abstratas (não podem ser instanciadas) Métodos abstratos (devem ser implementados) O polimorfismo em ação Classe Object (a superclasse final de tudo) Extraindo objetos de uma ArrayList (eles são capturados com o tipo Object) O compilador ve rifica o tipo Referências polimórficas Entrando em cantata com seu objeto interno

147

d . ro am ( ) ;

148 149
151 152 153 156

ae refe-rencía (antes de permitir que v ocê "ch-a um cnétodo) 155 -me
157

xi

Co n,::~e ndo U

Losango Fatal (probl ema de herança múltipla ) Usando interfaces (a melhor solução!) Exercícios e quebra-cabeças

rn! _referência de obj eto (passando mais para ~a i xo n§l árvore de heran ça) 158
162 167

162

Vida e morte de um objeto

9
~~anão

Objetos nascem e objetos morrem. Você é quem manda. Você decide quando e como
construÍ-Ias. Decide quando abandoná-los . O Coletor de Lixo (ge, garbage collector} solicita memória . Examinaremos como os objetos são criados, onde residem e como manter ou abandonálos eficientemente. Isso significa que falaremos sobre o heap, a pilha, o escopo, construtores, superconstrutores, referências. nulas e qualificação para o gc.
êlguem cbamar o
D-,;.cJr be:ns.
mé~oão

go{),

esse obja t o

ab<.~.TldOnddo.

SUIt única: .referencia roí reprogramada pi!J.rõ. um obj e ta Duc:k

A pilha e o heap onde os objetos e as variáveis residem Métodos da pilha Onde as variáveis locais residem Onde as variáveis de instância residem O milagre da criação de objetos Construtores (o código que será executado quando você usar new) Inicializando o estado de um novo objeto Duck (Pato) Construtores sobrecarregados Construtores de superclasse (cadeia de construtores) Chamando construtores sobrecarregados usando this( ) A vida de um objeto Coleta de Lixo (e como tornar os objetos qualificados) Exercícios e quebra-cabeças

172 172

173
174 175, 175

177
179 182 184 187

'd' reaebe\.! U1t: novo objeta Duck" deixando o objeto DllCR c~~~~~ ~l :0 primeiro) abanàonaào~ Agora esse primeí~·o objetc pode ser consideraoo e .1.in:i nado .

189
194

"I

Os números são importantes

10
primei ra instância de kiã (cr íença )

Faça o cálculo. O APl Java tem métodos para valor absoluto, arredondamento, min/max, etc.
Mas e quanto à formatação? Você pode querer que os números sejam exibidos apenas com duas casas decimais ou com pontos em todos os locais corretos. E pode querer exibir e manipular datas, também. E quanto à conversão de uma string em um número? Ou a conversão dEi um número em uma string? Começaremos aprendendo o que significa para uma variável ou método ser estático.

-S~ ----..
"I
__ o

~I

- 1. i

Variáveis estáticas são compartilhadas por todas as instâncias de uma classe.
segunda

Classe Math (você precisa realmente de uma instância dela?) Métodos estáticos Variáveis estáticas Constantes (variáveis estáticas finais) Métodos de Math (random( ), round( ), abs( ), etc.) Classes encapsuladoras (Integer, Boolean, Character, etc.) Auto-inserção Formatação de números Formatação e manipulação de datas Importações estáticas Exercícios

in9"àncía de J:id

198 199
202 204 207 207 209 212 217 220 222

e quebra-cabeças

variáveis de instâncía: uma por instán=ia
Va.ríEl1reis -est á.cicas: u,ma por classe

.

xii

iL -'"

~

.

a introdução

Comportamento arriscado

,

1

Problemas acontecem.

o arquivo não está no local. O servidor está travado.

t

~

Independentemente de quanto você é bom em programação, não é possível controlar tudo. Quando criar um método perigoso, precisará de um código para manipular o que acontecer de errado. Mas como saber quando um método é perigoso? Onde inserir o código que manipulará a situação excepcionaf? Neste capítulo, construiremos um MIDI Music Player, que usará o perigoso APl JavaSound, portanto, é melhor descobrirmos.

Criando um aparelho de som (como o BeatBox) E se você tiver que chamar o código perigoso?
lança uma exceção

226

Exceções dizem "algo inadequado pode ter ocorrido ..." O compilador garantirá (ele verificará) que você fique ciente dos riscos Capturando exceções usando uma instrução try/catch (skatista) Controle do fluxo em blocos try/catch

228 228
229

~".:':, _u

, . ?(---{01--- - - - \ I--CD
chama um

,

~.~ao .

!: F-'iJO".I!"

~."~~.
seu código

-7) ........~~,
classe com
um método

"" """"

O bloco final/y (não importa o que aconteça, desligue o forno!)
Capturando várias exceções (a ordem é importante) Declarando uma exceção (apenas desvie) Manipule ou declare como lei Receita de código (emitindo sons) Exercícios e quebra-cabeças

método perigoso

per igoso

230 233 233 235
239

240
241

247

Uma história muito gráfica
Encare a realidade, você precisa criar GUls. Mesmo se acredita que durante o resto de sua vida escreverá somente código no lado do servidor, cedo ou tarde terá que criar ferramentas e vai querer uma interface gráfica. Dedicaremos dois capítulos às GUls e aprenderemos mais sobre determinados recursos de linguagem, inclusive a Manipulação de Eventos e as Classes Internas. Inseriremos um botão na tela, pintaremos a tela, exibiremos uma figura jpeg e trabalharemos ate mesmo com um pouco de animação.
c la ss MyOu ter Class {

private int x;
claS5 r-1yl nnerCl ass '(

Sua primeira GUI Capturando um evento de usuário Implemente uma interface ouvinte Capturando o evento ActionEvent de um botão Inserindo figuras em uma GUI Dive rsão com paintComponent( ) O objeto Graphics2D

252 254 254 256 258 259

void go () { x= 42 ;

} l/fecha a classe 1n terna

.éJ
inner

} l/fecha a classe externa

Agora os ob j eto s ext e r n o e interno estão intimamente ligaàos .

260
263 266

Inserindo mais de um botão em uma tela Classes internas ao resgate (torne seu ouvinte uma classe interna) Animação (mova-a , pinte-a, mova-a , pinte-a , mova-a, pinte-a ... )

270
273

Esses dois objetos do heap cêm uma ligação espe ci al . O objeco interno ~ode u sar as

Receita de código (pintando figuras ao ritmo de música) Exercícios e quebra-cabeças

variavei s d o objet:. o e x ter no ( e vice - versa j.

278

Trabalhe em seu Swing
O Swing é fácil. A menos que você se importe realmente com o local de cada elemento. O código Swing parece fácil, mas depois de compilar, executar e examiná-lo nos damos conta disto: "ei, isso não deveria estar aí. " O que torna fácil a codificação é o que torna difícil o controle - o Gerenciador de Layout. Más com um pouco de esforço, você pode fazer os gerenciadores de layout se curvarem a sua vontade. Neste capítulo, trabalharemos em nosso Swing e aprenderemos mais sobre os elementos gráficos.
282 Gerenciadores de Layout (eles controlam o tamanho e o local) Três Gerenciadores de Layout (borda, fluxo, caixa) 282 284

xiii

,r-'

'"

/"\
r"'\

F
Os e2ementos das parCE-S

í' ~

~II
L ..~L __ ~__ ~~~~~~J _B~r_d_e~L!!,out(co ntrola cinco regiões) S?,Ç
{ _.

!

___ _ .__ f _ _ _ _ _ Borte ."~ _ _ _:· FlowLayout (controla a ordem e o tamanho preferido)

. n_ _ _ _ _ _

~ ~

___

~'

superior e
:infericr

__..

\

,"'- -

- ~-~-

-

'. ( - - - -

BoxLayout (como no fluxo , mas pode empilhar componentes verticalmente) JTextField (para entrada de usuário de uma linha) JTextArea (para texto de rolagem de várias linhas)

ficar.am com a altura selecionada.
Os

Oeste
t

CE!ltJ:o

. Leste
.!

compone.!ites

JCheckBox (foi feita a seleção?) JList (uma lista de seleção rolável) Receita de código (O código completo - construindo o cliente de bate-papo BeatBox)

da esquerda e da direita ficaram c om a 2argura selecionada.

O fsn::rc :ficárli

cam '-------' l

<)

q".!';

IHlib1:6:Z'

,~====~==~~~==~==~ s~ · >

'----" Exe rcícios e quebra-cabeças

284 286 288 290 290 291 292 293 297

~I
'\
./

'"\~~ .

" "I
('\

"" ~I

-

I

/'-. I

- I
I

Salvando objetos
Os objetos podem ser achatados e reconstituídos. Os objefos possuem estado e comportamento. O comportamento reside na classe , mas o estado reside dentro de cada objeto. Se o seu programa tiver que salvar o estado, você poderá fazê-lo da maneira mais difícil, examinando cada objeto e gravando meticulosamente o valor de cada variável de instância. Ou , da maneira mais fácil, orientada a objetos - simplesmente congele o objeto (serialize-o) e reconstitua-a (desserialize), para que volte ao que era.
serializado

1
Alguma pergunta? desserializ a ão

Salvando o estado do objeto Gravando um objeto serializado em um arquivo Fluxos Java de entra da e saída (conexões e encadeamentos) Serialização de objeto Implementando a interface Serializable Usando variáveis transientes Desserializando um objeto Gravando em um arquivo de texto java.io.File Lendo em um arquivo de texto Dividindo uma string em fichas com split( ) Receita de código Exercicios e quebra-cabeças

302 303 304 305 306 308 309 312 316
317

320 324 326

Crie uma conexão
Conecte-se com o ambiente externo. É fácil. Todos os detalhes de nível inferior de rede são definidos pelas classes na biblioteca java.net. Um dos melhores recursos do Java é que enviar e receber dados através de uma rede é realmente apenas uma atividade de EIS com um fluxo de conexão um pouco diferente na extremidade da cadeia. Neste capítulo criaremos soquetes de cliente. Criaremos soquetes de servidor. Criaremos clientes e servidores. Antes do fim do capítulo, você terá um cliente de bate-papo totalmente funcional com vários segmentos. Dissemos com vários segmentos?
Conexâo de soquete ccm a porta 5000 pare
o
S0r:1;~:Ldcr

de Ewde.reço lP;;. J60if .1 .1 03 .

Visão geral do programa de bate-papo Conectando, enviando e recebendo Soquetes de rede Portas TCP Lendo dados em um soquete (usando BufferedReader) GravéJndo dados em um saquete (üsando PrintWriter) Escrevendo o programa Daily Advice Client Criando um servidor simples Código do Dail y Advice Server Criando um cliente de bate-papo Várias pilhas de chamada Iniciando um novo segmento (crie-o, inicie-o)

330 331 332 332 334 335 336 337
337

.!t, ,

339 343 343

xiv

i
;
-

~

----,-..,'

...:-c",:;.,.
-./11-

a in trodução
A interface Runnable (a tarefa do segmento) Três estados de um novo objeto Thread (novo, executável , em execução) O loop executável em execução Agendador de segmentos (é ele quem decide e não você) Colocando um segmento em suspensão Criando e iniciando dois segmentos Problemas de concorrência : esse casal pode ser salvo?

,
,

""

O problema de concorrência de Ryan e Mônica, em código Bloqueando para gerar atomicidade Todo objeto tem um bloqueio O temível problema da "Atualização Perdida" Métodos sincronizados (usando um bloqueio) Impasse! Código de ChatClient com vários segmentos Código predefinido para SimpleChatServer Exercícios e quebra-cabeças

344 345 346 346 349 350 351 352 355 356 356 358 359 361 362 365

Estruturas de dados
A classificação é instantânea em Java. Você tem todas as ferramentas para coletar e
manipular dados sem ter que escrever seus próprios algoritmos de classificação. O Java Collections Framework tem uma estrutura de dados que deve funcionar para praticamente qualquer coisa que você precisar fazer. Quer manter uma lista que você possa aumentar facilmente? Encontrar algo pelo nome? Criar uma lista que exclua automaticamente todos os dados repetidos? Classificar seus colaboradores por quantas vezes lhe traíram?

Conjuntos Classificando como ArrayList com Collections .sort( )

370
372

U st

Dados genéricos e garantia de tipo Classificando itens que im plementam a interface Comparable Classificando itens com um comparador personalizado O APl de conjuntos - listas, conjuntos e mapas Evitando dados repetidos com HashSet Sobrepondo hashCode( ) e equals( ) HashMap Usando curingas para gerar polimorfismo Exercícios e quebra-cabeças

Map

376 381 384 388 388 390 394 399 400

Lance seu código

17

É hora de pôr em prática. Você escreveu seu código. Testou o código. Aprimorou-o. Você
contou para todo mundo que conhece que, se nunca se deparar com uma linha de código novamente, não haverá problema. Mas, no fim das contas, terá criado uma obra de arte. O negócio funciona mesmo! Porém, fazer o que agora? Nesses dois últimos capítulos, estudaremos como organizar, empacotar e implantar seu código Java. Examinaremos opções de implantação local, semilocal e remota , incluindo arquivos jar executáveis, o Java Web Start, RMI e Servlets. Calma. Alguns dos recursos mais interessantes em Java são mais fáceis de usar do que você imagina.

Opções de implantação Mantenha os arquivos de seu código-fonte e de suas classes separados Criando um arquivo JAR (Java ARchives) executável Processando um arqu ivo JAR executável Insira suas classes em um pacote!
MyApp.jar MyApp.class

404 405 406 407 407
"TVU

Os pacotes devem ter uma esfrUf[jfã a diretório ctuequ ada -é Compilando e executando co m pacotes

A M'

409

xv

mi

Compilando com -d
;;;;o

My Ap~.jál

O

o Java Web Start (JWS) para a implantação na Web
Como criar e implantar um aplicativo JWS Exercícios e quebra-cabeças

410 411 415 417 417

Computação distribuída

1
Cliente ~

Trabalhar remotamente não precisa ser ruim. Certo, as coisas são mais fáceis quando
todas as partes do aplicativo estão em um local, em um heap, com um JVM para regular tudo. Mas nem sempre isso é possível. Ou desejável. E se seu aplicativo manipular cálculos poderosos? E se ele precisar de dados de um banco de dados seguro? Neste capítulo, aprenderemos a usar o surpreendentemente simples Rêmote Method Invocation (RMI) do Java. Também examinaremos rapidamente os Servlets, os Enterprise Java Beans (EJB) e o Jini.

I

" servidor

(/

~. . r ~~

ro U ~l;
~

O Remote Method Invocation (RMI) do Java, na prática, bem detalhado Servlets (uma visão rápida) Enterprise Java Beans (EJB) , uma visão muito rápida Jlnl , o melhor entre todos os truques .

","~~ . ':!I

. \~ \. j

U \

'. Construindo o navegador universal de serviços realmente avançado ~

~ OFim

422 433 438 439 441 450

Apêndice A
O projeto final da receita de código. O código completo do beat box de bate-papo clienteservidor. Sua chance de ser uma estrela do rock .

"" '" "

0.-/

'-./

""
452 456

BeatBoxFinal (código cliente) MusicServer (código servidor)

"
~

,...

--..<.

r--

"

"

Apêndice B
Os dez principais itens que não apareceram no livro. Ainda não podemos soltá-lo no mundo. Temos mais algumas coisas para você, mas é aqui que acaba o livro. E dessa vez é verdade .
Lista dos dez mais

,-

460

xvi

como usar

Introdução
t~

",

.

)l,

~

Â
~ ~
~

Nesta seçã.o$ respondemos
HMas por que

ti

pergunta intrigante:
p.rog.:t\?L~ação

eles colocilram isto em um livro de

em Java?"

~
~

J\
À

,A

.Acc_,
~
,~

xvii

___ AID. ._ _ _ _ _ _ _ __ _ _ _ _ _ _ _ _ __ __ __ _ _ ____ · .

como usar

e.s:e :1\' ::;
- - --

A quem se destina este livro?
Se você puder responder "sim" a todas estas perguntas:

-_._---

----

Q) Você

já programou? aprender Java?

® Quer

~ Prefere conversas estimulantes na hora do jantar a palestras secas,
chatas e técnicas?

Este não é ;üm~obr~ d~ referência. Use a Cabeça! Java é um livro projetado ' para aprendizado. não é . uma enciclopédia de fatos sobre a Java.

/..-....,

Então este livro é destinado a você.

Quem provavelmente deve ficar longe deste livro?
Se você puder responder "sim" a qualquer das perguntas a seguir:
Sua experiência em programação se limita somente à HTML, sem nenhum contato com linguagens de script? (Se você já fez algo com loops ou lógica if/then, conseguirá se virar com este livro, mas somente tags HTML podem não ser o suficiente.)
r-.. .

® Você

é um bom programador de C++ procurando um livro de referência?

~ você tem medo de tentar algo diferente? Prefere fazer um tratamento de
canal a misturar listras e xadrez? Acredita que um livro técnico não pode ser sério se houver a figura de um pato na seção de gerenciamento da memória?

Então este livro não é para você.
[Nota do pessoal de marketing: quem retirou a parte sobre como este livro serve para qua.lqu ..r pessoa com um ·cartão de c r édito válido? E quanto à promoção d e fér ias "Dê uma Java de presente" que di scutimos .•. - Fred.)

r 'I
.......'1

~I

Sabemos em que você está pensando.
"Como isto pode ser um livro sério de programação Java· "Para que todas as figuras?" "Conseguirei aprender realmente dessa forma')" "Estou sentindo cheiro de pizza?"
Seu cérebro acba que I.SSO é importante
&

E sabemos no qu e sua mente está pensando.
Seu cérebro procura novidade. Está sempre procurando, pesquisando, esperando por algo incomum. Ele foi gerado assim e o aj uda a permanecer vivo. Atualmente, há menos probabilidades de você se tornar o almoço de um tigre. Mas seu cérebro ainda está procurando. Só que você não sabe. Mas o que seu cérebro faz com toda as coisas rotineiras , comuns e cotidianas que você encontra? O possívef para evitar que interfiram em sua verdadeira tarefa - gravar as coisas que interessam. Não interessa gravar as coisas irrelevantes; elas nunca passam pelo filtro "é claro que isso não é importante". Como seu cérebro sabe o que é importante? Suponhamos que você saia para a sua caminhada diária e um tigre salte em sua frente; o que aconteceria dentro de sua cabeça? Acionamento dos neurônios. Ativação das emoções. Explosilo química. E é assim que seu cérebro fica sabendo ...
..~ ~I

-I

;j
~I

-,

.;2.

Isso deve ser importante! Não esqueça!
Mas imagine se você estivesse em casa, ou em uma biblioteca. É um local seguro, aconchegante, sem tigres. Você está estudando. Preparando-se para um exame. Ou tentando aprender algum assunto técnico difícil, algo q ue o seu chefe acha qu e vai levar uma semana, dez dias no máximo. Só há um probl ema. Se u cérebro está tentando lhe fazer um grande favor. Está tentando se certificar ele que esse conteúdo obviamenre irrelevante não use recursos escassos. Recursos que seri am melhor utilizados no
XVIII

introducâG

a introduçaõ ·
~

I

armazenamento das coisas realmente importantes . Como os tigres. Como o perigo de incêndio. Como você nunca tentar praticar novamente snowboard de short. . E não há LIma maneira simples de dizer a seu cérebro: "Ei, cérebro, muito obrigado, mas , independentemente de o quanto esse livro seja chato, e de como eu estou registrando esse fato em um nível baixo na escala Richter emocional nesse momento, quero realmente que você guarde isso."

s~~ cérebro acha crue não val e a ;ena guardar ISSC~

Pensamos no leitor de "Use a Cabeça! Java" como um aprendiz.
Mas o que é necessário para aprender algo? Primeiro, você tem que captar, depois se certificar de que não vai deixar isso escapar. Não é apenas empurrar os fatos para dentro de sua cabeça. Com base nas pesquisas mais recentes da ciência cognitiva, da neurobiologia e da psicologia educacional, é preciso muito mais para se aprender do que apenas texto em uma página. Sabemos o que interessa ao seu cérebro.
É preciso chamar .um método no servidor

Alguns dos princípios de aprendizagem da série Use a Cabeça!:

retorno

Destaque o aspecto visual. As figuras são muito mais fáceis de memorizar do que palavras isoladas e tornam o aprendizado mais eficaz (até 89% de melhoria em estudos de lembrança e transferência de Serviço RMI conhecimento). Também tornam as coisas mais inteligíveis. Coloque as remoto palavras dentro ou perto da figura às quais estão relacionadas, em vez de embaixo ou em outra página, e os aprendizes ficarão duas vezes mais aptos do que o normal a resolver problemas referentes ao conteúdo. Use um estilo coloquial e personalizado. Em estudos recentes, alunos se saíram até 40% melhor em testes pós-aprendizado quando o conteúdo se comunicava diretamente com o leitor, usando um estilo coloquial em primeira pessoa em vez de adotar um tom formal. Contar histórias em vez de proferir palestras. Usar linguagem casual. Não se leve tão a sério. Em quem você prestaria mais atenção: em uma companhia estimulante no jantar ou em uma palestra?

o

Faça o aprendiz pensar com mais afinco. Em outras palavras, a menos que você flexione seus neurônios ativamente, não acontecerá muita coisa em sua cabeça. Um leitor tem que estar motivado , engajado, curioso e inspirado a resolver problemas, tirar conclusões e gerar novos conhecimentos. E, para que isso ocorra, você precisa de desafios, exercícios e perguntas que instiguem o pensamento, além de atividades que envolvam os dois lados do cérebro e vários sentidos.
Faz sentido dizer que a banheira É-UM banheiro? Que o banheiro É-UMA banheira? Ou. trata-se de um relacionamento TEM-UM?

Prenda - e mantenha presa - a atenção do leitor. Todos nós já tivemos uma experiência do tipo "quero realmente aprender isso, mas não consigo ficar Sem corpo no método! acordado após a página um". Seu cérebro presta atenção em coisas que são fora do Termine-o com um ponto-a-vírgula comum, interessantes, estranhas, atraentes, inesperadas. Aprender sobre um assunto técnico novo e difícil não precisa ser chato. O cérebro aprenderá muito mais rapidamente se não o for.

}L
.J--~

~ ._emoc~ona1.

,. '

Toque as emoções deles. Agora sabemos que sua habilidade de se lembrar de algo depende muito do conteúdo Você se lembr~rá do que lhe preocupar. Le~1brará quando sentir al~o. Não est.amo~ falando de histórias dramatIcas so15re um memnO e seu (;acllürro:-'E~li:1IIlV" H1Lnd"(')-cle-g'J"l'P~CLm{)s·1-düde, dlversao, de pensamentos do tipo "mas o que é isso?" e do sentimento "so u mais eu!" que surge quando você resolve um enigma, aprende algo que as outras pessoas acham difícil ou percebe que sabe algo que Bob "sou mais técnico que você" da engen haria nc70 sabe .
você está aqui ... xix

.~._______ .J.. ..

....
como usar este ;ív, ()

I

r-..

Metacognição: entendendo o

p~~.?at"D.~nto.

_ _ _ __
,--,

Se você quiser realmente aprender, e quiser fazê-lo mais rápida e efic ientemente, preste atenção em como sua atenção é atraída. Pense em como você pensa. Entenda como aprende. Quase ninguém fe z cursos de metacognição ou teoria do aprendizado quando estava crescendo. Esperavam que aprendêssemos, mas raramente nos ens in avam a aprender. Mas presumimos que, por você estar segurando este livro, deseja aprender Java. E é provável que não queira demorar muito. Para aproveitar este livro ao máximo, ou qualquer livro ou experiência de aprendizagem, tome as rédeas de seu cérebro. Dedique-se a esse conteúdo. O truque é fazer seu cérebro ver o novo material que você está aprendendo como Realmente Importante. Crucial para seu bem-estar. Tão importante quanto um tigre. Caso contrário, você estará em batalha constante, com seu cérebro fazendo o melhor para não deixar o novo conteúdo escapar. Mas exatamente como fazer seu cérebro tratar a Java como se fosse um tigre fanllnto ? Há a maneira tediosa e lenta ou a mais rápida e eficaz. A maneira lenta é através da repetição contínua. É claro que você sabe que pode aprender e se lembrar até do mais chato dos tópicos, se continuar in sistindo nisso . Com um nível suficiente de repetição, seu cérebro pensará: "Isto não parece importante, mas, como ele continua se dedicando à mesma coisa repetidamenre, portanto, suponho que deva ser." A maneira mais rápida é fazer qualquer coisa que aumente a atividade cerebral, principalmente tipos diferentes de atividade cerebral. Os itens da página anterior são grande parte da solução e todoscomprovadamente ajudarão seu cérebro a t.rabalhar a seu favor. Por exemplo, estudos mostram que inserir palavras dentro das figuras que elas descrevem Ce não em algum outro local da página, como em uma legenda. ou no corpo do texto) fará com que seu cérebro tente descobrir como as palavras e a figura estão relacionadas. e isso ocasionará o acionamento de mais neurónios. Maior acionamento de neurónios = mais chances de seu cérebro perceber que isso é algo em que vale a pena prestar atenção e possivelmente memorizar. O estilo coloquial ajuda, porque as pessoas tendem a prestar mais atenção quando percebem que estão em uma conversa, já que se espera que elas acompanhem o assunto e exponham sua opinião. O interessante é que seu cérebro não está necessariamente preocupado com o fato de a "conversa" ser entre você e um livro! Por outro lado , se o estilo da redação for formal e seco, ele a perceberá como se você estivesse assistindo a uma palestra enquanto senta em uma sala cheia de espectadores passivos. Não é preciso ficar acordado. Mas figuras e um estilo coloquial são apenas o começo.

~ I

!

--j

I

Entenda o que fizemos:
Usamos figuras , porque seu cérebro capta estímulos visuais e não texto. No que diz respeito ao cérebro, uma figura realmente vale por 1.024 palavras. E quando usamos texto e figuras em conjunto, embutimos o texto nas figuras , porque o cérebro funciona mais . eficientemente quando o texto está dentro daquilo a que ele se refere e não em uma legenda ou oculto em algum local da redação . Usamos a repetição, dizendo a mesma coisa de diferentes maneiras e por meios distintos , e vários sentidos, para aumentar a chance de que o conteúdo seja codificado em mai s de uma área de seu cérebro. Usamos conceitos e figuras de maneiras inesperadas, porque seu cérebro capta novidades, e empregamos figuras e idéias com pelo menos algum conteúdo emocional, porque o cérebro foi programado para prestar atenção à bioquímica das emoções. Qualquer coisa que fizer você sentir algo terá mais probabilidade de ser lembrada, mesmo se esse sentimento não passar de um a pequena animação, surpresa ou interesse. Usamos um estilo coloquial personalizado, porque seu cérebro foi programado para prestar mai s atenção quando anedita que está ocorrendo uma conversa do que qUqndo acha que você está passivamente assistindo a uma apresentação. Ele fará isso até mesmo quando você esti ver lendo.

~ U

Dog

Seja o compilador

. ........ .~

xx in troduç;;)o

~
. .' ..

~~

Estamos em ENIGMÓPOLlS

~,
-t'I

?;-=-

a introdução

Incluímos mais de SO exercícios, porque seu cérebro foi programado para aprender e lembrar melhor quando vocêfaz coisas e não quando lê. E criamos exercícios desafiadores porém viáveis, porque é isso que a maioria das pessoas prefere.
h

h

J,
I~
I~

Usamos vários estilos de aprendizagem , porque você pode preferi r procedimentos passo a passo, enquanto outra pessqa pode querer ter uma visão geral primeiro e outra deseje apenas ver um exemplo de código. Mas independentemente de sua preferência de aprendizado, todos se beneficiarão em ver o mesmo conteúdo representado de várias maneiras.

DISCRIMINAÇÃO DOS PONTOS
Tudo sobre o Java

J"

Incluímos conteúdo para os dois lados de seu cérebro , porque, quanto mais ele estiver comprometido, maior probabilidade você terá de aprender e lembrar e mais tempo conseguirá se concentrar. Já que trabalhar um lado do cérebro geralmente significa dar ao outro lado a chance de descansar, você pode ser mais produtivo no aprendizado durante um período maior. E incluímos histórias e exercícios que apresentam mais de um ponto de vista, porque seu cérebro foi programado para aprender mai s intensamente quando é forçado a fazer avaliações e julgamentos. Incluímos desafios, com exercícios, e perguntas que nem sempre têm uma resposta direta, porque seu cérebro foi programado para aprender e lembrar quando tem que trabalhar em algo (da mesma forma que você não consegue colocar seu corpo em forma apenas observando pessoas fazendo ginástica). Mas fizemos o melhor que pudemos para assegurar que, quando você estiver se esforçando muito , isso ocorra envolvendo as coisas certas. Que você não gaSte nem mesmo um dendrite extra processando um exemplo difícil de entender ou analisando jargões carregados e complexos ou texto extremamente conciso.

~~ ~Halterofilismo
cerebral

,
J"

Usamos uma abordagem 80/20. Presumimos que, se você estiver tentando obter um PhD em Java, esse não será seu único livro. Portanto, não abordamos tudo. Apenas o que você realmente usará.

Veja o que VOCÊ pode fazer para fazer seu cérebro obedecer.

__________________ K
Q}Tenha calma . Quando mais você entender, menos terá que memorizar. Não leia apenas. Pare e pense. Quando o livro lhe fizer uma pergunta, não passe apenas para a resposta. Imagine que alguém está realmente fazendo a pergunta. Quando você forçar seu cérebro a pensar, mais chances terá de aprender e lembrar.

Fizemos nossa parte. O resto é com você. Essas dicas são um ponto de partida; escute seu cérebro e descubra o que funciona com você e o que não funciona. Tente coisas novas.
Re~::: ...!:.s~ ~ col~ ~ ~a~elade i~ ._

_ _ _ _ _.

@Beba água. Muita . água. . Seu cérebro funcionará me lhor com um bom banho. A desidratação (que pode ocorrer antes mesmo de você sentir sede) diminui a função cognitiva.
Em voz alta. Falar ativa uma parte diferente do cérebro . Se vo cê estiver tentando entender algo, ou aumentar suas chances de se lembrar de algo posteriormente, fale em voz alta. Melhor ainda , tente explicar em voz alta para outra pessoa. Você apre nderá mais rapidamente e pode descobrir particularidades que não tinha percebido ao ler sobre o assunto.

~Fale sobre o assunto.

~L
~h

~Faça os exercícios. Es~reva suas próprias
anotações. . Nós os inserimos, mas se os resolvermos, isso seria como ter outra pessoa f azendo uma prova para você . E não olhe apenas para os exercícios . Use um lápis . Há muitas evidências de que a atividade física durante o estudo pode aumentar o aprendizado. @Leia a parte "Não existem perguntas idiotas" Quero dizer todas. Não são apenas notas laterais elas fazem parte do conteúdo principal! Às vezes as perguntas são mais úteis do que as respostas. leia tudo no mesmo local . Levante-se, estique o corpo, mova -se , mude de cadeira, v á até outra sala. Isso ajudará seu cérebro a sentir algo e não deixará que o aprendizado fique muito ligado a um local específico.

fh
),
:: .

.

.}

~~

~Não

seu cérebro. Preste atenção se seu cérebro está ficando sobrecarregado. Se perceber que começou a ler superficialment e ou a esquecer o que acabou de ler, é hora de fazer um intervalo. Uma ve z que tiver passado de um certo ponto, você não aprenderá com maior rapidez tentando assimilar mais e pode até prejudicar o processo. @Sinta algo! Seu cérebro precisa saber que isso é importante . Envolva ~se com as histórias . Cri e suas próprias legendas para as fotos. Reclamar de uma piada ruim é melhor do que não sentir absolutamente nada.

~Escute

essa ser a última coisa a ser feita antes de você ir para a cama. Ou pelo menos a última ~Digite e execute o código. coisa desafiadora. Digi te e execute os exemplos de código. Em seguida, Parte do aprendizado (principalmente a trans f erência você poderá fazer te stes alterando e aperfeiçoando o código (ou interrompendo - o, o que às ve ze s é a ~____ _ par~ :'..lll.:~ór ia de lon~o prazo) ocorre~á d~pois que VOce recnar o J.lvro . ~eu - c...~uvr€C.l.~ct ue t-empv-- -me--±-hor maneira. de descobr i r () qu.e está re.almente acontecendo). Em exemplos longos de códigos ~ próprio, para continua r processando. Se você captar predefinidos, você pode fazer o download dos algo novo durante e ss e tempo de processamento, parte arquivos -fonte a part ir de j eadjavafirst . com do que acabou de aprender será perdida.
L.U.II

~Deixe

você está aqui ;.

xxi

L:~------

_______________________________________________________________________________________

como usar este U"iT;

r ,"

Requisitos deste livro:

- - - - - - --

Você não precisa ele nenhuma outra ferramenta de desenvolvimento, como um ambiente de desenvolvimento integrado (IDE. Integrated Development Environment). Recomendamos que não use nada a não ser um editor de texto básico até concluir a leitura (e principalmente não antes do Capítulo 16). Um IDE pode lhe proteger ele alguns dos detalhes que são muito importantes, portanto, você se sairá muito melhor aprendendo na linha de comando e, em seguida, após ter compreendido realmente o que está acontecendo, passe para uma ferramenta que automatize parte do processo.

Configurando o Java
- Se você já não tiver um SDK (Software Development Kit) Java 2 Standard Edition 1.5 ou superior, precisará dele. Se estiver trabalhando no Linux, Windows ou Solaris, poderá adquiri-lo gratuitamente em java.sun.com (site Web para desenvolvedores Java). Geralmente não são necessários mais do que dois cliques na página principal para que a página de downloads do J2SE seja acessada. Capture a última versão nela-beta publicada. O SDK inclui tudo que você precisará para compilar e executar o Java. Se você estiver executando o Mac OS X 10.4, o SDK Javajá estará instalado. Ele faz parte do OS X e você não terá que fazer mais nada. Se estiver com uma versão anterior do OS X, terá uma versão desatualizada do Java que servirá para 95% dos códigos deste livro. Nota: este livro foi baseado no Java 1.5, mas por razões desconhecidas ele marketing, logo após o lançamento, a Sun a renomeou como Java 5, embora tenha mantido "IS' como o número da versão no kit do desenvolvedor. Portanto, se você se deparar com Java 1.5, Java 5, Java 5.0 ou "Tiger" (pseudônimo original da versão 5), são todas a mesma coisa. Nunca houve um Java 3.0 ou 4.0 - ele saltou da versão IA para a 5.0, mas você ainda encontrará locais onde é chamado de 1.5 em vez ele 5. Não pergunte por quê. (Ah, e apenas para deixar a situação mais divertida, tanto o Java 5 quanto o Mac OS X 10.4 receberam o mesmo pseudônimo "Tiger", e já que o OS X 10.4 é a versão do Mac OS necessária à execução do Java 5, você ouvirá pessoas falando sobre "Tiger em Tiger". Isso significa apenas Java 5 no OS X 10.4.) - O SDK não inclui a documentação do APl e você precisa dela! Acesse novamente java.sun.com e capture a documentação do APl J2SE. Você também pode acessar os documentos do APl on-line, sem fazer o download,.mas isso é complicado. Acredite. Melhor fazer o download. - Você precisará de um editor de texto. Praticamente qualquer editor de texto pode ser usado (vi, emacs, pico), inclusive os de GUI que vêm com a maioria dos sistemas operacionais. O Bloco de Notas , WordPad, TextEdit, etc., todos servirão, contanto que você se certifique de que eles não acrescentem um ".txC ao final de seu código-fonte. - Quando você tiver feito o download e descompactado, compactado ou seja lá o que for preciso (depende de que versão e para qual sistema operacional), terá que adicionar uma entrada para sua variável de ambiente PATH, que apontará para o diretório bin dentro do diretório Java principal. Por exemplo, se o J2SDK inserir um diretório em sua unidade de disco chamado "j2sdkl.5.0", olhe dentro desse diretório e você encontrará o diretório "bin" onde os arquivos bináJios (as ferramentas) do Java residem. O diretória bin é aquele para o qual você precisará de uma variável PATH, para que, quando digitar:
% javac r

'\

'j

r--. .

" i'
../

r

,,!

,

r
"

,

I

~1

~j
- I

i

na linha de comando, seu terminal saiba como encontrar o compiladorjavac.
Nota: se você ti ver probl emas com sua in stalação. recomendamos qu e acesse javaranch. com e se associe ao fórum Java-Beggining ! Na verdade, você deve fazer isso. lendo ou não problemas. Nota: grande parte dos códigos desle li vro estão di sponívei s em wi ckedl ys mart. com

JJ",
xxii introduçãü

------------------~

t~~~

~~

a introdução
Usmnos urna UNL :fict íci a.

Coisas de última hora que você precisa saber:
Esta é uma experiência de aprendizado e não uma obra de referência. Eliminamos deliberadamente tudo que pudesse atrapalhar o aprendizado, independentemente do que estivéssemos abordando em um certo ponto do livro. E, na primeira leitura, é preciso estudar desde o início, porque o livro faz suposições sobre o que você já viu e aprendeu.

modificada

ê

maia simpLes

Cão
tamanho latir( ) comer ( ) pers eguirGato (

)

Usamos diagramas simples semelhantes à UML.
Se .tivéssemos usado UML pura, você veria algo parecido com Java, mas com sintaxe totalmente errada. Portanto, usamos uma versão simplificada de UML que não entra em conflito com a sintaxe do Java. Se você ainda não conhece UML, não terá que se preocupar em aprender Java e UML ao mesmo tempo.

1
)

J

Não nos preocupamos com a organização e o empacotamento de seu código até o fim do livro.
Neste livro, você pode dar prosseguimento à tarefa de aprender Java, sem se preocupar com alguns dos detalhes organizacionais e administrativos do desenvolvimento de programas em Java. No dia-a-dia, você terá que conhecer - e usar - esses detalhes, portanto, eles foram abordados cuidadosamente. Mas deixamos para o fim do livro (Capítulo 17) . Relaxe enquanto aprecia o Java, tranqÜilamente.
Aponte seu lápis
Você deve executar TODAS as atividades "Aponte seu lápi s"

i:.-...

Os exercícios de fim de capítulo são obrigatórios; os quebra-cabeças são opcionais. As respostas dos dois estão no fim de cada capítulo.
Uma coisa que você precisa saber sobre os quebra-cabeças - eles são enigmas. Como nos enigmas lógicos, nos estimuladores cerebrais, nas palavras cruzadas, etc. Os exerc.ícios estão aqui para ajudar você a praticar o que aprendeu, e é recomendável fazê-los. Os quebra-cabeças são diferentes e alguns deles são bem desafiadores de uma maneira enigmática. Esses quebra-cabeças foram projetados para funcionar como decifradores de enigmas e, provavelmente, você saberá quando encontrar um. Se não tiver certeza, sugerimos que tente fazer alguns deles, mas, independentemente do que acontecer, não . desanime se não conseguir resolver um quebra-cabeça ou se simplesmente não tiver tempo para isso.

L -..,
L
",:1---,

~L

h

t -. ~~

As atividades marcadas com o logo t ipo Exercí c i o ( t éni s d e corrida ) são obrigatóriasl
Não deixe de executá - las r
se

Os exercícios "Aponte Seu Lápis" não têm respostas.
Pelo menos não impressas neste livro. Para alguns deles, não há resposta correta e, em outros, parte da experiência de aprendizado da atividade será você decidir se e quando suas repostas estão corretas. (A lgumas de nossa respostas sugeridas estão disponíveis em wickedlysmart.com.)

quiser mesmo aprender Java.

Os exemplos de código são tão simples quanto possível
É frustrante percorrer 200 linhas de código procurando pelas duas linhas que você precisa entender. A maioria dos exemplos deste livro é mostrada no contexto mais simples possível, para que a parte que você estiver tentando aprender fique clara e fácil. Portanto, não ~spere que o código seja rob usto ou mesmo completo. Isso vai depender de você depois que terminar o livro. Os exemplos do livro foram escritos especificamente para o aprendizado e nem sempre func ion am perfeitamente. .
Se você se deparar com o logoti po Quebra-Cabeças, a atívidade é opcional e, se não
for um apreciaãor de lógi ca

traiç"oeíra ou palavras cruzadas, também não gostará dessas atívidades .

. , -l .... _________
br. ~ ·

você está aqui ~

xxii i

--;

como usar est'3

;:V:d

r I

Editores técnicos
"Todos merecem crédito, mas os erros são respo nsabilidade apenas do autor. .. " Alguém acredita nisso? Estão vendo as duas pessoas que se encontram nesta página? Se você en contrar problemas técnicos. provavelmente será culpa delas. :)
l"alenr ir... Crsttaz

o MINI de Jessíca

i.:le-ssica Sane

\

/
~

I

~ I

.
Jess trabalha na Hewlett-Packard na Equipe de Serviços de Auto-Reparo. Ela se formou em Engenharia da Computação na Villanova University, tem os certificados SCPJ 1.4 e SCWCD e se passaram literalmente vários meses desde que recebeu seu diploma de Mestre em Engenharia de Softwares na Drexel University (uau!). Valentin Valentin Crettaz tem o diploma de Mestre em Ciência da Informação e Computação do Instituto Federal Suíço de Tecnologia em Lausanne. (EPFL). Ele trabalhou como engenheiro de softwares com a SRI International (Menlo Park, CA) e como engenheiro chefe no Laboratório de Engenharia de Softwares do EPFL.

~,

,

rJ
_.{
~(

;:(

-i

Quando não está trabalhando, estudando ou dirigindo seu MINI Cooper S, Jess pode ser encontrada brigando com seu gato pelo novelo enquanto conclui seu último projeto de tricô ou crochê (alguém aí quer um gorro?). Ela é originalmente de Salt Lake City, Utah (não, ela não é mórmon .. . É claro, você deve ter pensado nisso) e atualmente vive perto da Filadélfia com seu marido, Mendra, e dois gatos: Cbai e Sake. Você pode encontrá-la moderando fóruns técnicos em javaranch.com.

Valentin é co-fundador e CTO da Condris Technologies, uma empresa especializada no desenvolvimento de soluções de arquitetura de softwares . Seus interesses em pesquisa e desenvolvimento incluem tecnologias orientadas à apresentação, padrões de projeto e arqu.itetura, serviços Web e arquitetura de software. Além de cuidar de sua esposa, praticar jardinagem, ler e fazer algum esporte, Valentin é moderador dos fóruns SCBCD e SCDJWS no Javaranch.com.Ele tem os certificados SCJP, SCJD, SCBSC, SCWCD e SCDJWS. Também teve a oportunidade de ser o co-autor do Simulador de Exames SCBCD do Whizlabs. (Ainda estamos chocados em vê-lo de gravata).

~

~
_§J.;
xxiv Imrooucso
:li

---------------------------------------

~! I . ~.lt

·~. ~-

a Introdução

h
h

Outras pessoas que merecem (culpa) crédito:
Na O'ReilLy:

h
h

I" h

Muito obrigado a NIike Loukides da O' Reilly, por participar deste projeto e aj udar a formar o conceito Use a Cabeça! em um livro (e série) . Quando esta segunda edição foi para a gráfica, já havia cinco livros Use a Cabeça! e ele esteve conosco em todos. A Tim O'Reilly, por se dispor a entrar em algo completamente novo e diferente. Obrigado ao inteligente Kyle Hart, por descobrir como a série Use a Cabeça.' poderia servir aos outros e por lançá-la. Para concluir, a Eddie Freedman, por projetar a capa da série "com ênfase na cabeça".

Alguns

de

nossos
em

revisores
Ja.va •••

especialistas

Jef Cumps

i"",,
~.

Nossos intrépidos testadores beta e equipe de revisores:

1\ '
1 ___

1 '\
i~ I~

I~

Agradecemos muito ao diretor de nossa equipe técnica no javaranch, .Johannes de Jong. Esta é sua quinta vez trabalhando conosco em um livro Use a Cabeça! e estamos felizes por você ainda estar em contato. Jerr Cumps já.está em seu terceiro livro conosco e continua implacável em achar áreas onde teríamos que ser mais claros ou COlTetos.

1-- .
l~

Corey McGlone. você é ótimo. E achamos que deu as explicações mais claras sobre o javaranch. Você deve perceber que roubamos uma ou duas delas. Jason Menard nos salvou tecnicamente em mais do que apenas alguns detalhes, e Thomas Paul, como sempre, nos forneceu feedback especializado e encontrou os sutis problemas do Java que o resto de nós deixou passar. Jane Griscti conhece Java (e sabe alguma coisa de redação) e foi ótimo tê-la ajudando na nova edição junto com o associado de longa data do javaranch Barry Gaunt. Mailyn de Queiroz nos deu excelente suporte nas duas edições do livro. Chris Jones, John Nyquist, James Cubeta, Terri Cubeta e Ira Becker nos foram de grande ajuda na primeira edição.
Agradecimentos especiais a alguns dos envolvidos na série Use a Cabeça! que nos têm ajudado desde o início: Angelo Celeste, Mjkalai Zaikin e Thomas Durr (twduff.com). E obrigado a nosso fantástico agente, David Rogelberg do StudioB (mas, falando sério, e quanto aos direitos do filme?)
Ira Becker
'rb.omas PaUl

I~
~'I~
-;:.1____
.. 1

.'

"h

' I~ I

Marilyn de Queiroz

Jame

s çubeta

Terr~

.

cubeta

Cbris Jon.es

- - -- ---- -

-

-----

VOG8

esta aqUi

~

xxv

como usar este iivl"Q

Quando você pensou que

nãQb;:nll:~r:iaJ]laj~ :::lgr:::lrlpr.imA.ntos*.

Mais especialistas técnicos em Java que ajudaram na primeira edição (em ordem semialeatória):
Emiko Hori, Michael Taupitz, Mike Gallihugh , Manish Hatwalne, James Chegwidden, Shweta Mathur, Mohamed Mazahim, John Paverd, Joseph Bih, Skulrat Patanavanich, Sunil Palicha, Suddhasatwa Ghosh, Ramki Srinivasan, Alfred Raouf, Angelo Celeste, Mikalai Zaikin, John Zoetebier, Jim Pleger, Barry Gaunt e Mark Dielen.

A equipe dos quebra-cabeças da primeira edição:
Dirk Schrekmann. Mary "Campeã de Cruzadas em Java" Leners, Rodney 1. Woodruff, Gavin Bong e Jason Menard, O Javaranch tem sorte por contar com se~ ap~io.

Outros conspiradores a ·agradecer:
Paul Wheaton, o principal Olientador do javaranch por dar suporte a milhares de aprendizes de Java. Solveig Haugland, instrutora de J2EE e autora de Dating design patterns (Encontrando-se com os padrões de projeto):
,,;

Os autores Dori Smith e Tom Negrino (backupbrain.com), por nos ajudarem a conhecer o mundo dos livros técnicos. Nossos parceiros no clime Head First, Eric Freeman e Beth Freeman (autores de Use a Cabeça! Design Patterns) , por disponibilizarem a BawlsTM para que terminássemos a tempo . Sherry Dorris, por tudo que realmente importa.

!

",,
~I
i

"I ,.
"Ii
;-.,, 1

Os bravos pioneiros que adotaram a série Use a Cabeça!:
Joe Litton, Ross P. Goldberg, Dominic Da Silva, honestpuck, Danny Bromberg, Stephen Lepp, Elton Hughes, Eric Christensen, Vulinh Nguyen, Mark Rau, Abdulhaf, Nathan Oliphant, Michael Bradly, Alex DalTow, Michael Fischer, Sarah Nottingham, Tim Allen, Bob Thomas e Mike Bibby (o primeiro).

"I
~
~I ,.j
\

'!u /
'" O grande número de agradecimelllos se deve ao fato de estarmos teslando a teoria de que todas as pessoas mencionadas nos ilgradecilllentos de um livro comprarão pelo menos uma cópia, provavelm e nt e mais, pensando nos parentes e con hecidos. Se você quiser estar nos agradecimentos de nosso próxim.o li vro e tiver lima família grande, nos e~c rev a.
..',"'-"

xxvi

introdução

---------------------------------------=~.

.ftw=.,.-:, ~~l

'-'---

- 1

1' ''-'' ~

k-"
I

i

1 dê um Mergulho Rápido

r......-.-

Aprofundando-se
Venha, a água está ótima! Mergulharemos direto na criação de um código, em seguida, nós o compilaremos e o executaremos. Falaremos sobre a sintaxe, loops, ramificações e o que torna a. Java tão interessante. Logo você estará codificando.

r-. . T r-.
I

----..
I

o Java o levará a novas fronteiras. No humilde lançamento
para o público como a (suposta) versão 1.02, o Java seduziu os programadores com sua sintaxe amigável, recursos orientados a objetos, gerenciamento de memória e, o melhor de tudo a promessa de portabilidade. A possibilidade de escrever uma vez!
executar em qualquer local exerce uma atração muito forte.

Seguidores devotados surgiram, enquanto os programadores combatiam os erros, limitações e, ah sim, o fato de ela ser muito lenta. Mas isso foi há muito t.empo. Se você for iniciante em Java, tem
: r--..

sorte. Alguns de nós tiveram que passar por algo como andar quase

dez quilômetros na neve e subir montanhas pelos dois lados .(descalços), para fazer até mesmo o applet mais simples funcionar. Mas você pode manipular o mais fácil, rápido e muito mais
poderoso Java atual. .
'

•.
~

este é um novo capítulo

como

(j

~':::\'2

fu nciona

Como o Java funciona

o objetivo é escrever um aplicativo (neste exemplo, um convite de festa interativo) e fazê-lo fu nci onar em
qualquer di spositivo que seus am igos tiverem.

Method Party ( )

Código-fonte do convite de festa

1

#1 <Method . fava . l ang .Object(»

Código-fonte

Cr ie um do cumento para o código - fonte. Use um pro t ocolo estabelecido (nesse caso, a linguagem Java) .

4 ret u rn

Compilador
Execute seu documento em um compilador de c ódigo-f onte. O compilador procurará erros e não deixará você c omp ilar até ter cer t eza de que tu do será executado corretamente.

Saída (código) Máquinas virtuais
O compilado r criará um novo documento, c odi ficado em bytecode Java . Qualqu er dispositivo capaz de executar Java consegui rá interpretar/conve rter esse a r quivo em algo que possa processar. O byt ec ode c ompi lado é dependente da plataforma.

o
Seus a migos não têm uma máquina Java física, mas todos têm uma máquina Java virtual (implementada em software ) sendo exe cu tada dentro de seus aparelhos eletrônicos. A máquina virtual lerá e executará o bytecode.

-;
~I

~I

o que você fará em Java
Você criará um arquivo de código-fonte, compilará usando o compilador javac e, em seguida, executará o bytecode compilado em um a máquina virtualJava.
import java.awc.* impo rt java. awt. event. class ?arty { public void buildlnvite () Frame f = new Fram e() ; Labe l 1 == n ew
Label("Party at Tirn'_s");

Button b : : . new
Sutcon ("Vou bet .. ) ; Buccon c ::::. new
Button ("Shoot me");

t-lethod Party ( ) o aload_ O 1 invokespecial #1 <Method java.lang . Object(» 4 return l1ethod vo id buildlnvi te (J O new #2 <Class java . awt.Fra!T1e>

)

Pane I p = new panel(}; p.addll) ; 1/ mais código aqui.

3 dup 4 invokespec i al #3 <Hethod
java awt Frame(»

Compilador Código-fonte

-.

--

Digite seu código-fonte. Salve como : Party.java

Saída (código)

Máquinas virtuais

o
Execute o programa iniciando a Java Virtual Machi n e (JVM) com o arquivo Party.class. A JVM converterá o bytecode em algo que a plataforma subjacente e ntenda e executará s e u programa.

Compile o arquivo
party.java

executando o javac (o aplicativo do c omp ilador) . Se não houver erros, você terá um segundo documento chamado Party.class O arqu ivo Party . class gerado pelo compilador é composto de byt:ecodes.
F·ssas ..; 71S::.r;;'C\.'S5
qtlC

Código compilado: Party . class

r

'-I

:~i:C·'" a;.
mêS

: E.O

,z:.:...~~~r;:,-~(=.mus

:r~s

se:JaIl.!
Ulll5

wtL

{Ut:Ol."l.a.l
d6

~ ~

t-'açe

~~ai

escrever

código I'Gal

(:;Jlt

brs·ve;

por

enqu~'1tCl/

q'.1ere.mcs apc.::e z

t.er..ha

idé2â

C61Y!O

t ndo

enc3ix;:.;

2 capítulo

'ã. -ro

"O

o

Ç')

o::
L-

Um histórico bem resumido do Java
AÍ\.

.!:
::J

o

::J

Ol

O)

2

E :::1
<tJ) 1:;1

> ctI -, 3.500
IctI

ctI

cu -cu (1) c;
(O)

v

o

'O ctI
ctI

...
(.)

>

o

()

3.000

c. 2.500

Q)

:c

o

2.000 1.500 '1.000

:.õ
ctI 'O

ctI ()

cn Q) 500 cn cn

O

Java 1.02
250 classes
Lenta.
Nome e logotipo in teressante s. Divertida de u sar . uito s erros . Os M applets são o destaque.

~

Java 1.1
500 classes
Um pouco ma is rápida. Mais recursos , mais amigável. Começando a se tornar muito popular. Código de GUI mais adequado .

Java 2 (versões 1.2 2.300 classes
MUito mais rápida.

1.4)

Java 5.0 (versões 1.5 e posteriores)
3.500 classes
Mais recursos, mais fácil de desenvolver.
Além d e ad ici ona r mais de n;lil clas s es comp l ement ares, a Java 5. O (conhecida como "Tiger'j ) acre s cento u alterações sign if icativas à própria l ingu agem, tornando-a maiS j fáCil (pe lo menos em teoria) p ar l os prog r a madores e f ornecendo novo s recu r sos que eram populare; em ou tr a s linguagens.

Po de (em al gumas situações) ser exec ut ada e m velocidades condi zentes . Pro fi ssion al, poderosa. Vem e m três versões: Micro Edition (J2ME), Standard Edit ion (J 2SE) e Enterprise Edition .(J2EE). Torna - se a linguagem preferida para novos ap li cativos empresari ai s (pr incipa lmente os baseados na Web) e móvei s .

~ .. ,(

ç ( ( ( ( ( ( ( (' ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (' ( ( ( ( \ ( ;(

,.J (.(

aponte seu íápis

Tente adivinhar o que cada linha de código está faze ndo ... (As respostas estão na próxima página.) Veja como é fácil escrever código Java.
int size
=

'"'
~

.
'.

27;'
=

String name Dog myDog x if
= =

"Fido";

new Dog(name, si ze);

s i ze - 5; (x < 1 5) myDog.bark(S);

wh ile (x

>

3)

{

myDog.play();

~I
I
I
~ I

,-... !

int[] nurnList = {2 , 4,6,S}; System. out.print("Hello"); System.out.print("Dog: String num " + name);

:'j

=

"S";

:;{
,..--.., 1
~!
- '!

I

int z = In teger .pars e l nt(num) ;

---I

try { readTheFile("myFile . txt" );

catch (F ileNotFoundException ex) System.out.prin t("File no t

{

found .") ;

P: Sei que existem o Java 2 e o Java 5.0, mas existiram o Java 3 e 4? E por que Java 5.0 e não Java 2.0?
As brincadeiras do marketing ... Quando a versão do Java passou de 1.1 para 1.2, as alterações foram tão significativas, que os anunciantes decidiram que precisavam de um "nome" totalmente novo, portanto .começaram a chamá-Ia de Java 2 , ainda que a versão fosse realmente a 1.2. Porém, as versões 1.3 e 1.4 continuaram a ser consideradas como Java 2. Nunca houve o Java 3 ou 4. Começando pelo Java versão 1.5, os anunciantes decidiram novamente que as alterações eram tão significativas, que um novo nome era necessário (e a maioria dos desenvolvedores concordou) , logo, eles avaliaram as opções. O próximo número na seqüência do nome seria "3", mas chamar o Java 1.5 de Java 3 parecia mais confuso, portanto, decidiram nomeá-lo Java 5.0 para usar o "5" da versão "1. 5". Logo, o Java original compreendeu as versões que iam da 1.02 (o primeiro lançamento oficial) às conhecidas simplesmente como "Java". As versões 1.2, 1.3 e 1.4 consistiram no "Java 2". E começando na versão 1.5, ele passou a se chamar "Java 5.0". Mas você também o verá sendo chamado de "Java 5" (sem o ".0") e "Tiger" (seu codinome original) . Não temos idéia do que acontecerá com a próxima versão ...

R:

:)::.
4 capíluio

~~ ';~ L~

.r".

l

dê um Mergulho Rápido

Respostas do exercício
Ainda não é preciso se preocupar em entender tudo isso!
Tudo que se encontra aqui é explicado com maiores detalhes no livro, grande parte nas primeiras 40 páginas . Se o Java lembrar uma linguagem que você usou no passado, alguns desses itens parecerão simples. Ca~o contrário, não se preocupe com isso. Chegaremos lá ...

Veja como é· fácil escrever código Java.
int si ze
=

27;'

declara uma variável de tipo inteiro

ch~da

• size' e lhe atribui o valor 27

Str i ng name = "Fido"; Dog myDog = new Dog (name, x size );

declara uma variável de string de ~aracteres cbamada 'name' e lhe atribuí o valor "Fido" declara a nova v ariável de tipo Dog chamada 'myDog' e cria o novo objeto Dog usando 'name' e 'size'
subtrai 5 de 27 "(valor de 'size') e atribui o valor a uma variável chamada 'x'

=

size - 5;

if (x < 15) myDog.bark(8);

se

X '

(valor = 22) for menor do que 15, informa ao cão (dog) para latir

while (x

>

3)

myDog.p l ay() ;

int[ ] numList = {2 ,4 ,6,8} ; System.out.print ( "Hello") ; System. out.print("Dog: St ri ng num
=

declara a lista de variáveis de tipo inteiro 'numList' e insere :1, 4, 6, 8. nela exibe "Bel.lo"... I'rovave1.mente na 1.inha de comando exibe "Hello Fido" (o valor de 'name' é "Fido") na 1.inba de comando
dec1.ara a variável. de string de caracteres

" + name)

" 8";

'num' e 1.he atribui o valor "S"

int z = I ntege r.parse l nt (num) ;

converte a string de caracteres "8"

DO

valor numérico real 8

try { readTheFi l e ("myF ile. txt" )

tenta fazer algo ••• Pode ser que o que estamos tentando não funcione ...
lê um arquivo de texto chamado "myFile . tx~U (ou pelo menos TENTA ler .0 arquivo ... ) deve ser o fim das "tentativas" , fazer muitas coisas . .. portanto, acho que é l'ossível tentar

catch(FileNotFoundExc e pti on ex) System.out.print("File n ot fo und. " );

aqui deve ser - onde você . saberá se o que tentou não funcionou •. .
se o que tentamos não deu certo, exibiremos "File Dot found u na lillha de comando
parece que tudo que se encontra entre { } é o que deve .ser rei to se a 'tentativa' não funcionar . .•.

Estrutura do código em Java

o que existe em
arquivo-FONTE?

um
p ublic class Dog{

r"
,..-."

Um arquivo de código-fonte (com a extensão .java) contém uma definição de classe . A classe representa uma parte de seu programa, embora um aplicativo muito pequeno possa precisar apenas de uma classe. A classe deve ficar dentro de uma par de chaves.

J

-======.=:1
public class Dog {
void bark ( ) {

classe

I j

,..-."

O que existe em uma CLASSE?
Uma classe tem um ou mais métodos. Na classe Dog, o método bark conterá instruções de como o cão deve latir. Seus métodos devem ser declarados dentro de uma classe (em outras palavras, dentro das chaves da classe).

í! .,

,
>

~

'"'
,..-."

método você está aqui
5

I>

.~

a==---=""",,~~

_ _

~

_ _ _ _ _ _____-_ _

~_-

_ _ __


uma classe Java

o que existe em um MÉTODO?
Dentro das chaves de um método, escreva as in struções de como e le deve ser executado. O código do método é basicamente um conjunto de instruções, e por enquanto você pode considerar o método como se fosse uma função ou procedimento.

nllhl i r

clas-s__ Dog

_{_

void bark ( )

[

instruçãol; instrução2;

i~
instruções

r

Anatomia de uma classe

'" ,
'" i

Quando a JVM começar a ser executada, procurará a classe que você forn eceu na linha de comando. Em seguida, começaGl a procurar um método especialmente escrito que se pareça exatamente com:
public static void main (String[] II seu código entra aqui args) {

;::"1
~:

Depois a JVM executará tudo que estiver entre as chaves { } de seu método principal. Todo aplicativo Java precisa ter pelo menos uma classe e um método main (não um método main por classe, apenas um por aplicativo) . chave de assa é uma
classe (ã.uh) o nome dessa

pública para que todos
po••

=

aama-'. \

\\ Ipublic I~?assll::r:tAPpl t§lol
retorno.. void
s:i..gnl.r~ca

I
I

c1.a sse

! /
que

abertu== ã.e

classe

nome desse
método

.

~

.

\\, \

\,

( abordaremos isso depois)
\
\

não há valor
de retorno

/'

\

\

\
\

arç....:me-nt-os do !1létodo. Ess€ mécoào deve receber uma . d . matr~z e str~ngs , e a matriz se chamará l args J
I

Ipublicllstaticl~§in' ll(stI;"ing[ . l args>l8J
ISystém ~ otit ~prfnt
essa instrução significa exibir ne saída padrão (o padrão é a linha de comando)

\\

I

.
R~lé!"~~~
\

chave de abertura
do método

/

/

/

tl"I

/

a string que voc4 que: exibir

\

~
.

toda instr-üção
DEVE

terminar com

ponto-e - virgu~a!!

[I]:- ~:--

cbave à$ fecnamento do método maín
chave de fechamento

.8

c.1.a sse MyFirsf:App

Não se preocupe em memorizar nada agora. Est e oapítulo é apenas uma. aprese.!'ltação.

Criando uma classe com um método main
Em Java, tudo é inserido em um a classe. Você criará seu arquivo de códi go-fonte (com extensão .Java) e, em seguida, o converterá em um novo arqui vo de classe (com extensão .class). Quando ex'ecutar seu program a. na verdade estará executando um a classe. Executar um program a significa informar à Java Virtual Machine (JVM ) para "carregar a classe Helio e, em seguida , execute seu mé.todo main( ). Continue executando até todo o código de main ter termin ado". No Capítulo 2, nos aprofundare mos no assunto das classes, mas, por enqu anto, você só precisa pensar ni sto : como escrever um código Java de modo que ele seja exectttado? E tudo começa com main( ). O método main ( ) é onde seu programa começará a ser executado. Inde pe ndentemente cio tamanho de !-.eu programa (em outras palavras , não importa quantas c/asses () seu programa vai usar), é preciso que haja um método main( ) que dê início ao processo.

dê um Mergulho Rápido

,
".......

publ ic class
HyF irs t App {

p ubl i c
staci c v o id main (S t ring[]
args) {

I ]
public class MyFirstApp {

System . out .p rint (" I Rul e !") ;
)

I]

)

public static void main (String[] argsl System . out.println("I Rule!") ; System.out .println("The World");

o o

I,......"

t

Salve MyFirstApp . java

Et Compile javac MyFirstApp.java
Execute

Method Par t y ()

o

aload_O

1

i n v okes p e ci a l
#- 1 <Method java.lim;J .Cbject () > 4 return

o ~(~'~'~~]:.,j
getstatic #-2 <Field .

Hethod voi d

' '"

MyFirstApp.class

o que você pode inserir no método main?
Quando você estiver dentro de main (ou de qualquer método), a diversão começará. Você pode inserir todas as coisas que costumam ser usadas na maioria das linguagens de programação parafazer o computador executar algo. Seu código pode instruir a NM a:

A brincadeira

o

fazer algo
Instruções : declarações, atribuições, chamadas de método, int x = 3 ; String name = "Dirk"; x = x * 17; System.out.print("x ' is" + x); double d = Math.random(); II isto é um comentário etc.

- Cada instrução deve terminar com ponto- e - vírgula.

Et

fazer algo repetidamente
Loops: for e while while (x' > 12) x = x - 1;

x = x + 1; - Um comentário de linha única começa com dua s barras .
x

= 22;

II esta linha me incomoda

- A maioria dos espaços em branco não é importante .
x
3

for (int x = O; x < 1 0 ; x = x + 1 ) { System.out.print("x is now " + xl;

E)

fazer algo sob essa condição
Ramificação: testes if/else if (x == 10) ( System.out.print("x must be 10"); else ( System . out.print ( "x isn't 10");

- As variáveis são declaradas com um nome e um tipo (você aprenderá todo s os tipos Java no Cap ítul o 3). Int weight;
II tipo: int, nome: weight

- As classes e mét o dos devem ser definidos dentro de um par de chaves. public void go( )
II o código entra aqui
}

_ _ _...Ji...Jf ,(....~x_ -<- -.J.+-&-+aa-m€-,.-equ.als ~ ~D.i..l':k-'--!)-!)L)'--+-_ _ _ _ _ _ _ "

System . out.println("Gently"); System.out.prin t("thi s line r uns no matt e r what");

você está aqui>

7

aspectos básicos da jav2

while maisBolas = = verdadeiro) continueJogando( );

do-while efor. Você verá todos os loops posteriormente no livro, mas não nesse momento; dessa forma, usemos while por enquan to.
A sintaxe (para não mencionar a lógica) é tão simples, qu e provavelmente você já deve ter adormecido. Contanto que alguma condição seja verdadeira, você fará algo dentro do bloco de loop. O bloco de loop é delimitado por um par de chaves; portanto, o que você quiser repetir terá que estar dentro desse bloco. A principal parte de um loop é o teste condicional. Em Java, o teste . condicional é uma expressão que resulta em um valor booleano - em outras palavras, algo que é verdadeiro oufalso. Se você di sser algo como "Enquanto (while) sorveteNoPote for verdadeiro, continue a tirar" , terá claramente um teste booleano. Há sorvete no pote ou não há. Mas se você dissesse "Enquanto Boh continuar a tirar", não teria realmente um teste. Para fazer isso funcionar, você teria que alterar para algo como "Enquanto Bob estiver roncando ... " ou "Enquanto Bob não estiver usando xadrez ... " .

Iterando e iterando e ... o Java tem três estruturas de loop padrão: ~j)hil e,

Testes booleanos simples

"

Você pode criar um teste booleano simples para verificar o valor de uma variável, usando um operador de comparação como:
< (menor que)

> (maior que)

==(igualdade) (sim, são dois sinais de igualdade)
Observe a diferença entre o operador de atribuição (apenas um sinal de igualdade) e o operador igual a (dois sinais de igualdade). Muitos programadores digitam acidentalmente = quando querem dizer = =. (Mas não você.)
int x = 4; II atribui 4 a x while (x > 3) { II o código do loop será e xecutado porque II x é maior qu e 3 x = x - 1; II ou f i c ar í a mo s e te rnament e no lo op i nt z = 27; /I while (z == 17) II o código do loop não será executado porque II z não é igual a 17

~
A
~

,

,j

,4

.~

Não existem

)(

Perguntas Idiotas

)(

P: Por que temos que inserir tudo em uma classe?
o Java é uma linguagem orientada a objetos (00). Não é como antigamente, quando tínhamos compiladores antiquados e criávamos um arquivo-fonte monolítico com uma pilha .de procedimentos. No Capítulo 2, você aprenderá que uma classe consiste no projeto de um objeto e que quase tudo em Java é um objeto.

'X
)t: )(
~

R:

..

P:
R:

' Tenho que inserir um método main em toda classe que criar?

. ~.

Não. Um programa em Java pode usar várias classes (até mesmo centenas) , mas você pode ter só uma com ' um método main - que fará o programa começar a ser executado. Você pode criar classes de teste, no entanto, que tenham métodos main para testar suas outras classes .

8 capítulo' 1

5~ -::. ~

-

dê um Mergulho Rápido

;- .,
r-..

P: Em minha outra linguagem, posso fazer um teste booleano com um tipo inteiro. Em Java, posso dizer
algo como
int x = 1; while (x) { }

----

I

Não. Um booleano e um inteiro não são tipos compatíveis em Java. Como o resultado de um teste condicional deve ser um booleano, a única variável que você pode testar diretamente (sem usar um operador de comparação) é um booleano. Por exemplo, você pode dizer:
boolean isH o t = true; wh il e ( i sHo t ) {

R:

Exemplo de um loop while
p ublic cl a ss Lo opy { p ub lic static void main (S tri ng [ ] arg s) i nt x = 1; Sy s t em.ou t. pri ntlnl"Antes do Loop"); whil e Ix < 4) ( Sy s tem . ou t.pr i nt lnl "No l o op" ) ; Sys tem. o u t. pr in t lnl"O va l o r d e x é " + x ); x = x + 1; Sys t e m. out.pri nt ln l" Es se é o fi m do loop" ) ;

DISCRIMINAÇÃO DOS PONTOS
- As instruções terminam em ponto-e-vírgula; - Os blocos de código são definidos por um par de chaves {} - Declare uma variável int com um nome e um tipo: int x; - O operador de atribuição é um sinal de igualdade

=

- O operador igual a são dois sinais de igualdade = = - O loop while executará tudo que estiver dentro de seu bloco (definido por chaves), contanto que o teste condicional seja verdadeiro. - Se o teste condicional for falso, o bloco de código do loop while não será executado, e o processamento passará para baixo até o código imediatamente posterior ao bloco do loop. - Coloque um teste booleano entre parênteses: while (X

% java Loopy Antes do Loop No loop O valor de x é 1 ________ Esta é a saída No loop O valor de x é 2 No loop O valor de x é 3 Esse é o fim do loop

<:

=== 4) ( )

Ramificação condicional
Em Java, um teste if é basicamente o mesmo que o teste booleano de um Ioop while -- só que em vez de dizer "while ainda houver cerveja .. .", você dirá "if (se) ainda houver cerveja ... "
c l ass IfTest { p ub li c stati c void mai n (S tri ng[] arg s ) ( int x = 3 ; i f Ix == 3) ( Syst em.ou t .pr i ntlnl"x deve se r i gua l a 3"); System. out . pr i nt ln l" I s s o será exe cu t ado de qualquer f orma ");

% java IfTest x deve ser igual a 3

~ ( ------ saída do códi go

Isso será executado de qualquer forma
'I ,....

O código anterior executará a linha que exibe "x deve ser igual a 3" somente se a condição (x é igual a 3) for atendida. Independentemente de ser verdadeira. no entanto, a linha que exibe "Isto será executado de qualquer forma" será executada. Portanto, dependendo do valor de x, uma ou duas instruções serão exibidas.
--.a inQ~V€1'-G€rv€j a,G0f!.ti.P..u€-a-GodiJ: çar,g!.se

Mas podemos adicionar um a instrução e/se à condição, para podermos dizer algo como "If Cc Jw-çontcirio.J.-p.eg.ue..Illil.is_ceDl.eja...e então continue ... "
9

-

você está aqL-li ...

r-...

r---. r---.

aplicativo Java profissional
class IfTest2 {
pü.blic stat.ic vüid
iúô...L.ú

('

'"
~

I

(--s-t:r--iny[]

ct.rgs)

C-

~

int x = 2; if (x == 3) { System . out.println("x deve ser igual a 3" ) ; else { System.out . println("x NÃO é igual a 3"); System.out.println("Isso será executado de qualquer forma");

.-..

'"
r'"

.

% java IfTest2 x NÃO é igual a 3 Isso será executado de qualquer forma

(~______

nova

seíâ~

........
~

, . Aponte seu lápi s
' ~

r--.

: System.out.PRINTversus ,'Syster'n.,ouLprir:ltLN<., " ,
, .. -" > " .',' ,

Dada a saída:
% java DooBee DooBeeDooBeeDo

.-r-

. ~Se võc~"~restou- aten~ão (~ cI~r~' q~e "prestou), de\le ter notado que n~s ~'áUérnamos ,ehtre:prlrlte prinln" . ! . . . .

,-..,
~

Preencha as lacunas do código:
public class DooBee { public static void main (String[] args) i nt x = 1; ) { while (x < System.out . _ _ ___ _ ("DOO") ; System. out. ("Bee") ; x = x + 1; if
) { (x == System.out . print("Do") ;

"....,

..I -I

:,

Você entendeu a diferença?
em 'prmtln como :'" . t'printnewline), . enquanto .. . ~ ·Sy~f~m.out.print ,continaa -exibindo I'là f 'mesmaJin'lia: Se v'ocê' qú'iser que 'cada '~ois;aque exibir esteja err( sua própria linha, usé println: Se quiser que tudo ' fique ]uritoem' uma ·Iinha, .ul:;e prjnt .
,'~

f 'inha ~ (penS'e

1.~~YS~rín·. o,ut..Prrintln i~, s,êr~ ~!1l~}!?Glv,é!.

{

r-r--.

- 'I
I -I .:)

-..

-

J

~.~ -~ ,~;
...--....: ~I ~

-' j

-

~l

"' _

;:C.'-'

.~

c,-,

~.,-, .

~

~'

-;,

l\ f .

Codificando um aplicativo empresarial real ,
Coiocaremos todas as suas novas aptidões em Java em uso com algo prático. Precisamos de uma classe com um método main( ), um tipo int e uma variável String , um loop vvhile e um teste if. Mais alguns retoques e você estará construindo esse back-end empresarial sem demora. Mas antes examinará o código dessa página e pensará por um instante em como você codificaria esse grande clássico, "99 gaJ.Tafas de cerveja".
public class BeerSong { public static void main (String[J args) int beerNum 99; String word = "bottles"; whil e (beerNum > O) {

{

if (beerNum = = 1) { word = "bottle";

II no singular, como em UMA garrafa.

System . out.println(beerNum + " " + word + " of b eer on the .wall"); System . out.print l n(beerNum + " " + word + " of beer. " ) ; System . out. println ("Take one down.") ; System.out.println("Pass it around."); beerNum = beerNum - 1; if (beerNum > O) { System.out . println(beerNum + " " + word + " of beer on the wall " ); else { System . out .println("No more bottles of beer on the wall"); Ainda há uma pequena fa lha em nosso II fim de else código. E le sel'á compilado e executado, II fim do loop while mas a saída não está 100 % perfeita. Veja II fim d o método main se consegue identificar a falha e cOlTija. fim da classe

} II

,

10

capitulo 1

l

dê um Mergulho Rápido

Segunda de manhã na casa de Sob

Ja~a

no

o despertador de Bob toca às 8:30 da manhã de segunda, como em todos os outros dias da semana. Mas Bob
teve um fim de semana cansativo e procura o botão SNOOZE. E é aí que a ação começa e os aparelhos habilitados com Java despertam.
r-

interior

/
o Java também está a.qui

Primeiro, o despertador envia uma mensagem para a cafeteira: " "Ei, o espertinho está dom1indo de novo, atrase o café em 12 minutos ," A cafeteira envia uma mensagem para a torradeira Motorola™: "Segure a torrada, Bob está tirando uma soneca." Em seguida, o despertador envia uma mensagem para o celular Nokia NavigatoirM de Bob: "Chame Bob às 9 horas e diga para ele que estamos ficando um pouco atrasados ." Para concluir, o despertador envia uma mensagem para a coleira sem fio de Sam (Sam é o cachorro), com um sinal bastante familiar que significa: "Pegue o jornal, mas não espere ser levado para um passeio." Alguns minutos depois, o despertador toca novamente. E mais uma vez Bob aperta o botão SNOOZE, e os aparelhos começam a se comunicar. O despertador toca uma terceira vez. Mas, assim que Bob alcança o botão SNOOZE, o despertador envia o sinal "salte e lata" para a coleira de Sam. Trazido à consciência por esse choque, Bob se levanta, grato por suas aptidões em Java e um pequeno passeio à Radio ShackThI terem melhorado a rotina diária de sua vida. Sua torrada está pronta. Seu café está quente. Seu jornal está esperando. Apenas mais uma maravilhosa manhã na Casa Habilitada com Java.
Manteíga

/

,

/.

A coleira de Sain tem Ja.va

\

Você também pode ter um lar habilitado com Java. Adote uma solução sensata que use Java, a Ethernet e a tecnologia Jini. Cuidado com imitações ao usar outras plataformas "plug and play" (que na verdade significa "conecte e perca os próximos três dias tentando fazer funcionar") ou "portáveis". A irmã de Bob, Betty, testou uma dessas outras plataformas e os resultados foram, digamos, não muito atraentes, ou seguros. Também não deu certo com seu cachorro ...

Essa história poderia ser verdadeira? Sim e não. Embora haja versões de Java sendo executadas em dispositivos, dentre os quais os PDAs, telefones celuhrres (principalmente nos telefones celulares), pagers, alarmes, cartões inteligentes e outros - talvez você não encontre uma torradeira ou coleira com Java. Mas mesmo se você não conseguir encontrar uma versão habilitada para Java de seus aparelhos favoritos , ainda poderá executá-los como se fossem um dispositivo Java, controlando-os através de alguma outra interface (como seu Iaptop) que esteja executando a Java. Isso é conhecido como arquitetura substituta Jini . Sim, você pode ter essa casa dos sonhos de um nerd .
. r'

* IP multicast se você for sistemático com relação a protocolos

r K
1

------

você está aqui

~

11

vamos escrever

L'n1

programa
public class PhraseOMa tic { ·- plibliç - -s-t-a-c-i-e- v·oid luctiIl (String[]

args)

~ I I crie trê s conjuntos d e palav ras onde será feita a seleção . Adicione o que qu i ser!
String[] wordListOne = {"24/7", " várias camadas" , "30.000 pés", " E- to-E", "todos ganham", ."fron t-end", "baseado na web" , " difundido", "inteligente " , "seis sigma", "caminho crítico", "dinâmi co "};

String[] wordListTwo = { "habilitado", "adesivo", "valor agregado", "orientado", "central", "distribuído", agrupado", "solidificado", "independente da máquina", "posicionado", "em rede", "dedicado", "alavancado", "alinhado ", "destinado", "compartilhado", "cooperativo", acelerado " } ; String[] wordListThree = {"processo", "ponto máx imo", "solução", "arquitetura", "habilitação no núcleo", "estratégia", "mindshare " , "portal", "espaço", " v isão", "paradigma", "missão"};

~

Certo, quer dizer que a canção da cerveja não era na verdade um aplicativo empresarial profissional . Ainda precisa de algo prático para mostrar ao chefe? Veja o código da Paráfrase.

II descubr a quantas palav ras e x istem em cada lista int oneLength = wo rdList One . length; int twoLength = wordListTwo.length; int threeLength = wordListThree.length;

6)

II gere trê s números aleatórios int randI = (i nt ) (Mat h.random () * oneLength) ; int rand2 = (int) (Math . random() * twoLength); in t 'rand3 = (int) (Math .random( ) * threeLength);

Nota: quand; você digi tar isso e.ln um e di tor, deixe o código criar sua própria quebra de palavra/linha! Nunca pressione a tecla Return quando estiver digitando uma string (algo entre "aspas"), ou ela não será compilada . Portanto, os hífens vistos nessa página são reais e você pode digité-Ios, mas não pressiona a tecla Enter antes de terminar uma string.

II agora construa uma frase String phrase = wordListOne [r andl] + " " + wordListTwo[rand2] + " " + wordListThree [rand3] ; II e x iba a frase System. out. print l n ("Precisamos de " + phrase);

~

Código da paráfrase
Como funciona
Em resumo, o programa cria três listas de palavras e, em seguida, seleciona aleatoriamente uma palavra de cada uma das três listas e exibe o resultado. Não se preocupe se você não entender exatamente o que está acontecendo em cada li nha. Ora, temos o li vro inteiro à frente, portanto, relaxe. Isso é apenas um rápido paradigma alavancado e destinado a exibir 10.000 metros de independência de máqu ina.

1. A primeira etapa é criar três matrizes de strings - os contêineres que armazenarão todas as palavras. Declarar e criar uma matriz é fáci l; a segui r temos uma pequena:
String[J pets

=

{"Fido",

"Zeus",

"Ein"};

Todas as palavras estão entre aspas (como toda string precisa estar) e foram separadas por vírgulas.

2 . Em cada uma das três li stas (matrizes) , o objetivo é se1ecionar urna palavra aleatória, portanto, temos que
saber quantas palavras existem em cada lista. Se houver 14 palavras em uma lista, precisaremos de um número aleatório entre O e 13 (as matrizes Java começam em zero, logo, a primeira palavra estará na posição O, a segunda na posição 1 e a última na posição 13 em uma matriz de 14 elementos). Uma matriz Java não fará objeções em exiblr seu tamanho imediatamente. Você só precisa perguntar. Na matriz de animais de estimação, diríamos:
i nt x = pets . leng th ;

e agora x teria o valor 3.

12 capítulo í

dê um Mergulho Rápido

3.' Precisamos ele três números aleatórios. O Java vem empacotada, independente,
predefinida e habilitada na memória central com um conjunto de métodos de cálculo (por enquanto, considere-os como funções). O método random( ) retorna um número aleatório entre O e quase 1, portanto, temos que multiplicá-lo pela 'quantidade de elementos (o tamanho da matriz) da lista que estivermos usando. Temos que forçar para que o resultado seja um inteiro (decimais não são permitidos l ) , logo, vamos inserir uma conversão (você verá os detalhes no Capítulo 4). É o mesmo que se tivéssemos um número de ponto t1utuante que quiséssemos converter em um inteiro:
int x = (int) 24.6;

o que precisamos aqui é um ...
Processo destinado e difundido Ponto máximo dinâmico independente da máquina Habilitação no núcleo distribuída e inteligente Mindshare habilitado em 24/7 Visão de 30.00 pés em que todos ganhafT1.Portal em rede seis sigma

I

,-'""""'

I~ I~ !~ I~

h I

4.

Agora construiremos a frase. selecionando uma palavra em cada uma das três listas e unindo-as (além de inserir espaços entre elas). Usaremos o operador "+", que concatenará (preferimos a palavra mais técnica 'unirá') os objetos String. Para selecionar um elemento da matriz, você fornecerá o número do índice (posição) do item que quer usar:
String s pets [Ol; 1/ agora s é a string "Fido" s = s +" " + "é um cão"; II agora s é "Fido é um cão"

1=
I",
I

5. Para concluir, exibiremos a frase na linha de comando e ... voila! Somos do marketing.
Bate-papo na fogueira
~

!~

1,.-.,

i:
I

I

i

~Jj
A Máquina Virtual Java

Conversa de hoje: O compilador e a "Quem é mais importante?

JVM discutem a

questão

o

compilador

i,.-,.

J
j

I~
'

!~

i

·1

O que, você está brincando? Olá. Sou o Java. Sou eu quem efetivamente faz um programa ser executado. O compilador apenas lhe fornece um arquivo. É só. Apenas um arquivo. Você pode imprimir e usá-lo como papel de parede, para acender fogo, forrar a gaiola de pássaros ou seja lá o que for, mas o arquivo não fará nada a menos que eu esteja lá para executá-lo. Não aprecio esse tom. E esse é outro problema, o compilador não tem senso de humor. Lógico, se você tivesse que passar o dia inteiro verificando pequenas violações na sintaxe minuciosamente ... Desculpe, mas sem a minha presença, o que exatamente você executaria? Há uma razão para o Java ter sido projetado para usar um compilador de bytecode, se você não sabe. Se ele fosse uma linguagem puramente interpretada, onde - no tempo de execução - a máquina virtual tivesse que converter código-fonte diretamente de um editor de texto, o programa Java seria executaao a uma velocidade comicamente lenta. O Java já demorou tempo suficiente para convencer as pessoas de que é rápido e poderoso o bastante para a maioria dos trabalhos. Não estou falando que você é, digamos, completamente inútil. Mas convenhamos, o que você faz ? Sério. Não faço idéia. Um programador poderia ape nas escrever bytecode manualmente, e eu o usaria. Você pode ficar sem trabalho em breve, amigo. Desculpe, mas esse é um ponto de vista bem displicente (para não dizer arrogante). Embora seja verdade queteoricamente - você possa executar qualquer bytecode tormatado apropriauameme mesTlTo se ele não· vier dê üm compilador Java, na prática isso é um absurdo . Um

I"

t: j~
j~
.I~

1 "

,l0
I~
!
i~

I~

l° !0 ,
-J".--.-

1 'I~
~0

-

você está aqui»

13

o compilador e a JVM

programador escrevendo bytecode manualmente é como se -- -'-você-executas'se-seu processamentb de palavras usando PostScript pura. E eu apreciaria se nào se dirigisse a mim como "amigo". (Vou continuar insistindo na veia irânica.) Mas você ainda não respondeu minha pergunta, o que faz realmente? Lembre-se de que o Java é uma linguagem fortemente tipificada, o que significa que não posso permitir que as variáveis armazenem dados com o tipo errado. Esse é um recurso de segurança crucial e posso bloquear a grande maioria das violações antes que elas cheguem até você. Além disso Mas algumas ainda passam! Posso lançar exceções ClassCastException e às vezes vejo pessoas tentando ~nserir o tipo errado de coisa em uma matriz que foi declarada como contendo algo diferente e -

Desculpe, mas não terminei. E sim, há algumas exceções de tipo de dado que podem surgir no tempo de execução, mas algumas delas têm que ser permitidas, para que outro recurso Java importante tenha suporte - a vinculação dinâmica. No tempo de execução, um programa Java pode incluir novos objetos que não eram conhecidos nem mesmo pelo programador original, portanto, tenho que permitir um certo nível de flexibilidade. Mas meu trabalho é bloquear qualquer coisa que nunca seria - poderia ser - bem sucedida no tempo de execução. Geralmente consigo saber quando algo não vai funcionar, por exemplo, se um programador tentasse acidentalmente usar um objeto Button como uma conexão de soquete, eu detectaria isso e evitaria que ele causasse danos no tempo de execução.

"\

.

I

OK. Certo. Mas e quanto à segurança? Veja tudo que eu faço com relação à segurança e você fica, digamos, procurando sinais de ponto-e-vírgula? Oooooh, mas que grande risco à segurança! Muito obrigado!

Desculpe, mas sou a primeira linha de defesa, como dizem. As violações de tipo de dado que descrevi anteriormente poderiam danificar um programa se fosse permitido que elas se manifestassem. Também sou eu que impeço as violações de acesso, como, por exemplo, um código que tentasse chamar um método privado, ou alterar um método que - por razões de segurança - não pudesse nunca ser alterado. Impeço as pessoas de mexer em códigos que não tenham permissão para ver, inclusive códigos que tentem acessar dados críticos de outra classe. Demoraria horas , talvez dias, para eu conseguir descrever a importância de meu trabalho.

Não importa. Acabo tendo que fazer a mesma coisa só para me certificar se alguém obteve acesso depois de você e alterou o bytecode antes de executá-lo.

É claro, mas como descrevi anteriormente, se eu não impedisse o que talvez chegue a 99 % dos problemas potenciais, você acabaria travando. E parece que não temos mais tempo, portanto, teremos que voltar a isso em um bate-papo posterior.
Oh, pode contar com isso. Amigo.

14 cap ítulo

r''Ti. ,
dê um Mergulho Rápido

r~

rmãs com código
Um programa Java funcional está todo misturado sobre a porta da geladeira. Você conseguiria reorgani zar os trechos de código para criar um programa Java funcional que produzisse a saída listada abaixo ? Algumas das chaves caíram no chão e são muito pequenas para que as recuperemos, portanto, fique a vontade para adicionar quantas delas precisar!
(

li~~ , ~. .J

I l I"
t
j'

----~-

i i -(-~--------:x: "' ''' 1) -~-------.._
:x: '"
. . Pr 1. n t ( "d ") . x-I; ,

SYst em . out

.~~~~

~
'f
~
}

( x "'= 2) ( S ys tem. o ut.p r int ( "b

c" ) ;

r - --f - ( X ·

1 I I

l

~~~

sy s t e m. ou t .prln

.

t (" a" ) .

'

1
int x

whil e

(x

>

O)

"
,,-.

Cada um dos arquivos Java dessa página representa um arquivo-fonte completo. Sua tarefa é person ificar o compilador e determinar se cada um deles pode ser compilado. Se não ser compilados, como você osconigiria?

B

"
,,-.

r--

A

public static void args) in t x = 5; wh i 1e ( x > 1 x = x - 1;

main(String

[]

r r

"
,,-.

c las s Exer cis e 1b p ublic stat ic v o id main (String a r gs ) ( in t x 1; while x < 10 )

if
[]

( x

<

3)

System.out .p rint1n("sma11

x");

if

x

>

3)

(

('

S yste m. out . pr int ln ( " big

x") ;

c
cla ss Ex er cisel b 'i nt x = 5 ; whi1e ( x > 1

r"
~

x

=

__________________________________

~f i

x - 1; ( x < . 3)
x");

S yst em. out .p rint 1n ("s ma 11

"
r--

I

......,.-..-. .
r-'

i

você está aqui

~

15

'"

L

,--

quebra-cabeça: palavra cruzada

~. nr --~ ~ '. "
~~

~

Cruzadas Java

Agora daremos algo para o lado direito de seu cérebro fazer. É uma palavra cruzada pad rão , mas quase todas as palavras da solução vêm do Capítulo 1. Apenas para que você fique alerta, também incluímos algumas palavras (não relacionadas à Java) do universo tecnológico.

Horizontais
4. Código de linha de comando 6. Ma is uma vez? 8. Não pode seguir dois caminhos 9. Acrônimo do tipo de energia de seu laptop 11. Tipo numérico de variável 12. Acrônimo de um chip 13. Exibir algo 17. Um conjunto de caracteres 18. Anunciar uma nova classe ou método 20. Para que serve um prompt?

.--.,

I

Verticais
1. Não é um inteiro (ou seu barco é um objeto _ _ ) 2. Voltou de mãos vazias 3. As portas estão abertas 4. Depto. de manipuladores de LAN 5. Contêineres de 'itens' 7. Até que as atitudes melhorem 10. Consumidor de código-fonte 12. Não é possível fixá-Ia 14. Modificador inesperado 15. É preciso ter um 16. Como fazer algo 19. Consumidor de bytecode Um programa Java curto é listado a seguir. Um bloco do programa está faltando. Seu desafio é comparar o bloco de código candidato (à esquerda) com a saída que você veria se ele fosse inserido. Nem todas as linhas de saída serão usadas e algumas delas podem ser usadas mais de uma vez. Desenhe linhas conectando os blocos de código candidatos à saída de linha de comando correspondente. (As respostas estão no final do capítulo.) Candidatos : Saídas possíveis:
{
y

Mensagens misturadas

class Test { p ub l ic static void ma i n(String [] args) i n t x = o; int y = o; wh ile ( x < 5 ) {

= x

-

y;

L:;i2'~46
11 34 59

{

X

sY",em + ou,.pr~. ::: X li

J
\\ \ \

1;
+ Y +"
") ;

.,

02 14 26 38 02" '14 36 48 00 11 21 32 42
-~, ~

x
Y
, if

x

} }

=
(

1; Y + ,_ Xi
y

-T

-

}

<5

)

{

11 21 32 44 53

o código

candidato entra aqui

I

if

x = X + 1; ( Y < 3 { x = x - 1;

00 11 23 36 410 02 14 25 36 47

} }
Y

=

Y + 2;
pOS.SIVRfS

Compare ca(ía candidaio com uma das siJldas

16 capítulo

dê um Mergulho Rápido
I

i,..-.,
r--.

I

~QUebra-ca beças na Pisci~.ar-_

I

1:I~

Sua tarefa é pegar trechos de código na pisci na e inseri-los nas linhas em branco do código. Você pode não usar o mesmo trecho mais de uma vez e não terá que empregar todos os trechos. Seu objetivo é criar uma classe qlle seja compilada e executada produzindo a saída listada. Não se engane - esse exercício é mais difícil do que parece .

. .,r--

cl as s PoolPuzzleOne ( public static vo id mainlString int x O; while
)

[J args)

(

(

if(x<l){

r--.

Saída
if

I

)

(

if I x

1 )

(

if

)

(

.,......,
System.out . printlnl"");

x

.,..
.

x < x > x > x <

O 1 1 3 4

x x x

x + 1; x + 2;

x x

2;

-

Nota: Cada trecho código da piscina só ser usado uma vez !
System . out . printl"noys "); System. out .print I "oise "); System . out . printl" oyster "); System. o ut .print I "annoys") ;

,..

") ;
") ; ") ;

~--

,..

-I !0

·1 0

!

i ~

____

você está aqui

~

17

Soluções dos Exercícios______

ímãs com código:
class Shuffle1 { public static void main{String [] args) int x == 3; while (x > O) if (x > 2) System . out.print("a ") ; x = x - 1; System . out.print("-"); if (x == 2) ( System . out.print("b c"); if
(x = =

class PoolPuzzleOne ( public static void main(String [I int x = o; while ( X < 4 ) System.out.print(Ua ");
if(x<l)

args)

System.out.print(U U); System.out.print(Un"); if ( X > 1 ) System.out.print(U oyster"); x x + 2; if x == 1 ) System.out.print(Unoys");
)

"
"-

,.......,
r--.

.--...,
-'""""'

1)

System . out . print("d") ; x = x - 1;

i f ( X<1

-'""""'
r"\ r"\
~

System.out.print(Uoise"); System . out . println("") ; = X + 1;

X

A
class Exercise1b public static void main(Str ing [] args) i nt x = 1; while ( x < 10
x

r
r-

"I

----- ..

I

= x

if

+ 1; ( x > 3)

" "

System.out.println("big x"); Esse código será compilado e e x ecutado (sem saida), mas sem uma linha adicionada ao programa , ele seria processado indefinidamente em um loop 'while' infinito!

B
clas s foo public static void main(String [ ] args) int x = 5; while ( x > 1

x = x - 1; if ( x < 3)
System . out . println( "small
x " ) ;

Candidatos:
y

Saídas possíveis:
22 46
11 34 59

x - y;
y + x; y
+ 2;

Esse arquivo não será compilado sem uma declaração de classe, e não se esqueç a da chave correspondente!

y
y

if( y >

c
class Exerciselb publi c static void main(String[]args) int x = 5 ; while ( x ·> 1 )

02 14 26 38 02 14 36 48

x
y

x + 1; Y + X;

00 11 21 32 42 21 32 42 53 11 23 36 410 02 14 25 36 47

x = x- I;
if ( x < 3) System . out . println("small
x");

if ( y < 5
x =x +

if

y

o código do loop 'while' deve ficar dentro de um método. Não pode ficar s implesmente isolado fora da classe .

y

= y

+ 2;

j.

18 c~p;tu!o 1

.-

~~

'~

~

2 classes

8

objetos

Uma Viagem até Objetópolis

~
i~

l,
·1

Ouvi dizer que haveria objetos. No Capítulo 1, coloca mos todo
,~

o código no método main( ). Essa não é exatamente uma abordagem orientada a objetos. Na verdade ela definitivamente não é orientada a objetos. Bem, usamos alguns objetos, como as matrizes de strings no código da paráfrase, mas não desenvolvemos nenhum tipo de objeto por nossa própria conta. Portanto, agora temos que deixar esse universo procedimental para trás, sair de main( ) e começar a criar alguns objetos por nossa própria conta . Examinaremos o que torna o desenvolvimento orientado, a objetos (00, object-oriented) em Java tão divertido. Discutiremos a diferença entre uma classe e um objeto. Examinaremos como os objetos podem melhorar sua vida (pelo menos a parte dela dedicada à programação. Não podemos fazer muito com relação à moda). Uma vez chegando em Objetópolis, você pode não voltar mais. Envie-nos um cartão-postal.

l~
·1

I~

~ I~

~
~
!~

I~

i

,~

I~

~

Iri

fI~ .J.. ______ I'''''
~

i /,....... i

1..-.

este é um novo capítulo

19

Guerra nas Cadeiras
As especificações

(ou como os objetos podem mudar sua vida)
Era uma vez em uma loja de softwares, dois programadores que receberam as mesmas especificações e a ordem "construam". O Gerente de Projetos Muito Chato forçou os dois codificadores a competirem, prometendo que quem acabasse primeiro ganharia uma daquelas modernas cadeiras Aeron™ que todo mundo no Vale de Santa C lara tem. Tanto Larry, o programador de procedimeritos, quanto Brad, o adepto da 00, sabiam que isso seria fácil. Sentado em sua baia, LaITy pensou: "O que esse pro§rama precisa fazer? de que procedimentos precisamos?". E respondeu "girar e emitir som". Portanto, ele começou a construir os procedimentos . Afinal, o que é um programa além de uma pilha de procedimentos? Enquanto isso, Brad voltou ao restaurante e pensou: "Que itens existiriam nesse programa ... Quem são os principais envolvidos?" Primeiro ele pensou nas Formas Geométricas. É claro que ele considerou outros objetos como o Usuário, o Som e o evento de Clicar. Mas já tinha uma biblioteca de códigos para esses itens, portanto, se dedicou à construção das Formas . Continue a ler para saber como Brad e Larry construíram seus programas e para conhecer a resposta à inquietante pergunta "Mas quem ganhou aAeron?"

t

A cadeira

Na baia de Larry
Como já tinha feito milhares de vezes, Larry começou a escrever seus Procedimentos Importantes. Ele criou rotate e playSound sem demora.
rotate(shapeNum) ( II faz a forma girar 360'

No laptop de Brad dentro do restaurante
Brad criou uma classe para cada uma das três formas
Square

r

I

1 1
ro·ta t e
II có Circle
}

;1
'"'-I
~

r-- ~

1 1

. J ~ -1
I

I;
rotate (
/I có

.

playSound(shapeNum) II u sa shapeNum para p esquis a r II que som AIF reproduzir e executá-lo
}

playSo1.;
II có II de
} }

Triangle r ota te ()
{

IJ

playSou
/I có

II código pa ra gira r um triângul o
}

II de
}
~-"""-,,.~ ~l;;Ji<

p laySound ()

{

li
!I

fi código pa ra rep ro duzi r o arquivo AIF

I / de um triângulo

}

_ .

_J

Larry achou que tinha conseguido. Podia quase sentir as rodas de aço da Aeron rolando embaixo de seu ...
Mas espere! Houve uma alteração nas especificações. "Certo, tecnicamente você venceu. Larry", disse o Gerente, "mas temos que adicionar apenas mais um pequeno item ao programa. Não será problema para programadores avançados como vocês doi s." "Se eu ganhasse uma moeda sempre que ouvisse isso ", pensou Larry, sabendo que alterações nas especificações sem problemas era ilusão. "E mesmo assim Brad parece estranhamento tranqüilo. O que estará acontecendo?" Larry continuou mantendo sua crença de que fazer da man"eira orientada a objetos, embora avançado, era lento. E que, se alguém qui sesse fazê-lo mudar de idéia, teria que fazer isso à fo rça.
20 capítulo 2

eba na d U\:n a am , formatO e f :nas. Havera o as outras on · ba ela . to CO\:n , . a ame ' tela, .lun uár'o ClICar n _e Quando o us s outras formas bif , O\:nO a . de SO\:n . <Tirara c , .,... arquIVO ' d\rz.i.ra UI" repro
t;>

o que foi adicionado às especificações

classes e objetos

Oe volta à baia de Larry

Usando o laptop de Brad na praia
Brad sorriu, tomou um gole de sua marguerita e criou uma nova classe . Às vezes o que ele mai s adorava na 00 era não ser preciso mexer em código que já tivesse sido testado e distribuído. "Flexibilidade, extensibilidade ... " ele pensou, refletindo sobre os benefícios da 00.
Amoeba

o procedimento de rotação ainda funcionaria; o código usava
uma tabela de pesquisa para comparar o argumento shapeNum com a fi gura de uma{orma real. Mas playSound teria que mudar. E o que diabos é um arqui vo .hif?
playSound(shapeNum) ( I I se a forma n ão for urna a meba, II u se shapeNurn para pesqu isar que II som AIF reproduzir e e xecu te- o II ou I I repr oduza o s om .h if da a meba

~--------------------~I ' rotate ()
II c ó digo pa ra girar a ameba

II
I;

h ~
~

Não pareceu ser uma grande idéia, mas ele se sentia desconfortável em alterar código já testado. Entre todas as pessoas, ele sabia que, independentemente do que o gerente de projetos dissesse, as especificações sempre seriam alteradas.

playSound ( )
1/ código para repr odu z ir o n ovo
I I a rqui vo .hif de uma a me ba

Larry acabou alguns minutos na frente de Brad.
(Ah! Tanto barulho por aquela besteira de 00.) Mas o sorriso de Larry desapareceu quando o Gerente de Projetos Muito Chato disse (com esse tom de desapontamento): "Oh. não, não é assim que a ameba deve girar...!" Os dois programadores acabaram escrevendo seu código de rotação dessa forma:

h,

k
h,

'-...,
..

1) determine o retângulo que circula a forma 2) calcule o centro desse retângulo e gire a forma ao redor desse ponto .
Mas a forma de ameba devia girar ao redor de um ponto em uma extremidade, como um ponteiro de relógio . "Estou frito" pensou Larry, visualizando um Wonderbread™ chamuscado. "Porém, hmmm. Eu poderia apenas adicionar outra instrução if/else ao procedimento de rotação e, em seguida, embutir o código do ponto de rotação da ameba. Provavelmente isso não atrapalhará nada." Mas uma voz longínqua em sua mente dizia: "É um grande erro. Você acha honestamente que as especificações não mudarão novamente?"

~

-:1

!

I

f~ 1 _____

i

..'"

ponto d' de Larry e Bra .

ba na versa da ame de rotaçao
~

~o

Onde o pont~ ' a estar. deve(1

de rotaçao

~

da ameba

o que as
especificações esqueceram de mencionar adequadamente

O

-:1/""
~

J

I:
_______________ _______~_ _~
você está aqui
~

1 1"\
I

~~m

l'" _1
r--.

21

era uma vez e-n O;:'jt=lópo:is

____Usando o laptop de Brad em Bl1B espreguiçadeira no Festival de B!uegrass de Ele achou que seria melhor adicionar os pontos de rotação como Telluride argumentos do procedimento de rotação. Grande parte do De volta à baia de Larry
código foi afetada. Teste, compilação, todo o trabalho teve que ser feito novamente. O que funcionava deixou de funci onar.
rotate(shapeNum, xPt, yPt) { II se a forma não for urna ameba, II calcule o ponto central II baseado em um retângulo, II e, em seguida, gire II ou II use xPt e ypt corno II o deslocamento do ponto de rotação II e, em seguida, gire

Sem perder nada, Brad modificou o método de rotação, mas só na classe Amoeba. Ele não tocou no código funcionaljá testado e compilado das outras partes do programa. Para fornecer à classe Amoeba um ponto de rotação, ele adicionou um atributo que todos os objetos Amoeba teriam. Ele modificou, testou e di stribuiu (com tecnologia sem fio) o programa revisto apen as durante o show de Bela Fleck.
Amoeba

r---------------------~I ! in t x point;
int y point; rotate() (
II c ó dig o para girar a ameba / 1 usa n do os pontos x e y

iJ

playSound()
II

código para reproduzir o novo

1/ a rqui vo .hi f d e uma ameba

Então, Brad, o adepto da 00 ganhou a cadeira, certo?
Não tão rápido. Larry encontrou uma falha na abordagem de Brad. E, j á que tinha certeza de que, se ganhasse a cadeira, também se daria bem com a Lucy da contabilidade, tinha que reverter a situação.
Larry: Você tem código duplicado! O procedimento de rotação aparece em todos os quatro itens Shape. Brad: Trata-se de um método e não um procedimento. E essas são classes e não itens. Larry: Não importa, É um projeto estúpido. Você tem que manter quaTro "métodos" de rotação diferentes. Em que isso poderia ser bom? Brad: Oh, acho que você não viu o projeto final. Deixe que eu lhe mostre como a herança da 00 funciona, Larry.

o que Larry queria (ele achava que a cadeira a impressionaria)
Amoeba

o

Procurei o que as quatro classes tinham em comum .

Square

Circle

Triangle

rotate () playSound ()

i.j

j

rotate() playSound ( )

.1

i

rotate () playSound ()

i'1

r otate () playSound ( )

~~-,._ ~ --~ .! - ~ -~
Elas são formas e todas giram e reproduzem som. Portanto, extrai os recursos comuns e os i~seri em uma nova ~ classe chamada Shape. Shape Shape

-~

o

rotate () playSound ( ) ~~~~____~

Superclasse

Em seguida, vincul e i as outras quatro classes de formas à nova classe Shape , em um relacionamento chamado herança.

Você pode ler isso como "Square herda de Shape", "Circle herda de Shape" e assim por dian te. Removi rotate( ) e playSoLlnd( ) das outras formas. portanto, agora há apenas um a cópia a manter.

Square

Amoeba

Diz-se que a classe Shape é a supel'Classe das outras quatro classes. As outras qu atro são as subclasses de Shape. As subclasses herdam os métodos da superclasse. Em outras palav ras, se ({ c/asse Shape Tipa uma fún.c ionalidade, emão, automalic(l/11el1le, as suhclasses terüo essa /TI.esma fúnc ion.alidade .
22 capítuio 2

classes _ objetos

E quanto ao método rotate( ) de Amoeba?
Larry: Não é esse o problema aqui - que a forma de ameba tinha um procedimento de rotação e reprodução de som totalmente diferentes? Brad: Método. Larry: Não importa. Como a ameba pode fazer algo diferente se ela "herda" sua funcionalidade da classe Shape? Brad: Essa é a última etapa. A classe Amoeba sobrepõe os métodos da classe Shape. Portanto, no tempo de execução, a JVM saberá exatamente que método rotate( ) exec utar quando alguém solicitar que o objeto Amoeba gire.
~ Fiz com que a classe Amoeba sobrepusesse os

Shape
ro ta te ()
Superclasse (mais abstrata)

métodos rotate( ) e playSound( ) da superclasse Shape. Sobrepor significa apenas que uma subclasse redefinirá um de seus métodos herdados quando precisar alterar ou estender o comportamento desse método.

Square
.___1

"J

---I
Subclasses (mais específicas)

Métodos de sobreposição

- I

da ameba playSound ( ) Il código de reprodução de som Ilespecífico • da ameba

..-1

I

Larry: Como você "diria" a um objeto Amoeba para fazer algo? Não é preciso chamar o procedimento, desculpe - método, e, em seguida, lhe informar que item girar? Brad: Isso é o que há de mais interessante na 00. Quando for hora. digamos, de o triângulo girar, o código do programa referenciará (chamará) o método rotate( ) no objeto Triangle. O resto do programa não saberá ou se importará realmente em como o tliângulo o fará. E quando você precisar adicionar algo novo ao programa, apenas criará uma nova classe para o novo tipo de objeto, para que os novos objetos tenham seu próprio comportamento.

Sei como um objeto Shape deve se comportar. Sua tarefa é me informar o que fazer e a minha é fazer acontecer. Não

o
O
1

r"

o

você está aqui

!lo--

23

pensando .-

o suspense está me matando.
Amy, que trabalha no segundo andar.

Quem ganhou a cadeira?
.-..

(Sem qu e ninguém so ubesse. o Gerente de Projetos tinha dado as especificações para três programadores.)

. o que você gosta na OO?
"Ajuda a projetar de um modo mais natural. As coisas têm uma maneira de evoluir."
- Joy, 27, engenheir:a de software

poder do cérebro
Hora de ativar alguns neurônios
Você acabou de ler uma hi stória sobre um programador de procedimentos competindo com um programador orientado a objetos. Tivemos uma breve visão geral de alguns conceitos-chave da 00, que incluiu as classes, métodos e atributos. Passaremos o resto do capítulo examinando as classes e objetos (retornaremos à herança e à sobreposição em capítulos posteriores). Baseado no que você viu até agora Ce no que deve s~lber de alguma linguagem orientada a objetos com a qual já trabalhou), faça uma pausa para pensar nestas perguntas: Quais são os itens fundamentais que você terá que considerar quando projetar uma classe Java? Que perguntas terá que fazer para você mesmo? Se pudesse projetar uma lista de conferência para usar quando estiver projetando uma classe, o que incluiria nela?

I

.1

"Não preciso mexer em código que já testei, só para- adicionar um novo recurso.'" - Brad, 32, programador
;"\
'

~!I ri
r

"Gosto do fato de quê os dados eos métodos que os ~t)liz~ ficam Juritos ~m uma cl~sse." .' '.
- Josh, 22, bebedor de cerveja

''A reutilização do código eni outros aplicativos. Quando crio uma nova classe, posso torná-la . flexíyel o suficiente para que seja usada em algo novo pQsteriormente."
- Chris, 39, gerente de projetos

dica metacognitiva
Se você empacou em um exercício, tente falar sobre ele em voz alta. Falar Ce ouvir) ativará uma parte diferente de seu cérebro. Embora isso funcione melhor quando temos outra pessoa com quem discutir, também funciona com animais de estimação. Foi assim que deu imorfismo.

"Não. posso 'acreditar que Chris .disseisso. Ele não . ' "'escreve uma linha de éódigo há 5 .anos."
:Daryl, 44, trabalha para qlr!s__

,-.

,

"Além da cadeira?"
·Amy, 34, programadora

"

Quando você projetar uma classe, pense nos objetos que serão criados com esse tipo de classe. Considere:
- as coisas que
ü

objeto conhece

- as coisas que () obj eto faz
Despertador h o r a Alarme modoAl arme configurarHoraAlarme ( carJtur a1. Ho [CtAlarme ( ) a l a rmeEs!:..iC:1n f i g u rado(
s o n e ca ( )
conhece

carrinhoCompras con t e údoCarrinho ad i c i onarAoCarrinho( remove rDoCa r r i nho( ) passarCai x a ( ) conhece

Botão rótul o cor con fi g u r arCor ( ) conf i gu rarRó t u l o( ) soltar( ) pressionarNovarnente ( conhece

faz

faz

faz
)

classes '? objetos

As coisas que um objeto conhece sobre si mesmo se chamam
- variáve is de instância

h

As coisas que um objeto pode fazer se chamam
- métodos
variáveis de instância (estado) métodos (comportamento)

Canção título artista configurarTítulo( co nfigurarArtista( rep rodu zir ( )
)

conhece

)

faz

As coisas que um objeto conhece sobre ele são chamadas dê variáveis de instância. Elas representam o estado de um objeto (os dados) e podem ter valores exclusivos para cada objeto desse tipo. Considere instância como outra maneira de dizer objeto.
I ,-----

_._~.'

, Aponte seu lápis
Preencha com o que um objeto televisão pode ter que saber e fazer.
Televisão

As coisas que um objeto faz são chamadas de métodos. Quando projetar uma classe, você pensará nos dados que um objeto terá que conhecer sobre si mesmo e também projetará os métodos que operarão sobre esses dados. É comum um objeto ter métodos que leiam ou gravem os valores das variáveis de instância. Por exemplo, os objetos Despertador têm uma variável de instância que armazena a hora de despertar e dois métodos que capturam e configuram essa hora. Portanto, os objetos têm variáveis de instância e métodos, mas essas variáveis de instância e métodos são projetadas como parte da classe.

li
li

variáveis de instância (estado)

I!

métodos (comportamento)

'r'\

Qual é a diferença entre uma classe e um objeto?
~l

,
Cão tamanho r aça

1
,

. '""

uma classe

Uma classe não é um objeto.
(Mas é usada para construí-los.)
Uma classe é o projeto de um objeto. Ela informa à máquina virtual como criar um objeto desse tipo específico. Cada objeto criado a partir dessa classe terá seus próprios valores para as variáveis de instância da classe. Por exemplo, você pode usar a classe Button para criar vários botões diferentes, e cada botão poderá ter sua própria cor, tamanho, forma, rótulo e assim por diante.

: ~1"-""
'::1...,..-.

~1~

l~
J~
-·1
I

' -., ';1' .,. .
;:,J----

"1

muitos objetos

··1

ç
I

,I
~i

I~

I '--~

Jr"

1-

Olhe dessa forma ...

Um objeto seria como um registro de sua agenda de endereços. Uma analogia que poderíamos usar para os objetos seria um conjunto de fichas Rolodex™ não utilizadas. Todas as fichas tem os mesmos campos em branco (as variáveis de instância). Quando você preencher uma ficha , estará criando uma instância (objeto), e as entro.das que criar nessa ficha representarão seu estado.

E T E Nome polimorfismo Telefone 555-0343

Os métodos da classe são as coisas que você pode fazer com uma fich a específica; obterNome( ), alterarNome( ), configurarNome( ), todos poderiam ser métodos da classe Rolodex. Portanto, todas as fichasfúzem. as mesmas coisas (obterNome( ). alterarNome( ), etc.) , mas cada uma conhece coisas exclusi vas sobre si mesma .

-0

~ r--.

J--

..

_--------

25

0~;~V""Iorl,.....

__ "

........... ___ ..... _ _ h:_"- _
VUJC lU

'-JI lal IU V

;:'I:JU t-J I IIIII:JII V

Mas o que é necessário para a criação e uso de um objeto? Você prec isa de duas classes. Uma para o tipo de obj eto que deseja usar (Dog, Alarm Clock, Television , etc. ) e outra para testar sua nova classe. É ria classe testadora que você inserirá o método principal e nesse método main ( ) cri ará e acessará obj etos de seu novo tipo de classe. A classe testadora terá apen as um a tarefa: lestar os método e variáveis de seu novo tipo de classe de objetos. Desse ponto do livro em di ante, você verá duas classes em muitos de nossos exemplos. Uma será a classe real - a classe cujos obj etos realmente queremos usar, e a outra será a classe testadora, que chamaremos de <qualquerQueSejaNomeSuaC/asse>TestDrive. Por exemplo , se criarmos uma classe Bungee, também pi'eci saremos de uma classe BungeeTestDrive. Só a classe <nomeA lgumaClasse> TestDrive terá um método main ( ), e sua única finalidade será criar objetos de seu novo tipo (a classe que não for a de teste) para em seguida usar o operador ponto (.) para acessar os métodos e variáveis dos novos objetos. Faremos tudo isso muito claramente nos exemplos a seguir.
~ Crie sua classe
c lass Dog {
in t si zei String b reed; String n ame ;

o operador ponto (.) lhe dará acesso ao estado e comportamento (variáveis de instância e métodos) de um objeto. Il cri a um novo o bjeto Dog d = new Dog( );
I I solicita que e l e lata usando o II operador ponto na II variável d para chamar bark( ) d.bark( );
II configure seu tamanh o usando II o operador pon to d.size=40;

r

Cão

void bark() { System . out . println("Ruff' Ruff!O);

tamanho raça nome latir(

i

-1 .......,i

i
,.-.
/

---- -I;
! I .'

/'" I
~ Crie uma classe testadora (TestDrive)
cl ass DogTes t Drive { public static void main (String[] args ) { II o código de t es te de Dog entra aqui

/,1
i,

' j
---- . j

I
I

I

~

Em sua classe testadora, crie um objeto e acesse suas variáveis e métodos class DogTestDrive { publ ic static voicl main (String[] args) Dog d = new Dog (); d .si ze 40 ;

~j
"' ~I
-"'I

~i

,. 1

--..: !

{

'i i

,,1

...i),:"',·n;,ôc ,:, ___ "

:1

~

-1

d . bark() ; ~(-------------------------------------

Se você já tem algum código 00 pronto, sabe que não esta mos usand o encapsulamento. Abordaremos esse assunto no Capítul o 4.

~

=1

3
': I

1~

,f-.;.
-- --~

classes

objetos

Criando e testando objetos Movie
class Movie ( String title; String genre; int rating; void playlt () System.out.println("Playing the movie");

public class MovieTestDrive ( public static void main(String[] args) Movie one new Movie(); one.title = "Gone with the Stock"; one . genre = "Tragic"; one .rating = -2; Movie two new Movie(); t'Alo.title = "Lost in Cubicle Space"; two . genre = "Comedy"; two .rating = 5; two . playlt() ; Movie three new Movie(); three . title = "Byte Club"; three.genre = "Tragic but ultimately uplifting"; three . rating = 127;

Aponte seu lápis
title

MOVI E title genre rating playlt(
)

Objeto 1

genre rating

11

i
r
title

A classe MovieTestDrive cria objetos (instâncias) da classe Movie e usa o operador ponto (.) para configurar as variáveis de instância com um valor específico. Ela também referencia (chama) um método em um dos objetos . Preencha a figura à direita com os valores que os três objetos apresentam no fim de main( ).

Objeto 2
rating

title

Objeto 3
rating

Rápido! Saia de main!
Se você estiver em main( ), não estará realmente em Objetópo!is. É adequado um programa de teste ser executado dentro do método main, mas, em um aplicativo 00 real, você precisará de objetos que se comuniquem com outros objetos e não de um método mail1 () estático criando e testando objetos.

As duas finalidades de main:

h

h
- 'Y\"

- testar sua classe real

I

- acionarliniciar seu aplicativo Java
--_ .~ ._-

Um aplicativo Java rcal nada mais é do que-objetos se comunicando com o-;'ltroS objetos. Nesse-caso, comunicar-se significa os objetos chamando os métodos uns dos outros . Na página anterior, e no Capítulo 4,

};

27

------------------------------------

saia logo ciG" ,,?ln examinamos o uso de um método main( ) em uma classe TestDrive separada para c,'ia,' e testEI]" os iihSiOuo, e variáveis àe' omraTlas; -:' No 'CapltTfÍOt\ -examinaremos o uso de uma classe com um método main( ) para iniciar um aplicativo Java real (criando objetos e, em seguida, deixando-os livres para interagir com outros objetos, etc.) No entanto, como um a prévia de como um aplicativo Java real pode se comportar, aqui está um pequeno exemplo. Já que ainda estamos nos estágios iniciais do aprendizado de Java, trabalharemos com um pequeno kit de ferramentas, portanto, você achará esse programa um pouco complicado e ineficiente. Talvez pense no que poderia fazer para aperfeiçoá-lo, e em capítulos posteriores é exatamente isso que faremos . Não Se preocupe se parte do código for confusa; o ponto-chave desse exemplo é que os objetos se comunicam entre si.

-'

o jogo de adivinhação
Resumo:

~

____________ GameLauncher

~ ,0

~

cria

71.J?1

obje t o

o jogo de adivinhação envolve um objeto 'game' e três objetos 'player'. O jogo gera um número aleatório entre O e 9 e os três objetos player tentam adivinhá-lo. (Não dissemos que seria umjogo divertido.)
Classes:
GuessGame.class Player.class GameLauncher.class
GuessGame pI p2 p3

íl
in sté.ncia :ios t.:,.:?E
i
I

#

A lógica:
1) É na classe GameLauncher que o aplicativo é iniciado; ela tem o método main( ). 2) No método main( ), um objeto GLiessGame é criado e seu método startGame() é chamado. 3) É no método startGame() do objeto GuessGame que o jogo i.nteiro se desenrola. Ele cria três j ogadores e, em seguida, "pensa" em um número aleatório (aquele que os jogadores têm que adivinhar). Depois solicita a cada jogador que adivinhe, verifica o resultado e exibe informações sobre o(s) jogador(es) vencedor(es) ou pede que adivinhem novamente.
public class GuessGame Player pI; Player p 2 ; Player p3; public void startGame ( ) pI new Player(); p2 new Player(); p3 new Player(); int guesspl int guessp2 int guessp3
O; O; O;

"-

A

1

~

I

startGame(

)

.,._.[1

Player número guess(
)

l 1

o palpi te óess:;:' j O!:?BÓ\:"T l-'!él.z. ê. c J"HlmeTO
pa]pí t e

1

~

r

;[

---,
A

aLI'ibuí

E1 eles as'

três

. .":;uTid;:.en~'2.;·

C\S

tl" t?s

T'::l. J ~)i t

es

qU<2 os jOÇiadOI'ê-B fornecerãc:
-:1

boolean plisRight boolean p2isRight boolean p3isRight in t

false ; false ; false; (Math . random()
e lll u ln

- .~

targetNumber = (int)

* 10);

~__----------__----__i

System . o ut.println("Estou pensaIldu

número entre ü e 9 ... ")

while(true) { System . out . println("O número a ad iv inhar é " + targetNumber);
pI. gU8 sS ( ) ;
',:,> " '. -:;: ,:

p2 . guess ( ) ; p3 . guess{) i

L- - - - - - - - - - - - - - - - - - - - -- - - - - - - - -- - - - - - -

28

2

-~_ .. ~ .~~ -

~i

c lasses e objetos
guesspl = pl . number ; System. o u t .pr intln("O j ogador um forn e ceu o palpite" + guesspl); guessp2 = p2.number ; System . out.print·ln("O jogador dois forneceu o palpite" + guessp2) guessp3 = p3 . number; System.out.println("O jogador tr ês forneceu o palpite " + guessp3); if (guesspl == targetNumber) plisRight = true;
" .. '1

I

'"

r-\

I

if (guessp2 -- targetNumber) p2isRight = true;
if

(guessp3 -- targetNumber) p3isRight = true;

if (plisRight

II

p2isRight

II

p3isRight)

I~

h
~

h
I~

System.out.println("Temos um vencedor!"); System.out.println("O jogador um acertou? " + plisRight); System.out.println("O jogador dois acertou? " + p2isRight); System.out . println("O jogador três acertou? " + p3isRight); System.out . println("Fim do jogo . "); break; II fim do jogo, portanto saia do loop else ( II devemos continuar porque ninguém acertou! L'u r.n:' pa;'p.i~e. System.out.println("Os jogadores terão que tentar novamente . " ) ; II fim de if /e lse II fim do loop II fim do método Saída (será diferente a cada vez que você executar) II fim da classe

~
-~-<

Executando o jogo de adivinhação
public c lass Player int number = o; II onde entra o palpite public void guess() number = (int) (Math . random() * 10); System.out . print l n("Estou pensando em " + number);

h

I iI

~~

l --

h
I

~

""j,.,
'j

public class GameLauncher { public static void main (String(] args) GuessGame game = new GuessGame() ; game.startGame() ;

l~
-I,"",
ir--

~
.

O Java coleta o lixo

1 =

I .r I r-l~
l~

/ r

J ,. --

Ir--

Sempre que um objeto é criado em Java, ele vai para uma área da memória conhecida como Heap. Todos os objetos - independentemente de quando, onde ou como sejam criados - residem no heap . Mas não se trat a simplesmente de qualquer memória heap como as antigas; na verdade a memória heap Java se chama Pilha de Lixo Coletável. Quando você criar um ob jeto, a Java alocará espaço na memória heap de acordo com quant o ess e objeto específico vai precisar. Um obje t o com, digamos , 15 variáveis de instância, provavelmente preci sará de mais espaço do que um objeto com apenas duas variáveis de instância. Mas o que acontecerá quando você precisar reclamar esse espaç o ? Como você tirará um objeto do heap quando não precisar mais dele? A Java gerenciará essa memória para vo cê! Quando a JVM 'perceber' que um objeto pode nunca mais ser usado, ele se tornará qualifi ca do pa ra a coleta de lixo . E se você estiver ficando com pouco espa ço
na memó ria. ,.
Q

c'9--1. I?tQr de. Lixo será executado

el imin ar.ª-..o3L~.

-( .J: ..':______

ir-1 r-I

objetos inalcançávei s e liberará espaço, para que esse possa ser reutilizado. Em cap ítul os posteriores vo cê aprenderá ma is sobre como isso funciona .

29

não existem í"'c,

~"',

""

~

.

Não existem
E se eu precisar de variáveis e métodos globais? Como conseguirei isso, se tudo precisa estar em uma classe? Não há um conceito de variáveis e métodos 'globais' em um programa Java orientado a objetos, Na prática, entretanto, haverá situações em que você pode querer que um método (ou uma constante) esteja disponível para qualquer código que for executado em qualquer parte de seu programa, Considere o método random( ) do aplicativo da paráfrase; é um método que tem que poder ser chamado de qualquer local. E quanto a uma constante como pi? Você aprenderá no Capítulo 10 que marcar um método como public e static faz com que ele se comporte de maneira semelhante a um método 'global', Qualquer código, de qualquer classe de seu aplicativo, poderá acessar um método estático público, E se você marcar uma variável como public, static e final - terá essencialmente criado uma constante disponível globalmente , Mas como poderia chamar isso de orientado a objetos se ainda é possível tornar globais as funções e dados? Em primeiro lugar, tudo em Java reside em uma classe, Portanto, a constante pi e o método random( ), embora públicos e estáticos, são definidos dentro da classe Math, E você deve se lembrar que esses itens estáticos (semelhantes aos globais) são a exceção em vez da regra em Java , Eles representam um caso muito especial, em que não se tem várias instâncias/objetos,

P·.

Perguntas Idiotas

R:

Um programa Java consiste em uma pilha de classes (ou, pelo menos, uma classe), Em um aplicativo Java, uma das classes deve ter um método main , usado para iniciar o programa, Portanto, como programador, você escreve uma ou mais classes, E essas classes são que você distribuirá, Se o usuário final não tiver uma JVM, você também precisará incluir nas classes de seu aplicativo, para que eles possam executar seu programa, Há vários programas de instalação que permitem incluir nas classes diversos JVMs (digamos, para diferentes plataformas) e inserir tudo em um CDROM, Assim o usuário final poderá instalar a versão correta da JVM (supondo que eles já não a tenham em suas máquinas), E se eu tiver uma centena de classes? Ou mil? Não seria complicado distribuir todos esses arquivos? Posso empacotá-los em um Kit Aplicativo? Sim , seria complicado distribuir uma grande quantidade de arquivos para seus usuários finais, mas você não precisa fazer isso, você pode inserir todos os arquivos de seu aplicativo em um Java Archive - um arquivo .jar- que usa o formato pkzip, No arquivo jar, você poderá incluir um arquivo de texto simples formatado como algo chamado mainfesto, que definirá que classe desse arquivo contém o método mainO que deve ser executado,

P: R:

O que é um programa Java? O que é realmente distribuído?

P:

P:

R:

R:

DISCRIMINAÇÃO DOS PONTOS

-------------m

- A programação orientada a objetos lhe permitiú estender um programa sem ser preci so mexer em código fu nci onal já testado. - Todo código Java é definido em uma classe. - Uma classe descreve como criar um objeto desse tipo de classe. Uma classe é como um projeto. - Um objeto pode cuidar de si próprio; você não preci sa conh ecer ou se importar com a malleiru de ele agir. - Um objeto conhece coisas e faz coisas. - As coi sas que um objeto con hece sobre si próprio se chamam variáveis de instância, Elas representam o estado de um objeto, - As coisas que um objeto faz são chamadas de métodos , Eles representam o comportamento de um objeto , - Quando você criar um a classe, tal vez queira criar ullla classe de teste separada, que usará para gerar objetos de seu novo tipo de classe. - Ullla classe pode herdar variáveis de in stâ ncia e métodos de uma supen:lasse mai s abstra,a. - No tempo de exec ução, um programa Java nada mai s é do qüe objetos 'co liluni ca ndo-se'
COI11

outros ohjelos .

30 c80ituln :2

classes e objetos

U17]él cri

eCO OS 06· 17]0 u 'leto s S 17]él rece élO Co lta. 17]0 Os 6·

eSSe -

.

IScoú

Os.

Seja o compilador Cada um dos arquivos Java dessa página representa um arquivo-fonte completo. Sua taTefa é personificar o compilador e determinar se cada um deles pode ser compilado. Se não puderem ser compilados, como você os corrigiria, e se eles forem compilados, qual seria sua saida?

I

h

A
class TapeDeck { boolean canRecord false; class DVDPlayer ( boolean canRecord

B

false;

void playTape () ( System.out.println("tape playing

U );

void rec ordDVD() ( System . out.println("DVD recording

U );

void recordTape() ( System.out . println("tape recording U

)

;

class DVDPl ayerTes tDrive { public static void main(String [] args) DVDPlayer d = new DVDPlayer (); d.canRecord = true; d.playDVD(); if (d . canRecord d.recordDVD(); true) (

(

class TapeDeckTestDrive ( public static void main(String [J args) t.canRecord = true; t.playTape() ;
i f

(

(t . canRecord true) dTap_ ( ) ; e t . racQr_

{

Ir--,

l~_nz

_ __

_.

você está aqui ..

31

exercício: ímãs com código

fmãs com código
Um programa Java está todo misturado sobre a geladeira. Você conseguiria reconstruir os trechos de código para criar um programa Java funcional que produzisse a saída listada a seguir? Algumas das chaves caíram no chão e são muito pequenas para que as recuperemos, portanto, fiq ue à vontade para adicionar quantas delas precisar!

J

d.pla y snare () ;

I,

DrumKi t
R ,t

d
lA

=

new

DrumKi t () "
4. %
$ i, ._ f ·,~

'"
..--.."

)II@.

~4ji4!~&

boolean boolean

topHat = true; snare = true;

'"'-

--..
void playSnare ( ) System. out. println ("bang bang") ; bang ba-

1 '" ~,
",.J,
J

'"

I

:[

public

static

void

main ( String

[)

args

,---..

,J
':1

.
1

.,

I

:

(d, snare __ I~~ d -- true ) r
1

}

·PlaYS n a r e () .

b

!
d. snare class
=

'

DrumKitTestDrive

{,

DrumKit
FI
~

Ed'! W ' d

H I
~T\~

D
:!::~T"':l-.:;':t;~t-'

~".r

.

ti.",;;,.
-< ' :

Dru~i tTé~iDri V~ ; bang .bang , ba-bang .. ' : ~ ','
%j ava
'<

~;-d i ~~~a~ ~ H~a~t~~(~ ~{~-------------------_____ y~T o:p~ )
• " s y stem. o ut.println (" ding ding da - ding",'

"<f,

' -

d~ng

ding ' da- ~inl:L , "',' :.:/

~. "" :",'

Quem sou eu?
Um grupo de componentes Java, vestido a rigor, está participado do jogo, "Quem sou eu?" em uma festa. Eles lhe darão uma pista e você tentará adivinhar quem são, baseado no que disserem. Se por acaso disserem algo que possa ser verdadeiro para mais de um deles, selecione todos aos quais a frase possa ser aplicada. Preencha as linhas em branco próximas à frase com os nomes de um ou mais candidatos. A primeira é por nossa conta.

~~

~.

Candidatos desta noite: Classe Método Objeto Variável de instância Sou compilado em um arquivo .java. classe _____________________________________________________ Os valores de minha variável de instância podem ser diferentes dos de meu colega. ______________________________ Comporto-me como um modclo. _________________________________ _~_____________________________~
Gosto de fazer coisas. Posso ter muitos métodos. Represento o 'estado'" ___ _____'_______________________________________'_ _____ ___-,-_ _ ~ ~ Odeio comportamentos. 4 Estou situado nos objetos. ~~ Vivo no heap . ________________________________________________________________________~
Coswmocriarins~nc i ~deo~cto. -----------------------------------_______

______

Meu estado pode se alterar. Declaro métodos.

32 capitulo . 2

Posso mudar no tempo de execução.

:i."
h..

;ii ~'

~.

c. .

classes e objetos

~Quebra-cabeças na Pisci~.a~~",
Sua tarefa é pegar os trechos de código da piscina e inseri-los nas linhas em branco do códi go. Você pode usar o mesmo trecho mai s de uma vez e não terá que empregar todos os trechos. Seu objetivo é criar classes que sejam compiladas e exec utadas produzindo a saída l.i stada.

public class EchoTestDrive ( public static void main (String [ ] args ) { Echo e1 int x
= .=

new Echo ( ) ;

O;
)

while (

(

Saída

e1 . hello () ;

if
e2.count
if

)

(

e 2 .c ount + 1;
)

,

(

r
.1

I

e2 .count
x = x + 1;

e2 . count + e1 . count;

I~

t

h
Pergunta adicional!
Se a última linha da saída fosse 24 em vez de 10, como você concluiria o quebra-cabeça?
class int

System.out . println( e2.c ount) ;

,~

l~
I v--.

O;

void System_out . println("helloooo . . _ O);

Nota: Cada trecho de código da piscina

I~

x y e2 count
1 -

x x x x

< < > >

4
5 O 1

I"
I

I,

I~

count + 1 ; e 1_count +

Echo Teste r echo( ) count ( ) hello ( )

x x

3 4

l~ --I" t, ...... -----I

-, ..L,,_
Ir>
I

!

e2 = e1; Echo e2; e2 e1; ' e2 = new Echo(

) ;

voce está aqui
.";".

p.

.33

r>

soluções

Cios

''é' (~ -.

Soluções dos ExercícioS____ _

..1

~Oluções dos quebra-cabeças

- com Imas \ co:d'190:
clas s DrumKit ( boolean topHat = true ; boolean snare = true; void playTopHat() ( System . out.println("ding ding da-ding"); void playSnare() ( System . out . println("bang bang

I
~

Quem sou eu?
Sou compilado em um arquivo .java. classe Os valores de minha variável de instância podem ser diferentes dos de meu colega. objeto Comporto-me como um modelo. classe

ba-ban~");

Gosto de fazer coisas. objeto, método Posso ter muitos métodos. classe, objeto

class DrumKitTestDrive ( public static void main(String [] args) DrumKit d = n ew DrumKi t(); d.playSnare() ; d . snare = false; d.playTopHat(); if (d . snare == true) d.playSnare() ;

Represento o 'estado ' . variável de instância
(

Odeio comportamentos. objeto, classe Estou situad o nos objetos. método, variável de instância Vivo no heap. objeto Costumo criar instânci as de objeto. classe Meu estado pode se alterar. objeto, variável de instância Declaro métodos. classe

Seja o compilador:
class TapeDeck { boolean canRecord = fal se; void playTape() ( System . out . println("tape playing"); void recordTape() ( System . out . println("tape recording");
~

Posso mudar no tempo de execução. objeto, variável de instância
Nota: di z-se que tanto as classes quanto os objetos possuen estado e comportamento. Eles são definidos na classe, mas também são considerados parte do objeto. Por enquanto, não vamos nos preocupar com a questão técnica de ond e eles residem.

A

clas s TapeDeckTestDrive ( public static void main(String [] args) { TapeDeck t = new TapeDeck( ); t.canRecord = true; Temos o modelo, t . pl ayTape () ; agora t 'emos que if (t .c anRecord == true) criar um t .recordTape() ; objeto!

Quebra-cabeça da piscina
public class EchoTestDrive public static void main(String [] args) { Echo e 1 new Ech o() ; Echo e2 new Echo(); II a resposta correta
- ou -

B

class DVDPlayer { boolean canRecord = false; void recordDVD() { System. out .pr intln ("DVD recording"); void playDVD ( ) { System.out .pr'intln("DVD playing");

Echo e2 el; II a da pergunta adicional! int x = O; while (x < 4 ) e1. helI o ( ) ; el.count = el.count + 1;
if
(x

== 3 )
=

e2 . count if (x > O) { e2 . count

e2.count + 1;

e2 .count + e1 . count ;

l~o!!~~:~ad~~!a~~~lt~~o7ão
class DVDPlayerTestDrive { public s ta tic void main (St ri ng [J args) DVDPlayer d = new DVDPlayer(); d . canRecord = true; d . playDVD() ; if (d . canRecord == true) d .recordDVD( ) ;

~--------------~ [f
(
~

seria

I'
~

x = x + l i

System . out.println(e2 . count);

I
i ,
i
~

t

class Echo { int count = O; v.oid helIo ( ) ( System . out . println("helloooo ...

");

34

capítulo 2

.(' ~:
\

::=.-F ,-

3

variáveis primitivas e

referência

Conheça suas Variáveis

/""'

)

A

Existem duas versões de variáveis: primitivas e de referência. Até agora você usou variáveis em duas situaçõescomo estado do objeto (variáveis de instância) e como variáveis
locais (variáveis declaradas dentro de um método). Posteriormente,

usaremos variáveis como argumentos (valores enviados para um método pelo código que o chamou) e como tipos de retorno (valores retornados ao código que chamou o método). Você viu variáveis declaradas como valores inteiros primitivos simples (tipo int). Examinou variáveis declaradas como algo mais complexo do tipo string ou matriz. Porém há mais coisas na vida além de inteiros, strings e matrizes. E se você tiver um objeto DonodeAnimal com uma variável de instância Cão? Ou um Carro com um Motor? Neste capítulo desvelaremos os mistérios dos tipos Java e examinaremos o que você pode declarar como uma variável, o que pode inserir em uma variável e o que pode fazer com ela. E, para concluir, discutiremos o que acontece realmente na pilha de lixo coletável.

~
·7~-

e~':'ilê

é um novo capitulo

35

~

._-------------------------------------

- = - " ' " ' - - --

declarando uma variável

Declarando uma variável

o Java considera o tipo importante. Ele não permitirá que você faça algo bizarro e perigoso como in serir a referência de uma girafa em uma variável Coelho - o que aconteceria quando alguém tentasse pedir ao suposto coelho para saltar( )? E não permitirá que insira um número de ponto flutuante em uma variável de tipo inteiro, a menos que você informe ao compilador que sabe que pode perder a precisão (o que se encontra após a vírgula decimal).
A Java considera tipo ilnportante . não pode inserir girafa em tuna variável Coel ho .

'"

"
'"
~

O compilador consegue identificar a maioria dos problemas:
Coelho saltador
=

'" o,
r....

i

new Girafa ( };

'" !
r-

Não espere que isso seja compilado. Ainda bem que não será. Para que toda essa segurança dos tipos funcione, você deve declarar o tipo de sua variável. Ela é um inteiro? Um Cão? Um único caractere? As variáveis vêm em duas versões: primitivas e de referência de objeto. As primitivas contêm valores básicos (pense em padrões de bits simples) que incluem inteiros, booleanos e números de ponto flutuante . As referências de objeto contêm, bem, referências a objetos. (Puxa! Isso não esclareceu tudo?) Examinaremos primeiro as variáveis primitivas e, em seguida, passaremos para o que uma referência de objeto significa realmente. Mas independentemente do tipo, você deve seguir duas regras de declaração:

:1
"'· 1
~1
I

"' I
' " o;

~ II
- i

1

As variáveis devem ter um tipo
Além de um tipo, uma variável precisa de um nome, para que você possa usar esse nome no código.

1
!

"'-1
~'I

As variáveis devem ter um nome
int counti
tipo

":1
~1
'1
j

I

~1
r-

nome

Nota: quando você se deparar com uma instrução como " um objeto de tipo X", pense em ripo e classe como sinônimos. (Detal haremos isso um pouco mais em capítulos posteriores.)

""

"Gostaria de um café duplo, não traga um do tipo inteiro."
Quando você pensar em variáveis Jav a, pense em xícaras. Xícaras de café, xícaras de chá, canecas gigantes onde cabe muita cerveja, esses grandes copos em que as pipocas são vendidas no cinema, xícaras com alças curvilíneas e sexy e canecas com oacabamento metálico que lhe disseram para nunca colocar em um microondas.
Uma variável é apenas uma xícara. Um contêiner. Ela contém algo
o

:1
r-- jo
---.

--

Ela tem um tamanho e um tipo. Neste capítulo, examinaremos primeiro as vario áveis (xícaras) que contêm tipos primitivos e, um pouco mais adiante, discutiremos as xícaras que contêm referências a objefos. Não deixe de acompanhar toda a nossa analogia com as xícaras - tão simples como está sendo agora, ela nos fornecerá uma maneira comum de examinar as coisas quando a discussão ficar mais complexa. E isso ocorrerá em breve. As variáveis primitivas são como as xícaras que vemos nos cafés. Se você já foi a um Starbucks nos Estados Unidos, sabe sobre o que estamos falando aquio Elas têm tamanhos diferentes e cada uma tem um nome como 'pequena', 'grande' ou "Gostaria de um ' moca' grande com pouca cafeína e chantilly". oPodemos ver as xícaras dispostas no balcão, portanto, é possível ordená-Ias corretamente:

~,l
~,

= 1

~1~
r-::,0

-~ r',

~~ ~t:

pequena

média

grande

gigante

J __.J:
~l

36

capítulo 3

~

variáveis primitivas e de referência
).-,

,

h

h h

-

E, em Java, existem tamanhos diferentes para as variáveis primitivas e esses tamanhos têm nomes. Quando você declarar uma variável em Java, deve declará-la com um tipo específico. Os quatro contêineres mostrados aqui são para os quatro tipos primitivos inteiros em Ja va.
int
curto

l ongo

byte

Cada xícara contém uma quantidade, o mesmo ocorrendo com as variáveis primitivas Java, de modo que, em vez de dizer "Quero uma xícara grande de café francês torrado", você diria ao compilador "Quero uma variável int com o número 90, por favor" . Exceto por uma pequena diferença ... Em Java, você também terá que fornecer um nome para sua xícara. Portanto, na verdade diríamos "Quero um int, por favor, com o valor 2.486 e chame a variável de tamanho". Cada variável primitiva possui uma quantidade fixa de bits (tamanho da xícara) . Os tamanhos das seis variáveis primitivas numéricas em Java são mostrados a seguir:

M b yte

~

curto

int

longo

8

16

32

64

float

32

1 d ouble

64

Tipos primitivos
Tipo Quantidade de bits Intervalo de valores

Declarações primitivas com atribuições:
int x; x = 234; byte b = 89; boo1ean isFun char c = 'f';

Bolleano e char
Booleano (específica da JVM) verdadeiro oufalso
char 16 bits

=

true;

o

a 65535

double d = 3456.98; int z

numéricos (todos têm sinal) inteiro
byte curto int longo 8 b i ts 16 bits 32 bits 64 bits - 128 a 127 -32768 a 32767 -214748364 8 a 2147483647 -enorme a e norme

= x;

boo1ean isPunkRock; ispunkRock = false; boolean powerOn; powerOn = isFun;

ponto flutuante
fl o at double 32 bits 64 bits varia varia

Observe o 'r'. É preciso inseri-lo em um tipo float, porque o J ava long big = 3456789; c onsidera tudo que float f = 32.5f; ( _______ encontra com um ponto flutuan t e como um tipo
ãouble, a menos que 'f' seja usado.

Você não queria derramar isso realmente ...
Certifique-se de que o valor cabe na variável.
Você não pode desejar uma quantidade grande em uma xícara pequena.

1~
.
~

Bem, certo, você pode, mas vai perder uma parte. Você terá o que chamamos de derramamento. O compilador tentará ajudar a impedir isso se conseguir perceber que algo em seu código não caberá no contêiner (variável/xícara) que você está usando . Por exemplo, você não pode despejar muitos inteiros em um contêiner de tamanho byte, como descrito a seguir:
in t x = 24; byte b - x ; l/não funci onará!!

.~

;1",

.J

~ -~~-----------------------------------------------------------------

você está aqui>

37

atribuição

Por que isso não funcionou, você poderia]Je!'g~l~t~r~ Afinéd, _ val~: 9~ é~~2_e 24~~!initivamente é _L1~n valor o. suficientemente baixo para caber em um tipo byte. Você sabe disso, e nós também , mas tudo que importa ao compilador é que houve a tentativa de se inserir algo grande em um recipiente pequeno, e há a possibilidade de derramamento. Não espere que o compilador saiba qual é o valor de x, mesmo se por acaso você puder vê-lo literalmente em seu código.

Você pode atribuir um valor a uma variável de várias maneiras dentre elas:
- digitar um valor literal depois do sinal de igualdade (x - atribuir o valor de uma variável a outra (x

= 12, isGod = true, etc).

= y)

- usar uma expressão combinando os dois (x

= Y+ 43)

Nos exemplos a seguir, os valores literais estão em itálico e negrito:
int size double d int y
=

=
=

32;
=

declara um int chamado size e atribui a ele o valor 32
'j';

char initial

declara um char chamado initial e atribui a ele o valor ' j ' declara um double chamado d e atribui a ele o valor 456,709 declara um booleano chamado isCrazy (sem atribuição) declara um int chamado y e atribui a ele um valor que é igual à somado valor atual de x mais 456

456,709;

boolean isCrazy; x + 456;

Aponte seu lápis

Afaste-se dessa palavra-chave!

o compilador não deixará que você insira a
quantidade de uma xícara grande em uma pequena. Mas e quanto à operação inversa - despejar o conteúdo de uma xícara pequena em uma grande? Sem problemas'Baseado no que você sabe sobre o tamanho e o tipo das variáveis primitivas, veja se consegue descobrir quais dessas linhas são válidas e quais não são. Não abordamos todas as regras ainda, portanto, em algumas das opções, você terá que usar o seu melhor palpite. Dica: sempre qúe o compilador erra, é em nome da segurança. Na lista a seguir, circule as instruções que seriam válidas se essas linhas estivessem em um único método:
1-

Você sabe que precisa de um nome e de um tipo para suas variáveis. Você já conhece os tipos primitivos.

Mas o que pode usar como nomes? As regras são simples. Você pode nomear uma classe, método ou variável de acordo com as regras a seguir (as regras reais são um pouco mais flexíveis, mas estas o manterão em segurança):
- Ele deve começar com uma letra. um sublinhado C) ou o cifrão ($). Você não pode iniciar um nome com um número. - Depois do primeiro caractere, você também pode usar números. Só não comece com um número. - O nome pode ser o que você quiser, se obedecer as regras, contanto que não seja uma das palavras reservadas do Java. As palavras reservadas são palavras-chave (e outras coisas) que o compilador reconhece. Mas se você quiser realmente brincar de confundir o compilador, simplesmente tente usar uma palavra reservada como um nome. Você já viu algumas palavras reservadas quando examinamos a criação de nossa primeira classe principal: não use nenhu:ma
public static void ( - - - - - - dessas palavras nos
nomes que
criar~

int x

=

34.5;

2. boolean boo 3. int g
4.

x;

17;

int y

g;

5. y = y + 10;
6.
7. 8.
9.

E os tipos primitivos também são reservados:
boolean char byte short int long

short s; s
=

y;
3;

float

I

double

byte b byte v

b;

10. short n = 12;
11.

v

=

n;
12 8 ;

1 2 . byte k

Mas há muitas outras que ainda não discutimos. Mesmo se você não precisar saber o que elas significam, terá que saber que não pode usá-las em suas criações. Não tente - deforma alguma - memorizá-las agora. Para reservar espaço em sua mente, provavelmente você teria que perder alguma outra coisa. Como onde seu carro está estacionado. Não se preocupe, até o fim do livro você terá a maioria delas memorizada.

38

variáveis p-rimitivas e de referência

o

Essa tabela está reservada
byte prot'€cted abstract do e x tends finally char final wh il e double native switch float static case int stri c f p default long sho rt vo l atile continue super goto
if

synchronized transient for n ew voi d bre ak package const

---r--..
,-.,

el s e class catch

assert t h is enum

implements import try throw

instanceo f interfac e th r ows r eturn

r-..

As palavras-chave Java e outras palavras reservadas (em ordem aleatória). Se você usá-las como nomes, o compilador ficará muito confuso.

Controlando seu objeto Oog
Você sabe como declarar uma variável primitiva e atribuir a ela um valor. Mas e quanto às variáveis não primitivas? Em outras palavras, e quanto aos objetos?

- Na verdade não há uma variável de OBJETO. - Há apenas uma variável de REFERÊNCIA de objeto. - Uma variável de referência de objeto contém bits que representam uma maneira de acessar um objeto. - Ela não contém o objeto propliamente dito, mas algo como um ponteir~. Ou um endereço. Em Java, não sabemos realmente o que se encontra dentro de uma variável de referência. Sabemos que, o que quer que seja, representará um e somente um objeto. E a JVM sabe como usar a referência para chegar ao objeto.

Você não pode inserir um objeto em uma variável. Geralmente consideramos isso dessa forma ... Dizemos coisas como "passei a string para o método System.out.println( )". Ou "o método retorna um objeto Dog" ou ainda "inseri um novo objeto Foo na variável chamada myFoo". Mas não é isso o que acontece. Não existem xícaras gigantes expansíveis que possam crescer até o tamanho de qualquer objeto. Os objetos residem em um e apenas um local- a pilha de lixo coletável! (Você aprenderá mais sobre i~so pos~<:~:i~I~m ~ nte neste capítu lo.) Enquanto uma variável primitiva fica cheia de bits que representam o valor recJ-d; -~ariável, uma variável de referência de objeto fica cheia de bits que representam uma maneira de chegar ao objeto.
você está aqui
~

I

~

-----

39

referências d'3 obj eto Você usará o operador ponto (.) em uma variável de referência para dizer "use o que está antes do ponto para me lfaZer U ljue está depoIs ào pomo". Purexemplo:
myDog . bark( );

significa "use o objeto referenciado pela variável myDog para chamar o método bark( )". Quando você usar o operador ponto em uma variável de referência de objeto, considere isso como se estivesse pressionando um botão do controle remoto desse objeto.

Dog d - new Dog( • d.bark( ) ,
~ considere
isso-

• ) ,
......

'""
como s e rosse isso

Pense na variável de referência de
Dog como o controle remoto de um objeto Vog o

Voc ê a usará para acessar o objeto e razer algo (chamar métodos).

Uma referência de objeto é apenas outro valor da variável.
Algo que é despejado em uma xícara. Só que dessa vez é um controle remoto.

'.,.

Variável primitva
byte x = 7;
os bits que repres entam 7 es tão na variável .
byte

curto

int

longo

(00000111) .

8

16

32

64

referência (quantidade de bits não é relevante)

pri mitivo

Nas variáveis primitivas, o valor da variável é ... O valor literal (5, -26,7, 'a'). Nas variáyeis de referência,o valor da variável são ... f Bits, que represent/[m umanianeira de chegar um I: . i objeto específico. .

byte

a

Variável de referência
Dog myDog

=

new Dog( };

Não sabemos (ou nos importamos) como uma JVM específica implementa as referências de objeto. Certo, elas podem ser um ponteiro que aponte para um ponteiro que aponte para ... Mas. mesmo Sé você souber, não poderá usar os bits para nenhuma outra finalidade que não seja acessar um objeto.

os bits que repres en tam uma maneira de acessar o objeto Dog fícam dentro da variável. O objeto Dog propriamente dito não fica na variável!

Não nos importamos co m quantos algarismos I e O ex istem em um a variá vel de referência. Isso é responsa bi lidade de cada .JVM e da fa se da Lua.

40 c8píruio 3

variáveis primitivas e de referência

'"",

As 3 etapas de declaração, criação e atribu ição de objetos
1
Dog myDog = new Dog(

N ão existem
Qual o tamanho de uma variável de referência? Você não saberá. A menos que tenha intimidade com alguém da equipe de desenvolvimento da JVM, não saberá como uma referência é representada. Haverá ponteiros em algum local , mas você não poderá acessá-Ios. Não precisará disso. (Certo, se insistir, não há por que não imaginá-Ia com um valor de 64 bits.) Mas quando estiver pensando em questões de alocação de memória, sua Grande Preocupação deverá ser com quantos objetos (e não referências de objeto) está criando e com qual seu (dos objetos) verdadeiro tamanho. Mas isso significa que todas as referências de objeto têm o mesmo tamanho, independentemente do tamanho dos objetos reais aos quais elas se referem? Sim . Todas as referências de uma determinada JVM terão o mesmo tamanho, independentemente dos objetos que elas referenciarem , mas cada JVM pode ter uma maneira diferente de representar referências , portanto, as referências de uma JVM podem ser menores ou maiores do que as de outra JVM. Posso fazer cálculos em uma variável de referência, aumentá-Ia, você sabe - operações próprias da linguagem C?

_/- 3

2
);

P:

Perguntas Idiotas

~ Declare uma variável de referência
Dog myDog
=

R:

new Dog ( );

Dog
Solic i ta à JVM para alocar espaço para uma variável de referência e nomeia essa variável como myDog . A variável de referênc i a será sempre do tipo Dog . Em outras palavras, um controle remoto que tenha botões que controlem um objeto Dog, mas não um objeto Car, Buttton ou Socket.
• Crie um objeto

Dog myDog = new Dog (

);

Solic i ta à JVM para alocar espaço para um novo objeto Dog no heap (aprenderemos muito mais sobre esse processo, principalmente no Capítulo 9). objeto Dog .

P:

~ Vincule o objeto e a referência
Dog myDog = new Dog( ) ; Atribui o novo objeto Dog à variável de referência myDog. Em outras palavras, programa o
cOlltrole

R:

remoto.

P:

R:
Tudo sobre o Java
Entrevista desta semana : A referência de objeto
Use a Cabeça!: Então, diga .. nos, como é vida de uma referência de objeto? Referência: Bem simples, na verdade. Sou um controle remoto e posso ser programada para controlar diferentes objetos. Use a Cabeça!: Você quer di zer objetos diferentes mesmo enquanto está sendo executada? Tipo, você pode referenciar um cão e, em seguida, cinco minutos após referenciar um carro ?

Não. Repita comigo: "O Java não é o C".

Use a Cabeça!: Isso significa que você pode referenciar apenas úm cão? Referência: Não, posso referenciar um cão e, em seguida, cinco minutos após referenciar algum outro cão. Contanto que seja um cão, posso ser redirecionada (como na reprogramação de seu controle remoto para uma TV diferente) para ele. A menos que ... Deixa pra lá, esquece. Use a Cabeça!: Não, diga. O que você ia dizer?

l= _______-~ ..-_

I:

Referência: Não acho que você queira entrar nesse assunto Referência: É claro que não. Uma vez tendo sido declarada, é agora, mas darei apenas uma expli cação rápida - se eu for iSsQque-&9 LL S@-@-u fO!" 0-G9Htre!e rgmet9..de L!!1l cão, entfio, _._ .... _mar:=d.a..c.muo..finaLe.ntão. quundome atribuírem um Cão. não poderei ser reprogramada para nada mais exceto esse e nunca poderei apontar (opa - descu lpe. não devemos di ze r apontar), digo, referenciar algo que não seja um cão. somente esse cão. Em outras palavras, nenhum outro objeto

voce est<?i aqui

!>-

41

referências de objeto

f' I d f . agora. OK , entao a menos que voce seja ma , po e re erenClar um cao e, em segUIda, referenciar um cao diferente. Voce pode _ . ? ' ,_ nao referenciar absolutamente nada. E posslvel nao ser ro ramada ara nada? p g p Referência: Sim, mas me incomoda falar sobre isso.
A • _ • • _ . A

,U ---f -I- - b· ' · -- ·--acontecerIa. Eu me sei1tit-ía tão...-rrÚíül.- Oill desperdício de Use a C a b eça.: voce esta certa, nao queremos a ar so re ISSO '", " " " , " ,' ItT '
A , - --

poderá ser atribuído a mim.

meus botões o dia inteiro, mas nada de interessante

bits. Na verdade, nem tantos bIts, mas mesmo assim a "uns. E -,. S f ,. t' d essa nao e a pior parte. e eu or a Ul1lca reerenCIa e um b' 'f' 'd f f' d II o ~eto especI lCO e, em segUI a, or con Igura a com nu (d d )' 'T ., d' guem po era esprograma a ,.ISSO slgm Ica que agora acessar aquele obJeto que eu estava referenciando.
A '

nl:1

Use a Cabeça!: E isso não é bom porque .. . Referência: Precisa perguntar? Desenvolvi um relacionamento com esse objeto, uma conexão íntima e, em seguida, o vínculo é repentina e cruelmente rompido. E eu nunca verei esse objeto novamente, porque agora ele estará qualificado para [produtor, deixa para a música trágica] a coleta de lixo. Sniff. Mas você acha que os programadores consideram isso? Snif. Por que, por que não posso ser uma variável primitiva? Odeio ser uma referência . A responsabilidade, todos os relacionamentos rompidos ...

Use a Cabeça!: Por quê? Referência: Porque significa que eu seria nula e isso me incomoda. Use a Cabeça!: Você quer dizer que então não teria valor? Referência: Oh, nulo é um valor. Eu ainda seria um controle remoto, mas é como se você trouxesse para casa um novo controle remoto universal e não tivesse uma TV. Não estarei programada para controlar nada. Vocês poderiam pressionar

A vida na pilha de lixo coletável
Book b = new Book() i Book c = new Book()i
Declare duas variáveis de referência Book. Crie dois novos objetos Book. Atribua os objetos Book às variáveis de referência. Agora os dois objetos Book estão residindo na pilha . Referências; 2 Objetos; 2 B00k

Book d = Ci
Declare uma nova variável de referência Book. Em vez de criar um terceiro objeto Book, atribua o va l or da variável a à variável d. Mas o que isso significa? É como dizer "pegue os bits de a, faça uma cópia deles e insira essa cópia em do. Tanto c quanto d referenciam o mesmo objeto. As variáveis c e d contêm duas cópias diferentes com o mesmo valor . Dois controles remotos programados para uma TV. Referências; Objetos; 2 3 Book

c = bi
Atr,ibua o valor da variável b à variável c . Agora você já sabe o que isso significa. Os bits da variável b serão copiados e essa nova cópia será inserida na variável c. Tanto b quanto c referenciam o mesmo objeto . Referências; Objetos: 2 3

42

capítulo 3

variáveis primitivas e de referência

Vida e morte na pilha
Book b = new Book( Book c = new Book( ); );

Declare duas variáveis de referência. Crie dois novos objetos Book. Atribua os ob jetos Book às variáveis de referência. Agora os dois objetos Book estão residindo na pilha. Ref erências at ivas: 2 Obje t os alcançáveis : 2 Book

b

=

c;

Atribua o va l or da variável c à variável b . Os bits da var iável c serão copi ados, e e ssa nova cópia será ins e rida na variável b. As duas var i áveis contêm valores idênticos . Tanto b quanto c referenciam o mesmo objeto. O objeto 1 será abandonado e estará qualificado para a Coleta de Lixo (GC, Garbage Co l lect i on) . Ref erências a tivas : 2 Objetos alcançáveis : I Objetos abandonados: I O p r imeiro objeto que b refer e nciava, o objeto 1, não tem mais referências, se tornou inalcançável.

Esse objeto foi .",abandonado. É isca do Ik::. coletor de lixo.

1

Book

c = null;
Atr i bua o valor null à var i ável c. Isso a tornará urna referência nula , o que significa que ela não está referenc i ando nada . Mas continua a ser urna variável de referência e outro objeto Book pode se r atribuído a ela. O ob jeto 2 ainda t em urna referênc i a ativa (b) e , enquanto a tiver, nã o e stará qua l i fi cad o para a GC . Refer ências ativas: I Refe r ências nulas : 1 Objetos alcançáveis: I Objetos abandonados : I

Ainda abandonado

1.

Ainda não foi abandonado ( esta·r áseguro enquant·o b referenciá - lO)

~

Book

~ referência

nula (não está programada para nada)

Uma matriz é como uma bandeja com xícaras

Declare urna variável de matriz int . Uma variável de matriz é o controle r e moto de urn objeto de matriz.

int [

nurns;

Cri e uma nova matriz int d e tamanho 7 e a a t ribua à variável int[ 1 nurns já declarada

n urns

new int [71; você está aqui ~ 43

uma matnz de objetos

Q Forneca

~ara cada elt;:!..IDp.nto da

mnr.r;7. 11m

v'3~lor

_iT"l'.-r_ _ __

Lembre - se de que os elementos de uma matriz int são apenas variáveis int.

nums[O] = 6;
-\O
"!i

1:1

nums[l] nums[2]

19;

7 'v'ariáveis int

'';

'"
~
~
4

-

44;

'<II
'';

nums[3] = 42; nums[4] = 10; nums[5] nums[6] 20; 1;

!'-.

~
.. . . . .
o"

.. ::l
"

....

~.

o
int

1 int

2 int

3
int

456
int int int

. j

objeto de matriz int (int[ ]l

~.

int []

Note que a matr iz será um objeto r mesmo se tiver os 7 elementos primitivos.

As matrizes também são objetos
A biblioteca padrão Java inclui várias estruturas de dados sofisticadas incluindo mapas, árvores e conjuntos (consulte o Apêndice B), mas as matrizes servirão bem quando você quiser apenas obter uma lista de coisas de maneira rápida, ordenada e eficiente. As ma1:J.izes lhe concederão acesso aleatório rápido, permitindo que você use a posição de um índice para acessar qualquer elemento existente nelas. Todo elemento de uma ma1:J.·iz é apenas uma variável. Em outras pahivras, um dos oito tipos primitivos de variável (lembré-se: Large Furry Dog) ou uma variável de referência. Qualquer coisa que você inserir em uma variável desse tipo poderá ser a1:J.-ibuída a um elemento de m.atriz do mesmo tipo. Portanto, em uma matriz de tipo int (int[ ]), cada elemento pode conter um inteiro. Em uma matriz Dog (Dog[ ]) cada elemento pode conter... Um objeto Dog? Não, lembre-se de que uma variável de referência só armazena uma referência (um controle remoto) e não o próprio objeto. Logo, em uma matriz Dog, cada elemento pode conter o controle remoto de um objeto Dog. É claro que ainda teremos que criar os objetos Dog .. . E você verá tudo isso na próxima página. Não deixe de observar um item-chave no cenário acima variáveis primitivas.
-i

a matriz será um objeto, mesmo se tiver

As matrizes são sempre objetos, não importando se foram declaradas para conter tipos primitivos ou referências de objeío. Mas você pode ter um objeto de matriz que tenha sido declarado para conter valores primitivos. Em outras palavras, o objeto de matriz pode ter elementos que sejam primitivos, mas a matriz propriamente dita nunca é de um tipo primitivo. Independentemente do que a matriz armazenar, ela sempre será um objeto!

Crie uma matriz de objetos 009
~ Decl are uma variável de matriz Dog

Dog[] pets;
Crie uma nova matriz Dog com taman ho igual a 7 e a a tribua à variável Dog[] pe t s já declarada

o
Dog

1

2

3

4

6

Dog

Dog

Dog

Dog

Dog

Dog

pets = new Dog[7];

o que está faltando?
Objetos Dog' Temos um a matriz de referências Dog, mas nenh um objeto Dog real!

objeto de matriz Dog (Dog[ ]l
Dog[]

44 ca Dítuin 3

variáveis primitivas e de referência
~ crie novos objetos Dog e atribua - os aos elementos
da matriz. Lembre-se de que os e lementos de uma matriz Dog são apenas variáveis de referênc ia Dog. Ai nda precis amos de ob je tos Dog'

I~

pets[Q[ new Dogi pets[l] = new Dogi

I"

I~
Aponte seu lápis
~.

,"""" ,

!" " 1 I""""
I

.::...

Qual é o valor atual de pets[2]? Que código faria pets[3] referenciar um dos dois objetos Dog existentes?

.. . i ::: ... Pet '
.
..

i,..---,.

Dog[]

~
.

.~ L

0123456 Dog Dog Dog Dog Dog Dog Dog

objeto de matriz Dog (Dog[ ])

j~
I~

1

I"

Controle seu objeto 009
(com uma variável de referência)
Dog fido = new Dog () ; fi do . name = "Fido";

,
Dog
name bark( ) eat( ) chaseCat(

Criamos um objeto Dog e usamos o operador ponto na variável de referênciajido para acessar a variável name*. Podemos usar a referênciajido para fazer o cão latire ), comere ) ou perseguirGatos( ).
Dog

fido . bark() ; fido.chaseCat () ;

o que aconteceria se o objeto D09 estivesse em uma matriz Dog?
Sabemos que podemos acessar as variáveis de instância e métodos de Dog usando o operador ponto, mas onde usá-lo ?

1
)

I

Quando o objeto Dog estiver em uma matriz, não teremos uma variável name real (como jido). Em vez disso usaremos a notação de matriz e apertaremos o botão do controle remoto (operador ponto) do objeto de um índi.ce (posição) específico da matriz:
Dog [] myDogs = new Dog[ 3]; myDogs[O]

= new

Dog() ;

myDog s [O] .name = "Fido"; myDogs[O] . bark();

*Sim. sabemos que não estamos demonstrando o encapsulamento aqui, mas estamos tentando manter o código simples. Por enquanto. Veremos o encapsulamento no Capítulo 4."

o

Java acha o tipo importante.

Quando você tiver declarado uma matriz, não poderá inserir nada que não seja do tipo declarado para ela. Por exemplo, você não pode inserir um objeto Cat em uma matriz Dog (seria muito frustrante se alguém achasse que só há cães na matriz e pedisse a cada um deles que latisse para então.com espanto descobrir que há um gato 'à espreita). E você não pode inserir um tipo double em uma matriz int (derramamento, lembra-se?). No entanto, pode inseri um byte em uma matriz int, porque o tipo byte sempre caberá em uma xícara de tamanho int. Isso é -coü1iecld.O como alargamento ImplÍcllo. l!,mraremos em deraihes pusLerÍurmeule; por enquant9' ape~J<ts' Iemti:e'"s~rl€ que o compilador não permitirá que você insira algo errado ,e m uma matriz, com b.~seno tipo declárado para ela.,
você está aqui!> 45

l -----J~

usando referências

Um exemplo de 009
class Dog St ring name; public static void main (String[] args )

Dog
name bark( eat ( ) chaseCat ( ) .

II cria um objeto Dog e o acessa
Dog dogl = new Dog(); dogl.bark() ; dogl . name = "Bart";

""'
,.-.,.
~

II ago ra cria uma matriz Dog
Dog[] myDogs myDogs[Q} myDogs[l} myDogs[2]
=

~

new Dog[3];

II and put some dogs in it
new Dog(); new Dog(); dogl;

Saída

r-...

r-... r-...

II agora acessa os objetos Dog II usando as referências da matriz
myDogs [ Q] . name myDogs[l] . name "Fred" ; "Marge" ;

"""' ""'
.

II

Hrnmmm ...

qual é o nemo de myDogs[2]?

.-.'
".t

System.out . print("o nome do último cão é "}; System . out.println(myDogs[2] .name ) ;

II agora execu ta um loop pela matriz II e pede a todos os cães para latirem
int x ::: O; while(x < myDogs.length) myDogs[x] . bark();
as ma.trizes têm t.una variá,,:rel { ~(~-------- 'length' que lhe fornecerá a ~Jantidade de elementos

.k
.~

......., ,; -"i

"""' ]
r--

'"

x = x + 1;

"""' ,#
c<i

-1

r-...

.~~

public void bark()

{

r .

System . out . println(name + " diz Ruff!"); public void eat() {

""' ,.... .'i"
I'"

public void chaseCat ( }

"
'"
..-..,

,
·fl

DISCRIMINAÇÃO DOS PONTOS - - - - - - - - - - ,
- As variáveis vêm em duas versões: primitivas e de referência. - As variáveis devem sempre ser declaradas com um nome e um tipo.

..-....
.......,
I'"

- O valor de uma variável primitiva são os bits que o representam (5, 'a', verdadeiro, 3. 1416, etc.). - O valor de uma variável de referência são os bits que representam uma maneira de acessar um objeto da pilha. - A variável de referência é como um controle remoto. Usar o operador ponto (.) em uma variável de referênci a é como pressionar um botão no controle remoto para acessar um método ou valiável de in stânci a. - Uma variável de referência tem valor nulo quando não está referenciando nenhum objeto. - Uma matriz é sempre um objeto, mesmo quando é declarada para conter tipos primitivos. Não existe algo como uma matriz primitiva, somente uma matriz que contenha tipos primitivos.
r-... ""

"""'
/\
J
"

"""'

iL

46

capítulo 3

variáveis primitivas e de referência

Seja o compilador

I'"

Cada um dos arquivos Java dessa página representa um arquivo-fonte completo. Sua é personificar o compilador e determinar se cada um deles pode ser compilado. Se não puderem ser compilados, como você os corrigiria?

A
class Books { String title; String author; class Hobbits { String name;

B

public static void main(String (] args) class BooksTestDrive ( public static void main(String (] args) Books (] myBooks int x = O; myBooks(Ol .tit le myBooks(l] .title myBooks(2] .title myBooks (O ] .author myBooks(ll.author myBooks (2 ] .author new Books(3]; "The Grapes of Java"; "The Java Gatsby" ; "The Jav a Cookbook"; "bob" ;
\\s ue" ;

(

Hobbits (] h = new Hobbits(3]; int z O; while (z < 4) z = z + 1; h(z] = new Hobbits (); h(z] . name = "bi l bo"; if (z == 1) ( h (z] .name = "frodo";
if
(z

"ian" ;
== 2)
(

I"
wh ile (x < 3) ( System.out.pr i nt (myBooks (x] . title); System . out .print(" by "); System . out . println(myBooks(x] .author); x = x + 1;

h(z ] . name = "sam"; System.ou t. p ri n t (h(z] .name + " is a "); System .out.print ln("good Hobbit name");

: '"

Imãs com código
\ in' Y

.

Um programa Java está todo misturado sobre a geladeira. Você conseguiria reconstruir os trechos de código para criar um programa Java funcional que produzisse a saída listada a seguir? Algumas das chaves caíram no chão e são muito pequenas para que as recuperemos , portanto, fique à vontade para adicionar quantas delas precisar!

01
{

int ref; while (y < 4)

1~~0 ]
Ij \
'1

1;

index(l] index( 2] index(3]

3;

o;
2;

l

String (]
p;;;ss:.4LM4t.Aii44ii ,, '

islands = new String(4]; .
"-I!!' iJ'!! _n

tIl , 14· . Qi854?iiWtlA'MIW$4t\4# Mi4iiWi'J94ij!!!nh

J'
,

System.out.print("island
, . _ -9
:>"' J:'~,'
r----~

= ");

,.
, %Q

«"S '

-*; ~'4'il

_4~ , _
<

,:;;<t;; {'! HG\#4&"'"'4 -

'-

1

lnt []

ind

_ -------:-----, ex - new lnt [4]; .

class TestArrays

você está aqui..

47

'"
.--."

quebra-cabeças: quebréH.:ab.sçós na p:scíns

,.--,.,

,.--,.,

Quebra-cabeças na Piscina

Sua tarefa é pegar os trech os de códi go da pi scin a e in seri-l os ... -----rms--rhrtTa~nim!nc·ocioc ód i go . Você pode usaJ'l5 mesmo trecho mais de um a vez e não precisa empregar todos os trechos. Seu objetivo é criar uma classe que seja compilada e executada, produzindo a saída listada.

.--."

"
,.-..,.

..-.,
r'-.

r'-.

c lass Triangle ( d oub le area ; in t hei g ht;

(poãemos não usar uma classe de teste separada, por

,.--,.,
..-.,
"\
~

estarmos tentando economizar
espa ço na pági na ~ )

Saída

i nt length; public s t atic void main(String [) a r gs) {

,.--,.,
...--.,.

while

( .heigh t

)

{

,.--,.,

_ __ _

,.--,.,
(x

+

1)

* 2;

_ _ _ _ . leng t h

x + 4;
"+x+" , area ");
_ _ _ _ o

'"

System.out . p rint("triangl e System . ou t. pr i nt l n(" = " +

'"'
r'-.

a re al ;

Pergunta adicional!
Para tentar ganhar mais pontos, use os trechos da piscina para preencher o que falta na saída (acima).
x = 27; Tr iangle t5 = ta(2); ta( 2) . area = 343; Sys t e m . out .print ("y System. ou t . pri n tl n (", vo i d s etAr e a ( ) (he i gh t
" + y) ;

'"'

,

"
-"

.~
" + t5. a r ea );
r--

t5 a rea

J
~
:\

,.--

.'

.~

* length)

/ 2;

...--.,.
~

" "
Nota: Cada trecho de código da piscina usado mais de urna

"
'"'
r"'o

ta .x . ar ea ta [x) . area

4, 4, 27, 27,

t5 t5 t5 t5

a rea ar ea ar ea area

18 .0 343 .0 18 . 0 343 . 0 int int int int int x; y; x x y

/' /'

ta[x) = setArea(); ta . x = setArea(); ta [x) . setArea () ; [ ) ta n ew Trian gle (4) ; , ta = new r J l [ ) ta = n ew

x x x
O; 1; x;

x + 1; x + 2; x - 1;
28 . 0 30 . 0

ta . x ta(x) ta[x)

r--.
r-...

x < x < ta = new Tri a n gle (); t a[ x) = new Triangl e() ;

'"

48

cap ituio 3

variáveis primitivas e de referência

Uma pilha de problemas
Um programa Java pequeno está listado à direita. Quando a linha 'II executa algo' for alcançada, alguns objetos e variáveis de referência terão sido criados. Sua tarefa é determinar que variáveis de referência apontarão para quais objetos. Nem todas as variáveis de referência serão usadas, e alguns objetos podem ser referenciados mais de uma vez. Desenhe linhas conectando as variáveis de referência aos seüs respectivos objetos.

Dica: a menos que você seja mais esperto que nós, provavelmente terá que desenhar diagramas como os das páginas 55 e 56 deste capítulo. Use um lápis para poder desenhar e, em seguida, apague os vínculos das referências (as setas que vão do controle remoto da referência para um objeto).
class HeapQuiz ( int id = O; publi c static v o id main (String [] args ) int x = o · HeapQuiz [ ] hq = new HeapQuiz[5]; while ( x < 3 ) ( hq[x] = new HeapQuiz () ; hq[x] .id = x· x = x + l '
Variáveis de referência: Objetos HeapQuiz:

}
hq [3 ] hq [1] ; hq [4] hq [1] ; hq[3] null; hq [ 4] hq [ O] ; hq [ O] hq [3] ; hq [3] hq [2 ] ; hq [2] hq [O] ; II executa algo
hq[41

hq[31

conecte cada variável de referÊncia
com 0(5) respe ccivo ( s) objeto(s}

Tal vez você nào precise usar todas as :re f erências.

o caso das referências
Um pequeno mistério ~~..

roubadas

Era uma noite escura e chuvosa. Tawny caminhava para a cela dos programadores como se fosse proprietária do local. Ela sabia que todos os programadores ainda estariam trabalhando e queria ajuda. Precisava de um novo método adicionado à classe principal, que devia ser carregada no novo celular altamente secreto e habilitado com Java do cliente. O espaço na pilha de memória do celular estava tão apertado quanto o vestido de Tawny, e todo mundo sabia disso. O murmúrio normalmente rouco na cela silenciou quando Tawny se encaminhou para o quadro branco. Ela desenhou uma visão resumida da funcionalidade do novo método e lentamente examinou a sala. "Bem meninos, hora de trabalhar", murmurou. "Quem criar uma versão para esse método que use a memória mais eficientemente irá comigo à festa de lançamento do cliente em Maui amanhã ... Para me ajudar a instalar o novo software."

Na manhã seguinte, Tawny entrou na cela usando seu curto vestido Aloha. "Senhores", ela sorriu, "o avião parte em algumas horas, mostrem-me o que vocês tem!" Bob foi o primeiro; quando ele começou a desenhar seu projeto no quadro branco Tawny disse: "Vamos direto ao ponto Bob, mostre-me como você manipulou a atualização da lista de objetos de contato." Bob escreveu rapidamente um fragmento de código no quadro:
Contact [] ca = new Co ntact[10]; while I ( x < 10 ) ( I I cria 1 0 obj etos de contato ca [x] = new Contact ( ); x = x + 1; II executa complicada atualização da lista de objetos

Con~act

com ca

"Tawny, sei que temos pouca memória, mas suas especificações diziam que tínhamos que ser capazes de acessar informações específicas de todos os dez contatos permitidos, e esse foi o melhor esquema que pude criar", disse Bob. Kent foi o próximo, já imaginando coquetéis de coco com Tawny. "Bob", ele disse, "sua solução é um pouco complicada não acha?" Kent sorriu, "Dê uma olhada neste bebezinho":
Cont a ct refc; whil e ( x < 1 0 ) ( II make 1 0 c o ntact objects r e f c = new Cont ac t (); x = x + 1; II e x e c ut a complicada at u ali z aç ã o da lista de o bje t os Cont a ct c o m r e f c

~I

"Economi.zei-muitas-vaF~ávsi-s-Ele referência q-ue usariam mem.Ó!::h:'1-,-BGbiz-i..Rho, po.!=tfl!lt-o, OQdel!Jlardar seu orotetor solar". 2:0Z0U Kent. "Não tão rápido, Kent!", disse Tawny, "você economizou um pouco de memória, ~as é Bob que ve~ comigo". . ~

Por que Tawny escolheu o método de Bob e não o de-Kent, se o de Kent usava menos memória?
você está aqui ..

49
_J

-.._--- - -

""""
,.-...
----, ----,

soluções dos

eX6tC'CI\..!.:>

--.
- -----····- -------- - c ~

Soluções .-dos Exercícios - _. \

I
I

cIa~s BOO~S {_ ~._. -rn::-re;Str ing au th or ;

~

" ,.-...
r-..

código:
cIas s TestArrays { pubIic static void main (String [] args) int [] index = new in t [4]; index [ O] 1; index [ 1] 3; index[2] O; index[3] 2; Str ing [] isI ands = new String[4] ; isIands [O] "Ber muda"; "Fiji" ; isI ands[ l] "Azores" ; i sIands [2] "Cozumel"; isIands[3 ] int y = O; int ref; whiI e (y < 4 ) { ref = index [y] ; System.out.print("island = "); Sys tem . out .prin tln(i s lands[ ref] ) ;
y
= y

{

cIass BooksTestDrive pub1 ic static vo id main(String [] arg s) Books [] myBooks = new Books[3]; int x = O; myBooks[O] new Books(); Lembre-se: temos que criar myBooks[l] new Books(); realmente os objetos Book! myBooks[2] new Books(); myBooks [O] . t i tl e "The Grapes of Java"; myBook s[l].title = "The Java Gatsby"; A myBooks [2] . titIe = "The Java Cookbook"; myBooks [O] . author "bob " ; myBooks[l].author "sue"; myBooks [2] . au t hor "ian" ; while (x < 3) { System.out.print(myBooks[x] . title ) ; System . out . print (" by ,,); System.out.println(myBooks [x ] . autho r); x = x + 1;

"
r-..
r--..

'"'"'

"
'"'

'"'

'"
~

r--..

+ 1;

Soluções dos quebra-cabeças

o

caso das referências roubadas

cl ass Hobbits { Str i ng n ame; public static vo i d main(String [] args) Hobbits [ ] h = neW HOrb~b~i~ t~s~[~3~ __________~____- , ]~; int z = -1 ; Lembre-se : as matrizes while (z < 2) começam com o elemento O! z = z + 1; h[z ] = new Hobbits(); h[z] . name = "bilbo"; if (z == 1) { h[z] . name = " fr odo"; 8
if
(z

r-..

-,

""""

"
r--..

Tawny percebeu que o método de Kent tinha uma falha séria. É verdade que ele não usou tantas variáveis de referência quanto Bob, mas não havia como acessar nenhum dos objetos Contact que esse método criava, exceto o último. A cada passagem do loop, ele estava atribuindo um novo objeto à variável de referência, portanto, o objeto referenciado anteriormente era abandonado na pilha inalcançável. Sem acessar nove dos dez objetos criados, o método de Kent era inútil.
(O software foi um grande sucesso, e o cliente deu a Tawny e Bob uma semana a mai s no Havaí. Gostaríamos de lhe dizer que, ao terminar este livro, você também conseguirá coisas desse tipo .)

== 2)

{

h[z] .name

=

"sam";

" r--..
r--

System. out . print(h[z] . name + " is a ,, ) ; Syst em. out . println (" g ood Hobbit name");

variávei s de referência:

-õ ;·· ·
. I J hq[ O]
:,:';

Objetos HeapQuiz:

class Triangle { double area; int he igh t; int length; pub1ic static void main(String [] args) int x = O; Triang1e [ ] ta = new Triang1e[4]; while ( x < 4 ) { ta[x] = new Triangle(); ta[x] . he ight = (x + 1 ) * 2 ; ta[x] . l eng th = x + 4; ta[x] .setArea(); System.out . print("triangle "+x+" , area "); System . out.println(" = " + ta[x] .ar ea);
x = x + li

,...., ,....,
'"

'"' '"'

'"
"""" '"'
r-,-.,
.~

int y = x; x = 27 ; Trianqle tS = ta [2]; ta[2 ] . area = 343; System . out.print( "y = " + y); System . out .pr intln(", tS area vo id- setArea() { area = (height * length)

'"'

,....,
"+ tS . area);

'"'
'"'
_J

/ 2;

~.

'" ,., " --:r ...-... :;
;

~

~ -

4 os métodos usarn variáveis de instância

r
,,-....
,,-...

,,-...

.,..-...
,--.

Como os Objetos se Comportam

r

o estado afeta o comportamento,

o comportamento

afeta o estado. Sabemos que os objetos têm estado e
comportamento, representados pelas variáveis de instância e métodos. Mas, até agora, não examinamos como o estado e o comportamento estão relacionados. Já sabemos que cada instância de uma classe (cada objeto de um tipo específico) pode ter seus próprios valores exclusivos para suas variáveis de instância. O cão A pode ter o nome "Fido" e peso de 37 quilos. O cão B se chama "Killer" e pesa 5 quilos. E se a classe Cão tiver um método emitirSom( ), bem, você não acha que um cão de 37 quilos latirá um pouco mais alto do que o de 5 quilos? (Supondo que o som incômodo de um ganido possa ser considerado um latido.) Felizmente, isso é o que há de importante em um objeto ele tem um comportamento que atua sobre seu estado. Em outras palavras, os métodos usam os valores

das variáveis de instância. Por exemplo: "Se o cão pesar menos de
8 quilos, emita um ganido, caso contrário ..." ou "aumente o peso em 3 quiios". A/Ceremos aiguns estados! _.
este é um novo capítulo 51

..... _---f'

,.....,.

'"""-os objetos possuem estado e COiliportamento

'"'

,.....,.

Lembre-se: uma classe d~sç!eve_ o qUf? um objeto conhece e o que ele faz
Uma classe é o projeto de um objeto. Quando você criar uma classe, estará descrevendo como a JVM deve criar um objeto desse tipo. Você já sabe que todo objeto desse tipo pode ter diferentes valores para as variáveis de instância. Mas e quanto aos métodos?
variáveis de instância (estado) métodos (COll\Portamento)

,.....,.
'""""'

Song
t i tle artist setTitle( setArtist( play( )
) )

j
conhece

,.....,.
r/""'o..

r'\

Cada objeto desse tipo pode ter um método com comportamento diferente?
Bem ... Mais ou menos. * Todas as instâncias de uma classe específica têm os mesmos métodos, mas eles podem se comportar diferentemente com base no valor das variáveis de instância. A classe Song tem duas variáveis de instância, title e artist. O método play( ) reproduz uma canção, mas a instância em que você o chamar reproduzirá a canção representada pelo valor da variável de instância title (título) dessa instância. Portanto, se você chamar o método play( ) em uma instância, reproduzirá a canção "politik", enquanto outra instância reproduzirá "Darkstar". O código do método, porém, é o mesmo.
void play() ( soundPlayer .pl aySound(title);

I~:

faz

,.....,.
----...
r--.

-

I'

c inco instâncias da cla s se Song

,--..,
"-

"-

.<
>/,

.
'"'-

~ ,

Chamar pla y( ) nessa instância fará com que
Song t2 = new Song(); t2 .setArtist( "Travi s" ); t2.setTitle("Sing"); Song s3 = new Song(); s3.setArtist("Sex Pistols"); s3.setTitle("My Way");
u

"Sing

seja\~p r~i

I
~
\'
);
~

'"'-

,.~

~

,.--.., ~

ê
Song
t2.play(

:~; ./
.- }1 s3 -

J

*Sim, outra resposta surpreendentemente clara!

Song
s3.play( };

Chamar play( ) nessa instância fará com que

\

"~ty

Way" seja reproduzida . não com O Sinatra)

(ma s

o tamanho afeta o latido
o latido de um cão pequeno é diferente do de um cão grande
A classe Dog tem uma variável de instância size (tamanho), que o método bark( ) usa para decidir que tipo de som emitir para o latido.

class Dog ( int sizei String name; void bark () { i f (size > 60) ( System.out.println("Wooof! Wooof!"); else if (size > 14) { System. out . println ("Ruff ! Ruff ! " ) ; else ( System . out.println("Yip! Yip''' ) ;

Dog
size name bark(
k

,

i

Lata Diferente

,;
)

:
-

52

capítulo 4

-----------------------

1

os métodos usam variáveis de instância
c la s s DogTestDrive { public static void ma i n (String[] a r gs) Dog one = new Dog(); one .s ize = 70; Dog two = new Dog(); two.size ·· = 8 ; ' Dog three = new Dog() ; thre e. size = 35 ; o n e . bark () ; two.bark(); three.bark(); (

Você pode enviar valores para um método
Como é de se esperar de qualquer linguagem de programação, você pode passar valores para seu método. Pode, por exemplo, querer informar a um objeto Dog quantas vezes latir chamando :
d.bark(3);

Dependendo de sua experiência em programação e preferências pessoais, você pode usar o termo argumentos ou talvez parâmetros para os valores passados para um método. Embora essas sejam distinções formais na ciência da computação que pessoas que usam jalecos e que quase certamente não lerão este livro fazem, temos coisas mais importantes com que nos preocupar aqui. Portanto, você pode chamá-los como quiser (argumentos, donuts, bolas de pêlo, etc.), mas usaremos essa convenção:

Um método usa parâmetros. Um chamador passa argumentos.
Os argumentos são os valores que você passará para os métodos. Um argumento (um valor como 2, "Foo" ou uma referência que aponte para um objeto Dog) será inserido diretarnente em um ... Adivinhe ... Parâmetro. E um parâmetro nada mais é do que uma variável local. Uma variável com um tipo e um nome, que poderá ser usada dentro do corpo do método. Mas aqui está a parte importante: se um método usar um parâmetro, você terá que passar algo para ele. E esse algo deve ser um valor do tipo apropriado.

r

~

Chame o método bark na variável de referência Dog e passe o va lor 3 (como o argumento do método) .

Dog d

=

new Dog(

)i

d.bark(3)i

~ Os bits que repr esentam o valor int 3 serão
dist ribuídos para o método bark .

r

parâme tro

vo id bark(int numOfBarks) { while (numOfBarks > O) { System.out.println("ruff H ) ; numOfBarks = numOfBarks - 1;

/

~ Os bits serão inseridos no parâmetro numOfBarks (uma
v ari áve l de tamanho in t) .

~ Use o parâmetro numOfBar ks como uma v a riáve l no código
do método .

Você pode fazer valores serem retornados por um método

você está aqui

ii>-

53

vários argumentos
void go () (

Mas podemos declarar um método que retorne um tipo específico de valor para o chamador, como em:
int giveS e cret () return 42 ;

Se você declarar um método que retorne um valor, terá que retornar um valor do tipo declarado! (Ou um valor que seja compatível com o tipo declarado. Nós nos aprofundaremos mais nisso quando falarmos sobre polimorfismo nos capítulos 7 e 8.)

o que você

disser que retornará é bom que seja mesmo retornado!

I
o t i po errado de c oisa.

. 1::.

n I.

o compilador não permi t irá que você retorne

int theSec
Es ses t ipos s er iguais

=

life.giveSecret();
Os bits que r epresentam 42 s ã o ret o rnados pelo método g i veSecr et( ) e inseridos na variável chamada tneSecret.

devem~

~ int
}

giveSe ret()

return~ preci s a caber
em um in t !

-.-l

{

ess e valor

Você pode enviar mais de um valor para um método
Os métodos podem ter vários parâmetros. Separe-os com vírgulas ao declará-los e separe os argumentos com vírgulas ao passá-los. O mais importante é que se um método tiver parâmetros, você deve passar argumentos do tipo e na ordem canetas.
~

Chamando um método de dois parâmetros e enviando dois argumentos para ele.
v oid go () ( TestStuff t = new TestStuff(); t. takeTwo (12, 34);
r"\

~

-7

r--..

void t akeTwo( int x, int y ) ( int z = x + y; Systern . out.println("Total is " + z);

\~

Os argumentos serão inseridos na mesma ordem em que você os p a ssar. O primeiro argUloen t o será inserido no primeiro parâmetro, o segundo argUlnento no segundo parâmetro e assim por diante.

l~
'~ ~

r--..

I.

'"'
"
r"\

Você pode passar variáveis para um método, contanto que o tipo da variável seja igual ao tipo do parâmetro.
vo i d go () { int foo = 7 · . int bar = 3;

.} UakeTwo

"0\ b,\

Os valores de foo e bar serão inseridos nos parâmetros x e y. Portanto, agora os bits de x serão idênticos aos de foo (o padrão àe bits do ' inteiro '7') e os bits de y serão idênticos aos de bar .

void takeTwo(int x , int y) { in t z = x + y; Sys tern . o u t . println ( " To tal is " + z ) ;

Qual é o val or de z? O resultado será o mesmo que voc ê obteria se somasse fao + b ar ao passá-los p ara o método takeTwo

54 capítulo 4

os métodos usa.!l variáveis de instância

o Java

passa por valor.

Isso significa passar por cópia.

..

~

int x

7, ·
int

o
z) { }

Declare uma var iável int e atribua a ela o valor '7' . O padrão de bits do número 7 será inser i do na variável chamada x .

v oid go(int

fi
int

Declare um método com um parâmetro in t chamad o z .

Chame o método go( ), passando a var i ável x como argumento . Os bits de x serão c opiados, e a cóp ia s erá inser ida e m z . int
TO O.

int

g o (x) ;

vo i d g o( i nt z ) { }

me smo ser z

x não ser á al t erado, f or .

! ! --

·..., .t

,
~

i-t-'"'


int int

I'" •
tr-

Altere o valor de z dentro do método . O val o r de x não se rá a ltera do ! O argumento passad o para o p arâmet ro z era ape n a s uma cópia de x . O mét odo não pode alterar os bits que estav am na variáve l x que o chamou .

void go(int z)

z = O;

I~

Não existem

1 P·. o =

Perguntas Idiotas

que aconteceria se o argumento que você quisesse passar fosse um objeto em vez de uma variável primitiva?

Você aprenderá mais sobre isso em capítulos posteriores , mas já sabe a resposta . A Java passa tudo por valor. Tudo. Porém ... Valor significa os bits existentes na variável. E lembre-se de que você não pode inserir objetos em variáveis; a variável é um controle remoto -- uma referência a um objeto. Portanto, se você passar a referência de um objeto para um método, estará passando uma cópia do controle remoto. Mas fique atento, temos muito mais há dizer sobre isso. Um método pode declarar diversos valores de retorno? Ou há alguma maneira de retornar mais de um valor?

R:

P:

! ,"""'\

r

.~-

• .,r..:.,

t( : Mais-;u ~en~s.·-U~ -método pode declarar somente um· valor de retorno. MAS ... Se -você qu iser retornar, digamos, três valores int, então, o tipo de retorno declarado pode ser uma matriz int. Insira esses tipos int dentro da
você está aqui >55

~~

...........--------------------------------------------------------------------------------------

argumentos e valores de retorno matriz e retorne-a . É um po~-º. mais complicado retornar diversos va lores com tipos diferentes; falaremos sobre isso em um capítulo posterior quando discutirmos o objeto ArrayList.

implicitamente onde um int for esperado. O chamador não se importará , porque o byte caberá perfeitamente no int que ele usará para atribuir o resultado. Você deve usar uma conversão explícita quando o tipo declarado for menor do que o que você estiver tentando retornar.

P: Tenho que retornar o tipo exato que declarei? R: Você poderá retornar qualquer coisa que possa ser um byte elevada a esse tipo. Portanto, pode passar

Lembrete: O Java acha o tipo importante!
Você não pode retornar uma Girafa quando o tipo de retorno for declarado como um Coelho. O mesmo ocorre com os parâmetros. Você não pode passar uma Girafa para um método que use um Coelho.

Tenho que fazer algo com o valor de retorno de um método? Posso apenas ignorá-lo?

O Java não exige que o valor de retorno seja usado. Você pode querer chamar um método com um tipo de retorno que não seja nulo, ainda que não se importe com o valor de retorno. Nesse caso, estará chamando o método pelo que ele executa internamente, em vez de pelo que retorna. Em Java, você não precisa atribuir ou usar o valor de retorno.

P: R:

r - - - - - DISCRIM INAÇÃO DOS PONTOS
- As classes definem o que um objeto conhece e o que ele faz. - As coisas que um objeto conhece são suas variáveis de instância (estado). - As coisas que um objeto faz são seus métodos (comportamento). - Os métodos podem usar variáveis de instância para que objetos do mesmo tipo possam se comportar diferentemente. - Um método pode ter parâmetros, o que significa que você pode passar um ou mais valores para ele. - A quantidade e o tipo dos valores que você passar devem corresponder à ordem e tipo dos parâmetros declarados pelo método. - Os valores passados para dentro e fora dos métodos podem ser elevados implicitamente a um tipo maior ou convertidos explicitamente para um tipo menor. - O valor que você passar como argumento para um método pode ser literal (2, 'c', etc.) ou uma variável com o tipo de parâmetro declarado (por exemplo, x onde x for uma variável int). (Há outras coisas que você pode passar como argumentos, mas ainda não chegamos lá.) - Um método deve declarar um tipo de retorno. Um tipo de retorno void significa que o método não retorna nada. - Se um método declarar um tipo de retorno que não seja void, deve retornar um valor compatível com o tipo declarado.

Coisas interessantes que você pode fazer com os parâmetros e tipos de retorno
Agora que vimos como os parâmetros e tipos de retorno funcionam, é hora de lhes darmos alguma utilidade prática: os métodos Getter e Setter. Se você quiser ser formal com relação a isso, pode preferir chamá-los de acessadores e mod(ftcadores. Mas desperdiçaria sflabas. Além do que, Getter e Setter se enquadram na convenção de nomeação Java, portanto, é assim que os chamaremos. Os método Getter (de captura) e Setter (de configuração) permitirão que você, bem , capture e cOl~flgure coisas . Geralmente variáveis de instância. A única finalidade de um método de captura é enviar, como valor de retorno, o valor do que quer que esse método de captura específico captu re. Portanto, não é surpresa que um método de configuração só ex ista para esperar a chance de receber o valor de um argumento e usá-lo para cOl ~fig urar uma variável de instânci a.
56

ElectricGuitar
brand numOfPickups( ) rockStarUse slt
~

getBrand( ) setBrand ( ) getNumOf Pickups ( setNumOfPi ckups ( getRockSta rUseslt setRockStarUs eslt
. ,,,.;
,~

convenções de .--..., nomeação si.gnifica que você est a rá /~ segtd.ndo um importante ) ~ pa.drão r)a,Vâ.J ) ,,~ ( ) ( )

----

1

Nota: usar essas

~1
"

-

~

capitu lo 4

os métodos usam variáveis de instância
cIass EIectricGuitar String brand ; int numOfP i ckups ; boolean rockStarUsesl t ; String getBrand() return brand;

1'-"

I

void setBrand(String aBrand) brand = aBrand ;

Irint getNumOfPickups() ( re turn numOfPickups;

void setNumOfP i ckups(int nUm) numOfPickups = num;

(

II'"""

boolean getRockStarUseslt() return rockStarUseslt;

,rrI
I

void setRockStarUse slt(boolean yesOrNo) rockStarUseslt = yesOrNo;

I

Encapsu lamento
Use-o ou arrisque-se a ser humilhado e ridicularizado.
Até esse momento tão importante, cometemos uma das piores falhas na 00 (e não estamos falando de violações menores como não usar 'B maiúsculo ' em BYOB). Não, estamos falando de uma Falha com 'F maiúsculo. Qual foi nossa transgressão vergonhosa? Expor nossos dados! Aqui estamos nós, apenas seguindo em frente sem sequer nos importarmos em deixar nossos dados expostos para que todos vejam e até mesmo mexam. Talvez você já tenha experimentado esse sentimento vagamente inquietante que surge quando deixamos nossas variáveis de instância expostas . Exposto significa alcançável através do operador ponto, como em:
theCat.height
=

-I

rf

I,......,

I,.......

1-lI'"""

I.)" ,

I

I~

27;

Pense nessa idéia do uso de nosso controle remoto para fazermos uma alteração direta na variável de instância do tamanho do objeto Cal. Nas mãos da pessoa errada, uma variável de referênci a (controle remoto) seria uma arma bem perigosa. Porque nada impediria isso:
theCat.height = Oi ( - - - - - opa! Não podemos deixar isso acontecer!

Seria péssimo. Precisamos construir métodos de configuração para todas as variáveis de instância e encontrar uma maneira de forçar os outros códigos a chamarem esses métodos em vez de acessar os dados diretamente.
I~

publ i c void setHeight (int ht) { Inserimos verificações para garantir uma if (ht > 9) { ~-----------------------------------­ altura mínima para o objeto Caé. height = ht;

T~'

i0
'1
I

Ao forçar todos os códigos a cllaIllã.z-em uzn método de cOl'lfigura r;ão, ~~de::r!c;;' pr?t"3g~r o o .bj-:to C~t- de alterações inaceitáveis no tamanho ..

""' -"

J,-,

I

-

você esta aqui

~

57

desenvolvedores profissionais

",S;:,;,,', ) :" 'C;:.;)SU,.~' i' ··~ ·

te)

Oculte os dados
Sim, é muito simples passar de uma implementação que esteja pedindo para receber dados inválidos para uma que proteja seus dados e seu direito de alteníla posteriormente. Certo, então como exatamente ocultar os dados? Com os modificadores de acesso public e private. Você está familiarizado com public - ele foi usado em todos os métodos main. Aqui está uma regra prática inicial para o encapsulamento (todas as isenções de responsabilidade referentes às regras práticas são aplicáveis): marque suas variáveis de instância com private e forneça métodos de captura e configuração públicos, para ter controle sobre o acesso. Quando você conhecer melhor o projeto e a codificação em Java, provavelmente fará as coisas de um a forma um pouco diferente, mas, por enquanto, essa abordagem o manterá seguro.

---.- f'; --------0 A .
/~

Tudo sobre o Java
Entrevista desta semana: Um objeto abre o jogo sobre o encapsulamento.

1
I

Use a Cabeça!: Qual é o grande problema do encapsu lamento? Objeto: Certo, você conhece aquele sonho em que está fazendo uma palestra para 500 pessoas quando subitamente percebe estar nu? Use a Cabeça!: Sim, já aconteceu conosco. É semelhante àquele da máquina Pilates e ... Bem, isso não importa. Certo, então você se sente nu . Mas além de estar um pouco exposto, há algum perigo? Objeto: Se há algum perigo? Algum perigo? [começa a rir] Ei, instâncias, ouviram isso, "Há algum perigo? ", ele pergunta? [rola de tanto rir] Use a Cabeça!: Qual é a graça? Me parece uma pergunta sensata. Objeto: Certo, vou explicar. É que [não consegue controlar o riso novamente] Use a Cabeça!: Posso pegar algo para você? Água? Objeto: Uau! Nossa. Não, estou bem . Falarei a sério. Vou respirar fundo. Certo. Prossiga. Use a Cabeça!: Então, de que o encapsulamento o protege? Objeto: O encapsulamento cria um campo de força ao redor de minhas variáveis de instância, portanto, ninguém pode configurá-las com, digamos, algo inapropriado. Use a Cabeça!: Você pode citar um exemplo? Objeto: Não é preciso ser um PhD. A maioria dos valores das variáveis de instância é codificada com certas definições sobre seus limites. Por exemplo, pense em todas as cclisas que não funcionariam se números negativos fossem permitidos. A quantidade de banheiros de um escritório. A velocidade de um avião. Aniversários. O peso de halteres. Números de celular. A potência de fornos de microondas. Use a Cabeça!: Entendo o que você quer dizer. E como o encapsulamanto permite a definição de limites? Objeto: Ao forçar os outros códigos a passarem por métodos de configuração. Dessa forma, o método de configuração pode validar o parâmetro e decidir se é viável. Ele poderá rejeitá-lo e não fazer nada ou lançar uma exceção (por exemplo, se houver um número de CPF nulo em um aplicativo de cartões de crédito) ou ainda arredondar o parâmetro enviado para o valor mai s próximo aceitável. O importante é o seguinte: você pode fazer o que quiser no método de configuração, contanto que não faça nada se suas variáveis de instância forem públicas. Use a Cabeça!: Mas às vezes vejo métodos de configuração que simp lesmente configuram o valor sem verificar nada. Se você tiver uma variável de instância que não tenha um limite, esse método de configuração não geraria uma sobrecarga desnecessária? Um impacto no desempenho? Objeto: O importante nos métodos de configuração (e também nos de captura) é que você pode mudar de idéia posteriormente, sem travar o código de ninguém! Imagine se metade das pessoas da empresa usasse sua classe com variáveis de instância públicas e um dia você percebesse, de repente, que "opa - há algo que não planejei para esse valor, terei que passar para um método de configuração". Você travaria o código de todo mundo. O interessante no encaps ul amento é que você pode mudar de idéia. E ninguém é prejudicado. O ganho no desempenho pelo uso das variáveis diretamente é tão pequeno que raramente vale a pena, se é que vale.

.Márque as variáveis de .instâncía coní 'private. Marque os métodos de corrflguh3çãoe captura com public.
"Infelizmente, Bill se esqueceu de encapsular sua classe Cat e acabou com um gato gordo." (Ouvido n o bebedouro.)

58

capi tulo 4

""'"

os métodos usam va riá veis de in stâ ncia

,-..
,-..

Encapsulando a classe GoodOog
class GoodDog { private int size;
~(~-----------------------------------

GoodDog
Torna a va.= iavel de

inscância

p~jvad~.

size
getSize( setS ize( bark( )
.
-~

/--[

Ir-I ........

,

public int getSize () return sizei

T0rna os métodos de captura e 'configuração ~blicos.
s) (

)

)

public void setSize (in t size -= s;

--"..

1~
1".-...

void bark() { if (size > 60) { System. out . println ("Wooof! Wooof!"); else if (size > 14) { System . out .println ("Ruff! Ruff''') ; e lse ( System . out . println("Yip! Yip ''' );

Ainda que os métodos não adici onem realmente uma neva funcionalidade, o interessante é ~Je você pode mudar de idéia pos teri ormente. Pode voltar e tcrnar um método mais seguro~ mais rápido e melhor.

class GoodDogTestDrive { public static vo id main (String[] args ) ( GoodDog one = new GoodDog(); o ne.setSize(70) ; GoodDog two = new GoodDog () ; two .se tSize(8) ; System.out.println ("Dog one : " + one.getSize ()) ; System . out . print ln(" Dog t wo : " + t wo . getSize()); one . bark( ) ; t wo . bark();

Qualquer local onde um valor . específico puder ser usado, uma chamada de-método que retorne esse tipo poderá ser empregada.
em vez de:
int x

,

=3
=

+ 24;

i: I
~

você pode usar:
int x 3 + one . getSize( ) ;

I: I"
f
Ir

!".-... 1,.....

ii

Como os objetos de uma matriz se comportam?
Exatamente como qualquer outro objeto. A única diferença é como você os capturará. Em outras palavras, como será o controle remoto. Tentaremos chamar métodos nos objetos Dog de uma matriz,:..._ - - - - - -__ .
~ Dec lare e crie uma matri z Dog, que
tenha 7 referências Dog . Dog[] pets ; pets = new Dog[7];

1

2

3

4

5

Dog

Dog

Dog

Dog

Dog

Dog

Dog[]

objeto de matriz Dog (Dog[ ])

pets [O] pets[l]

new Dog () ; new Dog() ;

______
peL:::;[O] . :seLSt-z-e(--:3U-) ;

'--_ _ _ _ _

l~I~I~ l?IQI~l~. l ) ~~~ DO~Og/
~_

int x = pets[O] . getSize() ; pets[11 . setSize(8) ;

Dog[]

objeto de mat riz Dog (Dog[ ])

--._------_ Dog Dog Dog

.....

você 83té aqui

.~

59
,-

-

inicializando variáveis de

i n s ti~f)ci êj

,-...,'

Declarando e inicializando variáveis de instância
Você já sabe que uma declaração de variável precisa de pelo menos um nome e um tipo:
int size; String name;

E sabe que pode inicializar (atribuir um valor) a variável ao mesmo tempo:
int size = 420; String name = "Donny";

Mas se você não inicializar uma variável de instância, o que acontecerá quando chamar um método de captura? Em outras palavras, qual será o valor de uma variável de instância antes de você a inicializar?
class PoorDog {

Declara duas variá,reis de private int size; ( ---------------------------------------- instância mas não atribui J private String name; (~----------------------------------- um valor
public int getSize() return sizei public String getName() return name;

".1

o

que esses métodos retornarão?
..-... :$

.'

~

,..-,
public class poorDogTestDrive { public static void main (String[] args) PoorDog one = new PoorDog ( ) ; O que voe€! System.out . println("O tamahho do cão é " + one.getSize()); ( - - - acha? Isso sera System.out.println("O nome do cão é " + one.getName()); (fl----------- compilado?
~:

1 ,

51

. ...,.

Não €'i preciso inicializar variáveis de instâ.ncia r

porque

elaB semp::$ têm um V"ê..lor padrão~ J:.JÚln.eros prim3.ti·J'os ( inclusive do tipo cha..:r) recebem o valer 0$ booleanos recebem fa1.so € variá:Fsis de referê.ncia de objeto ficam. com

'"

'.

valor

nulo~

(LemJ::J:.re~se

de que nulo significa apenas um controle remoto
nada~

que não e.stá controlando/programado para :referênci2~. porém sem '1..00 objeto real .. )

É

Q~~

A diferença entre variáveis de instância e locais
As variáveis de instância são declaradas dentro de uma classe, mas não dentro de um método . class Horse { private double height private String breed; II mais código.

15.2;

As variáveis locais são declaradas dentro de um método. class AddThing int a; int b = 12; public int add ( ) int total = a + b; return total;

As variáveis locais NÃO recebem um valor padrão! O compilador reclamará se você tentar usar uma variável local antes dela ser inicializada.
"" -1 "
) r
~

1

A ,r-. .~
.............. -.1

.

-

-]. 7

60

os métodos usam variáveis
As variáveis loca is DEVEi'] se r class Foo ( public void go() ini ci ali z adas antes de s er usadas!

de instância

{
~

j~
\

int x · int z = x + 3 ;

Não será compiLado! v-ocê pode declarar Jl sem _______________________________ um v alor, mas r assim qu e tentar USÁ~LO$ o

compiLador ficará confuso.

I'"" I I"

I

I~
\r-

Não existem.

1=

Perguntas Idiotas

P: E quanto aos parâmetros do método? Como as regras sobre variáveis locais se aplicam a eles? locais -- são declarados dentro do método R: Os parâmetros dos métodos são praticamente iguais às (bem, tecnicamente eles são declarados na lista de argumentos do método em vez de dentro do corpo dele, mas
variáveis

I~

ainda são variáveis locais e. não variáveis de instância) . Porém nunca serão inicializados, e você nunca verá uma mensagem de erro do compilador informando que uma variável de parâmetro não foi inicializada. Mas isso ocorre porque o compilador exibirá uma mensagem de erro se você tentar chamar um método sem enviar os argumentos de que ele precisa. Portanto, os parâmetros são SEMPRE inicializados, já que o compilador garante que esses métodos sejam sempre chamados com argumentos que correspondam aos parâmetros declarados para eles, e os argumentos são atribuídos (automaticamente) aos parâmetros.

Comparando variáveis (primitivas ou de referência)
Haverá situações em que você pode querer saber se duas variáveis primitivas são iguais. Isso é muito fácil, basta que use o operador = =. Em outras, pode querer saber se duas variáveis de referência apontam para o mesmo objeto da pilha. Também é fácil , use o operador = = . Mas você pode querer saber se dois obj etos são iguais. E para fazer isso, precisará do método .equals( ). A idéia de igualdade no que diz respeito a objetos depende do tipo de objeto. Por exemplo, se dois objetos String diferentes tiverem os mesmos caracteres (digamos, "ativo"), serão sign ificati vamente equivalentes, independentemente de serem dois objetos di stintos da pilha. Mas e quanto a um Cão? Você vai querer tratar dois Cães como se fosse m iguais se, por acaso, tiverem 6 mesmo tamanho e peso? Provavelmente não . Portanto, o fato de dois objetos diferentes serem tratados como se fossem iguais dependerá do que for relevante para esse tipo de objeto específico. Examinaremos a noção de ig ualdade entre obj etos novamente em capítulos posteriores Ce no Apêndice B), mas, por enquanto, temos que saber que o operador = = é usado apenas para comparar os bits de duas variáveis. O que esses bits representam não interessa. Eles são iguais ou não.

I

r~

Use = = para comparar duas variáveis primitivas ou saber se duas referências apontam para o mesmo objeto. Use o método equals( ) para saber se dois objetos diferentes são iguais.
(Como dois objetos String diferentes representando os caracteres de "Fred".)

Para comparar duas variáveis primitivas, use o operador

==

o operador =

pode ser usado para comparar duas variáveis de qualquer tipo, e ele comparará apenas os bits.

A instrução if (a= =b) ( ... ) examinará os bits de a e b e retornará verdadeiro se o padrão de bits for o mesmo (porém ela não verificará o tamanho da variável, logo, os zeros do lado esquerdo são ilTelevantes).
(há mais zeros no lado esquerdo do número inteiro, mas isso não únpoz·t " aqu i)

':..... i
r--

L_

int a = 3; byte b = 3; if (a = = b)

( II verdadeiro)

os padrões de bits sào os mesmos r portanto, essas duas
usa.rm:os
"Z

=

int

byte

você está aqui»>

61

---------------------------------------

igualdade

Para saber se duas referên~i.as ~~~~guail? (o que si9.':lifi~ª-q~~e_elas referenciam o mesmo objeto da pilha) use o operador = =

Os p adrões de bits
----S""i!3-

os mesmos para a.
~

Lembre-se de que o operador = = só leva em consideração o padrão de bits da variável. As regras serão as mesmas, sendo a variável uma referênci a o u um tipo prirrlitivo. Portanto, o operador = = retornará verdadeiro se duas vari áveis de referênc ia apontarem para o mesmo objeto' Nesse caso, não saberemos qual é o padrão de bits (porque não depende da JVM e essa ~ .

O'"
\

e C J po=tantc, serão iguais se usarmos = =

info em,ção ",ta," oco 'ta), m" ,"bemo, qu" q""qu,,' qoe

"i', m'6 o me,"", pom duo.< /

~fei;~c~, q:;;~:;;;:: ~om o m"nw ob}"o.
Foo c a;

f.1: : '
(
~ a ,

, ,

~:!:

,-..

.-

1: :: ;! ;; ;:~meiro)

:: :::::do,ro ;:
o Jav-a

O
foo

\'

~

~ :- ':ii

As rOSas Sao verme l has paSSar por valor é essa poesia é 1 ' PasSar Por ' . a eatoria
cOP~a

Oh, acha que d estúpido segu:~o e fazer melhor? Tente. subst· verso pel Substitua ~tua o Poema os seu própri nosso nunca o esquecera'. ~nte~ro Por SUas , o. Melhor ainda propr~as palav ras, e você

o que

é válido?

int a shor t c

ca1cArea(7, 12);
=

Dado o método a seguir, qu al das chamadas li stadas à direita são váli das? Insira uma marca de seleção próxima às c hamadas que forem válidas. (Alg um3 s in stru ções só foram incluídas para atribuir os valores usados nas chamadas do método.)
int ca1cl,rea ( in t heigh t, int width) return height * widt h ; (

7;

ca1cArea(c,15) ;

Mantenha-se

int d = ca1cArea(57) ; ca1cAre a(2,3 ) ; 10ng t
=

42; ca1cArea(t,17); ca1cArea( ) ;

à direita

int f int g

ca1cArea() ; byte h int j
=

=

ca1cArea(4 ,2 0);

calcArea( 2 ,3,5);

62 sapituio 4

os métodos usam variáveis de instância

Seja o compilador
Cada um dos arquivos Java dessa página representa um arquivofonte compl eto. Sua tarefa é personificar o compilador e determinar se cada um deles pode ser compilado. Se não puderem ser compilados, co mo você os corrigiria, e, se eles forem compilados, qual seri a sua saída?

A
class XC opy ( public static void main(String [] args) int orig XCopy x int y
= =

B
class Cloc k { String time; ( void setTime (Str ing t) time = t; (

42; new XCopy () ;

x . go(orig) ;

void getTime () { return time;

System . ou t.print ln(orig + " " + y); class ClockTestDrive ( public sta t ic void main(String [] args ) ( Clock c = new Clock(); c . setTime("124S"); String tod = c . getTime(); Sys tem. out .print l n("t ime: " + tod);

int go (in t arg ) { arg = arg * 2 ; return arg;

Quem sou eu?
Um grupo de componentes Java, vestidos a rigor, está participado do jogo, "Quem sou eu?" Eles lhe darão uma pista e você tentará adivinhar quem são, baseado no que disserem. Suponha que eles se mpre digam a verdade quando falam de si mesmos. Se por acaso disserem algo que possa ser verdadeiro para mai s de um deles, anote todos aos quais a frase possa ser aplicada . Preencha as linhas em branco próximas à frase com os nomes de um ou mais candidatos.

.

-..

Candidatos desta noite:
Variável de instância, argumento, retorno, método de captura, método de configuração, encapsulamento, public, private, passar por valor, método

Uma classe pode ter quantos quiser. _______________________________________ O método só pode ter um. _____________________________________________________________________________ Pode ser clevado
implicitamen~.

_________ _____ _________ ______________~

Prefiro minhas variáveis de instância privadas. Na verdade significa 'fazer uma cópia'. _____ _________________________________ Só os métodos de configuração devem atualizá-Ios. _ _ __ __ __ _______________________ .Um
m~odopode~rmui~sdcl~.

_ _ _______ ____ __ _____ __ ______________~

r

Retorno algo por definição. ________________ __________ ______________ Não devo ser usado com variáveis de instância. ___________________________ _______ Posso ter
mu~o s ~gunlento s .

_________ _ _____________ _____ _ _____________

.,,-...

Por definição. uso

Ulll

argulnento. _____~~~~~~~~~~~-~~~~~~~---------------____

~udama c riaro encap s ulrunenw. -----------------------------_______

Estou sempre sozinho. _____________________ _________________ _ _ _____
você está aqui
17

63

quebra-cabeças: rnensag&ns misturadas
JJJ1LPrOgrama Java. c urto está listado à sua di r~itJ.. Doi ~b tocQ~ d9--p....m.grmTIq estão faH~ndo. Seu desafio é comparar os blocos de código candidatos (a seguir) com a saída que você veria se eles fo ssem inseridos .

I":'\~­

q;;;s

Mensagens misturadas

Nem todas as linhas de saída serão usadas, e algumas delas podem ser usadas mais de uma vez. Desenhe linhas conectando os bl ocos de código candidatos à saída de linha de com ando correspondente.

'"'
public c l ass Mix4 { int counter = int count = Mix4 [] m4a int x =

"

o;
{

public static void main(String [] args)

o;
=new Mix 4[20];

o;

Candidatos:
x < 9

Saídas possíveis:
whi1e ( m4a[x] count count new Mi x4 (); c ount + 1 ; count + m4a[x] .maybeNew(x);

index < 5
k

m4a[x ] .counter = m4a[x] . counter + 1;

x = x + 1; System.out . println(count + "
" + m4a[1].counter);

pub1ic i nt maybeNew( i nt index)
F~~~

{.

x < 19
if ( 1 _ _ _ .... 1)

Mix4 m4 = new Mix4(); m4 . counter = m4.counter + 1; re turn 1 ; return O;

64

capítulo 4

~

os métodos usam variáveis de instância

,I

l~

I~

Quebra-cabeças na Piscina
Sua tarefa é pegar os trechos de código da piscina e inseri-los nas linhas em branco do código. Você pode não usar o mesmo trecho mais de uma vez e não precisa empregar todos os trechos. Seu objetivo é criar uma Classe que seja compilada e executada produzindo a saída listada.

i .-., .
\

!

I

public class Puzzle4 ( public static void main(String [ ) args) int y int x while (x
1;
O;
=

(

int result
<

O;
(

6)

Saída

y

y

* 10;

x = 6;

1""-"
i
I~

while (x > O) result

(

!

Ir"

result +

I~

System.out . println("result " + result);

i
rI""'

! !--..

l~

class int ivari ______ doStuff(int if (ivar return else ( return
>
- - - -)

(

100)

(

Nota : Cada trecho de código da piscina pode ser usado só uma vez!

obs[xl . doStuff(factor); obs[xl . doS t uff(x); ivar + ivar * Xi ivar ivar * x; factor ivar * x; public obs[xl .ivar = y; private

factor; Puzzle4 (2 + factor ) ; Puzzl e 4b (5 - factor); Puzzle4b( factor; x = x + 1;
x

= x-I;

int short

obs [x l obs [ )

new new Puzzle4b( new

-l--\~
1;.<-

\.:....
.irl _

.

você está aqui

~

65

quebra-cabeças: um pequeno mistério

Um pequeno mistério ~~III!..

Quando Buchanan encostou sua arma em Jai, ele congelou. Jai sabia que Buchanan era tão estúpido quanto feio e não queria assustar o grandalhão. Buchanan ordenou que ele entrasse no escritório de seu chefe, mas como Jai não tinha feito nada de errado (ultimamente), pensou que conversar com Leveler, o chefe de Buchanan, não seria tão ruim. Ele vinha movimentando muitos estimulantes neurais no lado oeste nos últimos tempos e achava que Leveler ficaria satisfeito. Estimulantes do mercado negro não geravam as maiores quantias que circulavam, mas eram inofensivos. A maioria dos viciados em estimulantes que ele conheceu desistiu após algum tempo e ' voltou à vida normal, talvez um pouco menos concentrada do que antes. O 'escritório' de Leveler era um esconderijo de má aparência, mas quando Buchanan o empulTou para dentro, Jai pôde ver que tinha sido modificado para fornecer toda a velocidade e segurança extra que um chefe local como Leveler poderia esperar. "Jai meu caro", sussurrou Leveler, "bom te ver novamente". "A recíproca é verdadeira ... ", disse Jai, sentindo a malícia por trás do cumprimento de Leveler, "devíamos estar quites, Leveler, há algo que eu não saiba?" "Ah! Você está fazendo tudo direitinho, Jai, sua carga foi preenchida, mas tenho sentido, digamos, algumas 'falhas' ultimamente ... " disse Leveler. Jai recuou involuntariamente, ele tinha sido um ótimo hacker no auge de sua can'eira. Sempre que alguém descobria como burlar a segurança de um sistema, uma atenção indesejada se voltava para Jai. "Não fui eu meu caro", disse Jai, "não vale a pena. Eu me aposentei das invasões, agora cuido dos meus próprios negócios". "Sim, sim", sorriu Leveler, "tenho certeza de que dessa vez não foi você, mas vou perder grandes margens de lucro até que esse novo hacker seja eliminado!" "Bem, boa sorte Leveler, me deixe aqui e eu conseguirei mais algumas 'unidades' para você antes de terminar por hoje", disse Jai , "Receio que não seja tão fácil, Jai, Buchanan disse que agora você está trabalhando com a J37NE", insinuou Leveler. "A Edição Neural? É verdade que me divirto um pouco com ela, e daí?", Jai respondeu sentindo-se um pouco preocupado. "A edição neural é como deixo os viciados em estimulantes saberem onde poderão encontrar a próxima dose", explicou Leveler. "O problema é que algum viciado ficou sem o estimulante por tempo suficiente para descobrir como invadir meu banco de dados WareHousing". "Preciso de alguém que pense rápido como você, Jai, para examinar minha classe J37NE StimDrop; os métodos, as variáveis de instância, o conjunto todo, e descobrir como estão invadindo. Você terá ... ". "Ei!", exclamou Buchanan, "não quero nenhum hacker como Jai examinando meu código!", "Calma grandão", Jai percebeu uma chance, "Tenho certeza de que você fez um ótimo trabalho com seu modificador de aces .. ,", "Você acha mesmo, embaralhador de bits!", gritou Buchanan, "Deixei públicos todos os métodos usados pelos viciados, para que eles pudessem acessar os dados do site, mas marquei todos os métodos críticos do WareHousing como privados. Ninguém do ambiente externo pode acessar esses métodos meu caro, ninguém!" "Acho que posso identificar a falha, Leveler; o que diz de deixarmos Buchanan aqui e darmos uma volta pelo quarteirão", sugeriu Jai. Buchanan procurou sua arma, mas a mão de Leveler já estava em seu pescoço, "Deixe estar, Buchanan", sorriu Leveler, "Largue a arma e saia, acho que Jai e eu temos alguns planos a pôr em prática".

"

De que Jai suspeitou? Ele conseguirá sair do esconderijo de Leveler com todos os ossos no lugar?
66
4

os métodos usam variáveis de instância

Soluções dos Exercícios

B

class Clock { String time; void setTime (Str ing t) time = t;

{

String getTime ( )
return time;

Nota: os métodos 'de captura' têm um tipo de retorno por definição.
(

A
A classe 'XCopy' será compilada e executada na forma em que se encontra! A saída será: '4284'. Lembre-se de que a Java passa por valor (o que significa passar por cópia), a variável 'orig' não será alterada pelo método go( ). Uma classe pode ter quantos quiser. O método só pode ter um . Pode ser elevado implicitamente. Prefiro minhas variáveis de instância privadas. Na verdade significa 'fazer uma cópia'. Só os métodos de configuração devem atualizá-Ias. Um método pode ter muitos deles. Retorno algo por definição. Não devo ser usado com variáveis de instância. Posso ter muitos argumentos. Por definição, uso um argumento. Ajudam a criar o encapsulamento. Estou sempre sozinho.

class ClockTestDrive { public sta tic void main (St ring [J args) Cl oc k c = new Clock(); c .s etTime("1245") ; String tod = c.getTime(); System . out.println("time : " + tod);

variáveis de instância, métodos de captura e configuração retorno retorno, argumento encapsulamento passar por valor variáveis de instância argumento método de captura public método método de configuração métodos de captura e configuração, public, private retorno

Soluções dos Quebra-cabeças
public class Puzzle4 ( public static void ma in (String [J args) Puzz1e4b [ ] obs = new Puzz1e4b[6]; int y = 1; int x = O; int result = O; while (x < 6) ( obs[x] = new Puzz1e4b( ); obs[x] • ivar = y; y y * 10; x = x + li
x = 6; while (x > O) ( x = x - 1; result = result + obs[x].doStuff(x);

Resposta do peque·no mistério ...
Jai sabia que Buchanan não era muito inteligente. Quando falou sobre seu código, Buchanan não mencionou as variáveis de instâncias. Jai suspeitou que embora Buchanan tivesse realmente manipulado seus métodos corretamente, não tinha marcado suas variáveis de instância com private. Esse deslize pode facilmente ter custado milhões a Leveler.

Candidatos:

Saídas possíveis:

System . out.println("result • + result);
x

class Puzz1e4b ( int ivar; pub1ic int doStuff(int factor ) i f (ivar > 100) { return ivar * factor; else ( return iva~*_~_: Jactor);

index < 7

7 7 20 1 205

---~-----=-=---'----_.- - _. -_._-- - - - - x < 19 __________
index < 1

você está aql:i

iii'

67
-

~
j~

5 escrevendo u

programa

Ir'\ Ir'\ I

Métodos Extra Fortes

I:
I

I~

Fortaleceremos nossos métodos. Você esmiuçou as
variáveis, brincou com alguns objetos e escreveu um pouco de código. Mas estávamos vulneráveis. Precisamos de mais ferramentas. Como os operadores. Precisamos de mais operadores, para que possamos fazer algo um pouco mais interessante do que, digamos,
(.'~

latir. E loops. Precisamos de loops, mas o que há de errado com os

discretos loops while? Precisamos de loops for se quisermos fazer algo sério. Poderia ser útil gerar números aleatórios. E converter
uma string em um inteiro, sim, isso seria avançado. É melhor

aprendermos isso também. E por que não aprender tudo criando algo real, para sabermos como é escrever (e testar) um programa a partir do zero. Talvez um jogo, como a Batalha Naval. Essa é uma tarefa pesada, portanto, precisarei de dois capítulos para terminar. Construiremos uma versão simples neste capítulo e, em seguid 9 , uma mais poderosa e sofisticada no Capítulo 6.

este é unl novo

69

construindo "',

i000

rea'

Construiremos um jogo no e_ _ st ilo_B_ talha.--,--,"",,,-,,-,-,,-,-~_-------=V< :.=c~ vai _ a __ N a v~ I : =--::o con§truJr çUOqº_Sil'lk a "Sink a Dot Com" Dot Com , com uma grade 7 x 7 e
Será você contra o computador, mas diferente do jogo de Batalha Naval real , aqui nenhum navio será nosso. Em vez di sso, sua tarefa será afundar os navios do computador no menor número de tentativas. Ah, e não afundaremos navios. Eliminaremos Dot Coms (empresas na Internet). (Demonstrando assim a importância das empresas para que você possa avaliar o custo deste livro.) Objetivo: afundar todas as Dot Coms do computador no menor número de tentativas. Você receberá uma classificação ou nível, baseado em como foi seu desempenho. Preparação: quando o programa dojogo for iniciado, o computador inserirá três DotComs em uma grade virtual 7 x 7. Concluída essa etapa, o jogo solicitará seu primeiro palpite. Como você jogará: ainda não aprendemos a construir uma GUI, portanto essa versão funcionará na linha de comando. O computador solicitará que você insira um palpite (uma célula), que deve ser digitado na linha de 'comando como "A3", "CS" , etc. Em resposta a seu palpite, você verá um resultado na linha de comando, "Correto", "Errado" ou "Você afundou a Pets.Com" (ou qualquer que seja a Dot Com de sorte do dia). Quando você tiver eliminado todas as três Dot Coms, o jogo terminará exibindo sua classificação.
grade 7 x 7
A
;-

três Dot Coms. Cada Dot Com ocupa três células. parte de interação do jogo
I

.,.i..

.,

B

c:

c
D

()

O

·N ·

(!)

o

' Fets.cc m

l.

E

F

G

A~

kMe.( om
4

r
6
\~célu.l aH

o

1

2

3

5

COlileça em: zero, como a.s matrizes ,.Jz:va

i

cada quadrad"o é uma

Primeiro, um projeto de alto nível
Sabemos que precisamos de classes e métodos, mas como eles devem ser? Para responder isso, prec isa mos de mai s informações sobre o que o jogo deve fazer.
,!

.'

-

escrevendo um programa

Primeiro, temos que descrever o fluxo geral do jogo. Aqui está a idéia básica:

Um círculo significa
inicio ou fim

Ct O usuário
~

inicia o jogo

O jogo cria três Dot Coms

Ct

~ O jogo insere as três Dot Coms e m
uma grade virtual

,...._....._-..,
Preparação do jogo

~

Um retângulo é usado p ara representar uma ação

Et O

jogo começa

Repita as etapas a seguir até não haver mais Dot Coms :

~ Sol ic ita a o usuário um palpite
("A2" ,
"CD",

etc.)

~ Confronta o palpite do usuário com
as Dot Coms para procurar um acerto, um erro ou uma eliminação. Toma a medida apropriada: se for um acerto, excluir a célula (A2, D4, etc.). Se for uma eliminação, excluir a Dot Com.

remove célula do local

o

remove

O jogo termina
Fornece ao usuário uma classificação, baseando - se na quantidade de palpites.

Dot Com

um losango represe nta um p onto de d eci s ão
sim

Agora temos uma idéia do tipo de coisas que o programa precisa fazer. A próxima etapa é definir de que tipos de objetos precisaremos para fazer o trabalho. Lembre-se, pense como Brad em vez de

classificação do usuário

.-,
\

Uau! Um diagrama de fluxo real

o "Jogo Dot Com Simples"
Uma introdução mais amigável
Parece que precisaremos de pelo menos duas classes, uma classe Game e uma classe DotCom. Mas antes de construirmos o jogo Sink a Doi Com completo, começaremos com uma versão simplificada, o Jogo Doi Com Simples. Construiremos a versão simples neste capítulo, seguida pela versão sofisticada que construiremos no próximo capítulo. . Tudo será mais simples nesse jogo. Em vez de uma grade 2-D, ocultaremos a Dot Com em uma única linha. E em vez de três Dot Coms, usaremos uma. No entanto, o objetivo será o mesmo, logo, o jogo ainda precisará criar uma instância da Dot Com, atribuir a e!a um local qualquer na linha, solicitar a entrada do usuário e, quando todas as células da Dot Com tiverem Sido adivinhadas, o jogo terminará. Essa versão simplificada nos ajudará muito na construção do jogo . completo. Se conseguirmos fazer essa versão menor funci onar, poderemos convertê-I a na versão mais f!-,,~~~_,;;~omplexa posteriormente. _ __ ,
____ m..~In( ). Em outras palavras, quando o programa for iniciado e main( ) começar a ser executado, ele criará uma

f · ' \ __ .

"....,. .'

Ne~sa versão simples, a classe Game não terá variáveis de instância, e todo o código do jogo ficará no método

n

você está aqui )-

71

1#

versão mais simples do jogo
e somente uma instância da Dot Com, selecionará um local • para ela (três células consecútivas -na -ÓillcãTinha virtuardesete - - - - - - ---'" células), solicitará ao usuário um palpite, verificará esse palpite e repetirá isso até todas as três células terem sido adivinhadas_ Lembre-se de que a linha virtual é ... Virtual. Em outras palavras, ela não existe em nenhum local do programa. Contanto que o usuário e o jogo saibam que a Dot Com está oculta em três células consecutivas entre sete delas (começando em zero), a linha propriamente dita não terá que ser representada no código. Você pode ficar tentado a construir uma matriz de sete ints e, em seguida, atribuir a Dot Com a três dos sete elementos da matriz, mas não é preoiso fazer isso. Tudo de que precisamos é uma matriz que contenha apenas as três células que a Dot Com ocupa. o jogo

é iniciado , cria UMA Dot Com e , õeITne um1.õCà1- para ela em crês células da linha única de sete células . Em vez de "A2", C4", etc ., os locais são apenas números inteiros . Por exemplo: 1 , 2, e 3 são os locais das células nessa figura :

o

1

2

3

4

5

6

o jogo c omeça a ser disputado. ~ Solicitará um palpite ao usuário e, em , seguida, verificará se ele acertou alguma das três células da Dot Com_ Se houver um acerto, ele incrementará a variável numOfHits. o jogo terminará quando todas as t r ês ~células tiv erem sido adivinhadas (a
variáve l numOfHits será igual a 3) e informará ao usuário quantos palpites e l e usou para afundar a Dot Com_

Uma interação completa do jogo

Desenvolvendo uma classe
Como programador, provavelmente você tem uma metodologia/processo/abordagem para escrever código. Bem, nós também _Nossa seqüência foi projetada para ajudá-lo a ver (e aprender) o que pensamos quando trabalhamos na codificação de uma classe. Não se trata necessariamente da maneira como nós (ou você) escrevemos códigos no dia-a-dia. É claro que, nesse contexto, você seguirá a abordagem que suas preferências pessoais, o projeto ou seu chefe impuserem_ Nós, no entanto, podemos fazer o que quisermos_ E quando criamos uma classe Java como uma "experiência de aprendizado", geralmente o fazemos desta forma: - Definimos o que a classe devefazer. - Listamos as variáveis de instância e métodos. - Escrevemos um código preparatório para os métodos. (Você verá isso em breve.) - Escrevemos um código de teste para os métodos.

o

poder do cérebro

Flexione esses dendrites. Como você definiria que classe ou classes construir prirneiro, quando estiver escrevendo um programa? Supondo que todos os programas, exceto os menores, precisem de mais de uma classe (se você estiver seguindo os bons princípios da 00 e não tiver uma classe que execute muitas tarefas diferentes), onde iniciaria?

- Implementamos a classe. - Testamos os métodos. - Depuramos e reimplementamos quando necessário .
- Agradecemos por não ser necessário testar nosso assim chamado aplicativo de experiência de aprendizado com usuários ativos reais .
."

72 capítulo 5

escrevendo um programá

'"
I,"",

I

As três coisas que escreveremos para cada classe:
código preparatório

I
I~
I~

Essa barra será exibida no primeiro conjunto de páginas para lhe mostrar em que parte você está trabalhando. Por exemplo, se você encontrar essa figura na parte superior de uma página, significa que estará trabalhando no código preparatório da classe SimpleDotCom.
classe Simpl e DotCom código preparatório

I~

~
o

Para fazer:
classe SimpleDotCo m
di.go nreparatório .. escreva o co . I;" i 'di go"de teste _ escreva o co .
' o

I
1 -

código preparatório
Um tipo de pseudocódigo, para ajudá-lo a enfocar a lógica sem se preocupar com a sintaxe.

,c.tA '0. ' di~6~lava final _ escreva o CO~8 ,'i' o , .
o• •

código de teste
Uma classe ou os métodos que testarão o código real e avaliarão se ele está fazendo a coisa certa.

cl~s~e

SimpleDotcomGam
0

código real
A implementação real da classe. Trata-se do código Java real.
código preparatório

' dicro preparatório _ escreva o co ° . o' código de teste (não1 escreva o va'o códicroJava final _ escre '"
00 -

SimpleDotCom

}-

~I ~

-

int[] locationCells int numOfHits String checkYouself(String guess) void s elfLoca ti onCel ls (int[] loc )
~

i
.-o:.
~

~

Você terá uma idéia de como o código preparatório (nossa versão do pseudocódigo) funciona quando exarrunar esse exemplo. Ele é como um intermediário entre o código Java real e uma descrição simples da classe em português. A maioria dos códigos preparatórios inclui três partes: declarações de variáveis de instância, declarações de métodos, lógica dos métodos. A parte mais importante do código preparatório é a lógica dos métodos, porque ela define o que tem que acontecer, que posteriormente converteremos em como, quando escrevermos realmente o código do método.

~ --.

,-

'"'

Declare uma matriz int para armazenar os l oca is das cé lul as. Chame-a de locationCells. Declare um int para a rmazenar o número de acertos. Chame-o de numOfHits e configure-o com O. Declare um método checkYourself( ) que us e uma String para o palpite do usuário (" 1" , "3", etc . ), veri fique a string e retor ne um resultado que represente um "acert o", "erro" ou "eliminação" . Declare um método de configuração setLocationCells( ) que use uma matriz int conte ndo os t r ês l ocais das c élulas na forma de números inteiros (2, 3, 4 , etc .) . Método:
String chec1r:Yourself(String

~ol ~ ..

userGuess)

Capture o palpite do usuár i o como um parâme tro de String Converta o palpite do usuário em um int Repita iss o para cada local de célula da matriz int
II Confronte o palpi te do usuário com o local da célula

Se o palpite do usuár i o estive r cor r eto Incremente o número de acertos
II Verifique se essa foi a última célula :

L
L

Se o número de acertos for i gual a 3, retorne "eliminação" como resultado Caso contrário não terá sido uma eliminação, portanto, retorne, "correto"

End If

Caso contrário o palpite do usuário não estará correto, portanto, re torne "errado"

_ _=~T.l: -.c..J.l~.l...L

Fim da iteração Fim do método

você está aqui fi>

73

.. ~

.'

classe SimpieDo:Ccm
Método:

void setLoc:ationCells (int l1 c:ellLoc:ations)

Capture os l oca is das c é lul as como um parâmetro de matriz int Atribua o parâme t r o d os locai s das células à v ar i ável d e ins tância desse s l o c a i s F im d o método
código preparatório

cõdi.go de' teste

Escrevendo a implementação dos métodos
Escreveremos o código real do método agora e faremos essa belezinha funcionar. .
Antes de começarmos a codificar os métodos, faremos uma pausa para escrever algum código que os teste. É exatamente isso, escreveremos o código de teste antes de haver algo para testar! O conceito de escrever o código de teste primeiro é uma das práticas da Extreme Programming (XP) e ela pode tornar mais fácil (e rápida) a criação de seu código. Não estamos dizendo necessariamente que você deva usar a XP, mas gostamos da parte sobre escrever os testes primeiro. E o termo XP soa bem.

Extreme Programming (XP)
A Extreme Programming (XP) é uma novidade no mundo da metodologia de desenvolvimento de softwares. Considerada por muitos "a maneira como os programadores querem realmente trabalhar", a XP surgiu no fim dos anos 1990 e tem sido adotada por empresas que vão da loja de garagem com apenas duas pessoas à Ford Motor Company. O destaque da XP é que o cliente obtém o que deseja, quando deseja, mesmo quando as especificações são alteradas na última hora. A XP se baseia em um conjunto de práticas testadas que foram projetadas para funcionar em conjunto, embora muitas . pessoas selecionem algumas e adotem somente uma parte das regras. Essas práticas incluem coisas como: Criar versões pequenas, mas freqüentes. Desenvol ver em ciclos repetitivos. Não inserir nada que não esteja na especificação (não importa o quanto você fique tentado a criar funcionalidades "para uso futuro"). Escrever o código de teste primeiro. Não seguir prazos apertados; cumprir as horas normais. Redefinir (aperfeiçoar o código) quando e onde notar a oportunidade. Não lançar nada que não tenha passado por todos os testes. Definir prazos realistas, baseando-se em versões pequenas. Manter a simplicidade. Programar em pares e com rotatividade para que todos conheçam bem tudo sobre o código.

Escrevendo o código de teste da classe SimpleDotCom
Precisamos escrever um código de teste que consiga criar um objeto SimpleDotCom e executar seus métodos. Para a classe SimpleDotCom , só nos preocupamos realmente com o método checkYours e ~f( ), embora seja preciso impl ementar o método setLocationCells( ) para que o método checkYourse(f( ) seja executado corretamente. Examine bem o código preparatório a seguir, do método checkYourse'=f( ) (O método (setLocationCells( ) é um método de configuração simples, portanto, não nos preocuparemos com ele, mas em um aplicativo 'real' poderíamos querer um método 'de configuração' mais robusto, que pudéssemos testar.) Em seguida, pergunte para você mesmo : "Se o método checkYourself( ) fosse implementado, que códi go de teste eu poderi a escrever qu e me provasse que ele está fun cionando corretamenteT'
74 cap itulo 5

escrevendo um programa

Baseado nesse código preparatório:
Método:

String cbeckYourself(String userGuess)

Capture o palpite do usuário como um parâmetro de String Converta o palpite do usuário em um int Repita isso para cada local de célula da matriz int
II Confronte o palpite do usuár i o com o local da célula

Se o palpite do usuário estive r correto

I ....,
I~

Incremente o número d2 acertos
II verifique se essa foi a última célula:

Se o número de acertos for igual a 3, retorne "eliminação" como resultado Caso contrário não terá sido uma eliminação, portanto, retorne "correto" End If Caso contrário o palpite do usuário não estará correto, portanto, retorne "errado" End If Fim da iteração Fim do método

Aqui está o que devemos testar:
1 Instanciar um objeto SimpleDotCom.

·1

2 . Atribuir um local para ele (uma matr iz de 3 in ts, como {2, 3, 4}) . 3 . Criar uma String que represente um pa lpi te do usuário ("2" , "O", etc.) . 4. Chamar o método checkYourself( usuário fictício. ), passando para ele o palpite de

1 ~l~

~I
.<

~I

,J~-

5 . Exibir o resultado para ava li ar se está co rreto ("bem-sucedido" ou "com falhas").

1

w :iI ,f-

Não existem

Perguntas Idiotas
que ainda não existe?

P·. Talvez eu não esteja entendendo alguma coisa aqui, mas como exatamente executar um teste em algo

Isso não é possível. Nunca dissemos que você começaria executando o teste; começará escrevendo o teste. Quando estiver escrevendo o código de teste, você não terá nada em que usá-lo, portanto, provavelmente não poderá compilá-lo até escrever o código 'stub' que possa ser compilado, mas isso fará com que o teste falhe (por exemplo, retornando nulo).

R:

., ~L .,
~

ato de planejar (e escrever) o código de teste ajudará a clarear seus pensamentos sobre o que o método propriamente dito precisa fazer. Assim que seu código de implementação estiver concluído, você já terá um código de teste apenas esperando para validá-lo. Além disso, você sabe que, se não o fizer agora, nunca o fará. Há sempre algo mais interessante a fazer. . O ideal seria escrever um pequeno código de teste e, em seguida, criar apenas o código de Implementação que você precisa que passe no teste . Depois escreva um pouco mais de código de teste e crie ··-apenas o novo código de implementaçao que tera que passar nesse novõ testê-:f.\Caaã repetiçãauu teste, você ~xecutará todos os testes já escritos, para que continue a avaliar se seus últimos acréscimos ao código não Interrom perão código já testado. você está aqui
~

P: R: o

Ainda não entendi. Por que não esperar até o código ser escrito e, então, projetar o código de teste?

75

classe SimpleDotCom

código preparatório

e6diqo de

Código de teste da classe SimpleDotCom

public class SimpleDotComTestDrive { public static void rnain (String[] args) { SimpleDotCom dot = new SimpleDotCom() i int[] locations
=

(~-------------

instancia um objeto SilnpleDotCom cria uma lnatriz int para o local das dot com (3 ints consecutivos entre 7 possíveis) chama o método de configuração na variável dot com fictício

{2,3,4}i

(~----------------

dot. setLocationCells (locations)

i ( _ _ _ _ _ _ _ _ _ _ __

String userGuess = "2"i ( - - - - - - - - - - - - - - - - - - cria um palpite de usuário
chaw~

o método cneckYourself( )

String result = dot.checkYourself(userGuess) i ~(------­ no objeto dot com e passa para ele o palpite fictício String testResult = "failed"i if (result.equals("hit") { se o palpite f i ctício (2 ) testResult = "passed"i ( __________________ retornar um ltacerto N z o código
}

estará
(~---------------------

f~~cionando

System.out.println(testResult)i
}
}

e,dbe o resu ltado do teste (bem-sucedido ou com falhas)

Aponte seu láp is

Nas próximas páginas implementaremos a classe SimpleDotCom e posteriormente retornaremos à classe de teste. Se examinarmos o código de teste anterior, o que mais deve ser adicionado? O que não estamos testando nesse código, que deveríamos testar? Escreva suas idéias (ou linhas de código) a seguir:

(

.... .

"i
~--i
"~

~

,~

/"

,

.~
.............. ,~
'{i

,., l
,..-

r:~
r--

j

:~

l I

76

capitulo 5

escrevendo um programa

código
de teste
I ~

I~

I

o método checkYourself( )
Não há uma conversão perfeita de código preparatório para código Java; você verá alguns ajustes, O código preparatório nos deu uma idéia muito melhor do que o código precisa fazer e agora temos que encontrar o código Java que cons iga definir a maneira de fazerEm segundo plano, pense em que partes desse código você pode querer (ou ter que) aperfeiçoar', Os números dentro do círculo são para indicar as coisas (recursos de sintaxe e linguagem) que você ainda não viu, Elas são explicadas na outra página,

Capture o palpite do usuario
Converta o palpi t.e ('..0

public Str i ng c heckYourse lf(St ri n g int guess

'stringGue ss )

=

Integer,parselnt(stringGue ss); (

®

usuario .em um int

um

converte a String em int

String result

"miss";

cria uma variável para armazenar o resultado que retornaremos. ( : - . - - - - - - - - - - - - Insere "miss" como o padrão (isto é, estamos presumindo que

ocorrerá

u..'1l \l erro""")

Repita is so pará cada célula (la ma't:r::L:-:; int

for

®in t (

cell

loc at ionCells ) { ( ----------------

repete para cada célula da matriz locationCells (cada local de célula do objeto)

Se o palpite. do usuáric est.iver corr eto
Incremente c nUITlE:ro d(.;?acertos
,,..-...,

if

(guess

==

cell)

resul t = "h,® numOfHits++; ~

;_============== <:

compara o palpite do usuário com esse ( - - - - - - - - - - - - - elemento (célula) da matriz tivemos um aoerto!

sai do loop, não é break; (~------------------­ preciso testar as outras células II fim do teste if II fim do loop for
! i Verifique se essa foi a última célula Se o número de acert:os ror igua l a 3
Retorne "e liminação" come resultado
Caso contrário D&.O terá sido uma eliminação: portanto, Retorne, ~'co rreto"

@)

if

(numOfHits

locationCells . length)

estamos fora do loop, mas vejamos se já terminamos (acertamos { ( ------- 3 vezes) e alteramos a string do resultado
para

result = "kill"; II fim do teste if

nkill,r

exibe o resultado para o usuário System.out.println(result); ' ( ----------------------- (l1Miss H r a menos que seja alterado para nHit N ou nKill")
retorna o resultado return re s ult; ~( ~-----------------------------------­ para o método chamador II fim d o método

Caso contrário Retorne "errado "

~--

você está aqui

~

77

.,,-,. .

-

classe SirnpleDotCorn

código preparatório

As novidades o que ainda não vimos se encontra nesta página. Pare de se preocupar! O resto dos detalhes está no final do
capítulo. Isso é o suficiente para que você possa continuar.
Um método da
c~asse

Integer

que sabe como llconverter H uma string no inteiro que

ela representa. Uma classe que com a Java. Usa uma St ring.

iTem

Q) Conve r tendo

u ma string em um int

~
'cell

Integer.parseInt(U3")

I
{ }

Leia essa declaração do Ioop for des ta forma: "repí ta para cada elemento da matr iz 'locationCells': extraia o próximo elemento da matriz
e atribua-o à variável int
r.
N

o sinal de dois-pontos (:)
significa "de", portanto,
o conjunto todo significa
,!'para cada valot ínt DE

locatíonCe1.ls ... "

®

O l oop

for

~

j
for (int cell locationCells)
A matriz que o loop percorrerá. A cada vez que o Ioop for percorrido, o próximo elemento da matriz será atribuído à variável "cell ". (VereIl10S mais sobre .i s so no final deste capítulo.)

Declara uma variável que armazenará um elemento da matriz. A cada vez que o loop for percorrido, essa variável (nesse caso uma variável int chamada "cell") r armazenará um elemento diferente da matriz, até que não haja mai s elementos (ou o código faça uma "interrupção" .. . Consulte o item 4 a seguir).

1

®

O operador pós-incremento

numOfHits++

o sinal ++ significa somar ~ ao que quer venha antes (em outras palavras, incrementar " ~ em 1).
numOfHits++ é o mesmo (neste caso) que dizer numOfHits = numOfHits + ~, exceto por ser um " pouco mais eficiente.

® I ns trução

break

breaki

Fará você sair de um loop. Imediatamente. Neste exato momento. Sem iteração, nenhum teste booleano, .">..~i"!: __"!:fl~~"!:!

------------------------------------------------------------------------" Perguntas Idiotas
Não existem

o que aconteceria em Integer.parselnt( ) se você passasse algo que não fosse um número? A instrução reconhece números por extenso, como em "three"?
Integer.parselnt( ) só funciona com strings que representem os valores ascii dos dígitos (O, 1, 2, 3, 4, 5, 6, 7, 8, 9) . Se voçê . entar converter algocomo "two" ou "blurp", o código será interrompido no tempo de execução. (Por t interrompido, queremos dizer na verdade que ele lançará unia exceção, mas não falaremos sobre exceções até chegarmos ao capítulo sobre elas. Portanto, por enquanto, interrompido é o que chega mais próximo.)

P:

R:

78 capítulo 5

escrevendo um programa

,
h

P: No começo do livro, havia um exemplo de loop for muito diferente desse loop for'?

há dois tipos diferentes de

Sim! Na primeira versão do Java havia apenas um tipo de loop for (que será explicado posteriormente neste capítulo) com a seguinte aparência:
for (int i = O; i < 10; i++) II faz algo 10 vezes {

R:

.h. h

h h h
,~

Você pode usar esse formato para qualquer tipo de loop de que precisar. Mas,.. A partir do Java 5.0 (Tiger) , também pode usar o loop for aperfeiçoado (essa é a descrição oficial) quando seu loop tiver que percorrer os elementos de uma matriz (ou outro tipo de conjunto, como você verá no próximo capítulo). Você sempre poderá usar o loop for antigo para percorrer uma matriz, mas o loop for aprimorado tornará isso mais fácil.

l~ ' l~

Código final de SimpleDotCom e SimpleDotComTester
pubI i c class SimpleDotComTestDrive { public sta t ic void main (String[] a r gs) ( S i mpIeDotCom do t = new SimpleDotCom() ; int[] locations = (2,3,4); dot . setLocationCe11s(locations); String userGuess = "2"; St ring r esu1t = dot.checkYourself(userGu e ss ) ;

1 :.
:~
~I

]"

public clas s S i mpleDotCom int [] l oca t i onCells; int nurnOfHi ts = O; pub l ic v oid s et Lo c ationCe 11 s(i n t [ ] l o c s) locationCell s = lo c s; (

pub lic String chec kYourse l f (St ring stringGuess ) int guess = In teg er . p a rse In t (stringGue s s); String resu1t = "missO ; fo r (int c eI 1 : loca t ionCell s ) if (guess == c e l l) ( resu lt = "hi t "; numOf Hits ++; b reak ;
II f o r a do Ioop

o que

devemos ver quando executarmos esse código?

if (nurnO f Hi ts == location Cells.length) resu l t = "kill"; System . out.println (result) ; return r e sul t; II fecha o mé t odo II fecha a classe

o código de teste cria um objeto SimpleDotCom e fornece um local para ele nas posições 2, 3 e 4. Em seguida, envia um palpite de usuário fictício igual a "2" para o método checkYourself( ). Se o código estiver funcionando corretamente, devemos ver a exibição do resultado:
Java SimpleDotComTestDrive hit

Há um pequeno erro à espreita aqui. O código será
~ºmpiJçtdo-.e .exe_ cillado.JTlas em _ alQUns momentos ...
ISSO

~ão se preocupe por e'nquanto, mas teremos que enfrentar
um pouco mais adiante.
vocs está aqui» 79

l .

.....
classe SirnpieDotCom

código

'~~,Aponteseulápis9--------------------------------------------------------------------------,

- '-

Construímos a classe de teste e a classe SimpleDotCom, Mas ainda não temos o jogo real. Dado o código da página anterior, e as especificações do jogo real , escreva suas idéias para o código prejJaratório da classe do jogo . Forneceremos uma linha ou outra para ajudá-lo a começar, O código do jogo real está na próxima página, portanto, não olhe a página até ter feito

A classe SimpleDotComGame precisa fazer isto:
1, Criar apenas um objeto SimpleDotCom, 2. Criar um local para ele (três, células consecutivas na mesma linha de sete células virtuais) , 3. Pedir ao usuário um palpite. 4. Verificar os palpites. 5. Repetir isso até a dot com ser eliminada. 6. Informar ao usuário quantos palpites ele usou.

esse exercício!
Você deve obter algo entre 12 e 18 linhas (incluindo as que escrevemos, porém sem incluir as linhas que apresentam apenas uma chave).
Método public static void main(Stringl] args)
Declare uma variável int para armazenar o número de palpites do usuário chamada numOfGuesses

Gere um número aleatório entre O e 4 que será a célula da posição inicial

Uma interação completa do. jogo
Enquanto a dot com existir: Capture entradas do usuário na linha de comando

r\

Código preparatório da classe SimpleDotComGame
Tudo acontece em maín( )
Há algumas coisas em que você terá apenas que acreditar, Por exemplo, temos uma linha de código . preparatório que diz, "CAPTURE entradas do usuário na linha de comando". Na verdade, isso vai um pouco além elo que gostaríamos de imv]ementar nesse momento. Mas, feli zmente, estamos usando a 00 . E isso significa que você solicitará a outra classe/objeto. que faça o que é necessário, sem se preoc upar com a lIlaneira como será feito. Quando você escrever o código preparatório, deve presumir que de alRUI/la jórm{/ será capaz de fazer o que for preciso, assim poderá dedicar toei o o seu poder mental à co nstrução da lóg ica.

" .
,,:"~
~

.,

-I
,I~

f\t

~ .. ~

"

80

capítulú 5

~~­
~g -

escrevendo um programa

"""'
código preparatório
public static void main(StringCJ args)

I

Declare uma variáv e l in t para armazenar numOfGuesses , e configure - a com o. Crie uma nova instância de Simp le DotCom .

U

HÚltlerO de palpites do usuário, chamada

L.
~

Gere um número aleatório entre O e 4 que será a célula da posi ção inicial . Crie uma matriz int com 3 inteiros us ando o número gerado aleatoriamente, esse número i ncrementado em 1 e ess e número incrementado em 2 (exemp l o : 3,4,5) . Chame o método setLocationCells( ) na ins tância de Si mpleDotCom. Declare uma variáve l booleana que representará o estado do j ogo, chamada isAlive , e configure-a c om verdade i ro . Enquanto a dot com existir (i sAli ve
I I Verifique o palpite do usuário

h

h
h ,h
~I,",

true) :

Capture entradas do usuário na linha de comando. Chame o método checkYourself( ) na inst â nci a de SimpleDotCom. Incremente a variáve l numOfGuesses.
II Verifique se a dot com f oi eliminada

J~
J~
~r

l~

'l~

I~

Se o resultado for "kill" Configure isAlive com falso (o que signif i ca que não entraremo s no loop novamente ) . Exiba o número de palp ites do usuário . End If End W hile Fim do método.

1~

t
~ il~

l"

dica metacognitiva
Não use apenas uma parte do cérebro por muito tempo. Usar apenas o lado esquerdo do cérebro por mais de 30 minutos é como usar apenas seu braço esquerdo durante esse período. Dê a cada lado de seu cérebro uma pausa, alternado-os em intervalos regulares. Quando você passar para um dos lados, o outro descansará e se recuperará. As atividades do lado esquerdo do cérebro incluem coisas como seqüências em etapas, resolução de problemas lógicos e análise, enquanto o lado direito se encarrega de metáforas, resolução de problemas que usam a criatividade, comparação de padrões e visualização.

~~--

f '. 1J~

~I .

DISCRIMINAÇÃO DOS PONTOS
- Seu programa Java deve começar com um projeto de alto nível. - Normalmente escrevemos três coisas quando criamos uma nova classe: código preparatório código de teste código real (Java) - O código preparatório deve descrever o que fazer e não como fazê-lo. A implementação ve m depois. - Use o código preparatório como ajuda no projeto do código de teste. - Escreva o código de teste antes de implementar os métodos. - Use loopsfor em vez de white quando souber quantas vezes deseja repetir o código do loop. - Use o operador pré/pós-incremento para adicionar uma unid ade a uma variável (x++). - Use o operador pré/pós -decremento para subtrair uma unidade de uma variável (x-) . .~ Use Intege~,p_<l.~elntU para capturar o valor int de LIm a String. - Integer.parselnt( ) só funcionará se a String representar um dígito ("O", "] " , "2", etc.). - Use break para sair antecipadamente de um loop (isto é, mes mo se a condi ção do teste booleano ainda for verdadeira). você: está aqdi 81

classe Sí'TipieDotCornGame

c-ódig-o preparatório

o método main( ) do jogo
Exatamente como você fez com a. classe SimpleDotCom, pense nas partes desse código que pode querer (ou ter que) aperfeiçoar. Os números dentro de um círculo são para as coisas que queremos destacar. Elas serão explicadas na outra página. Ah, se estiver querendo saber por que saltamos a fase do código de teste nessa classe, não precisamos de uma classe de teste para o jogo. Ele só tem um método, portanto, o que você faria em sel1 código de teste? Criaria uma classe separada que chamasse main( ) nessa classe? Não é necessário.
public static void main(String[) args) int numOfGuesses

"
".~
~3

=

O;

cria uma variável para ~------------------------------- controlar quantos palpites o usuário usou
essa é uma classe especial que cria~s e que contém o método de captura de ~------entradas do usuário~ Por enquanto considere - a como parte do Java
l

"::1.
-;;

f

"'

~

com 0 .

GameHelper h e lpe r

new GameHelpe r ( ) ;

Crie um obje t ü
SimpleD0t:CorI: _

SimpleDotCom theDotCom = n e w SimpleDotCom ( ) ; int randomNum = (int) (Math.random()

~ cri" o obieto uot com

Gere um núrne:r(; êlleatóL-i c'
ern.l!2 U 2
.:,1..

CD

* 5);

~
t~'ês c~lulas

o

l o c~l

das

int[)

locations = {randomNum , randomNum+l,

~
~------------

gera um número aleató~io para a primeira célula e o usa para criar a matriz de locais de células

~ ,

".1.;

randomNum+2};

theDotCom . setLocationCells (locations) ; boolean isAlive = true; booleana isAl ive

fornece à doI:: com ,sua
localização i a matriz)
cria uma variável

.,,-.....- :

~-I;

,, :

booleana que será usada no teste do loop whiIe para registrar se o jogo continua ativo. Repete o loop enquanto o jogo estiver a.tivo ..

enquanto '" d~,t ,= GF '2x:Lstir . Capture ii entrada ,:10 usuárjo. ; i Verifique-a
Chame
:,:·heCv.Youl-S~J.

whi le ( isAlive

==

true)

String guess = help er. getUserI nput (" insira um número") ;

®

captura a string da entrada do

usuário
solícita à ãot com para String resul t theDotCom.checkYourself(guess); ~verificar o palpite; sal ,rã. O resul tado retornado em uma string

t {

n(;· ·:,bj et .:' cL,t. c ,:,m.

., 1~' i

] 1" .
'.J a:.: m~~~ !'\..l.

Configure

.... v ;;:~

<~,~>m

incrementa a contagem de numOfGuesses++; ~-----------------------------------­ palpites if ( result.equa ls( "kill ")) isAlive = false; foi uma l~e líminação~'? Se rorr conrJ:gu,re isAlive

coxo

1:<'0.1

$:;)

(pare não

entramos nOV8~ente no Ioop) e ex:tbe 5. contagem de palpites do usuário
System.out.println (";Você usou" + numOfGuesses + " palpites");
II ence rra a instru ção if II encerra wh il e II encerra mai n

~i_._______8_2___

C_8_P_it_lJ_IO 5_________________________________________________________________________________________ ___

~

"

iS
-

:=:'1

T~-~

escrevendo urn programa

h
I. . . .

h
I....,
,
J--..

random( ) e getUserlnput( )
Duas coisas que precisam de um a exp li cação um po uco me lhor estão nessa página. Trata-se apenas de um a visão geral para que você possa continuar; mais detalhes sobre a cl asse GameHelper se encontram no fim deste capítulo.
Isso é uma 'conversão' e ela forçará o que estiver imediatamente após a ficar com o seu tipo (isto é, o tipo entre parênteses). Matb,random retornará um tipo double, portanto teremos que convertê-lo em um int (queremos um número inteiro entre O e 41.
Nesse caso~ a conversão eliminará a parte Eracionáría do tipo àoubl e .

l.......,

h ~ h
i Ir--

o método Math.random retornará um número no intervalo entre zero e menor ~Je um. Portanto, essa fórmula (com a conversão), retornará um n~~ero de O a 4 (isto é, de O a 4,999 .. , convertido em um inteiro).

'I,~
..:..

Ir""'-

~ Ge r e um número a l eató r io

j
(Math . randorn(

int randomNum = (int)

*

5)

Declaramos ~~a variável int que armazenará o número aleatório fornecido.

!

que

uma clas se vem com a Java ..

método da classe Matb.
Um

\

uma instância que criamos
anteriormente, de uma classe que construímos para auxil i a r o jOgo .

~

Ela se cbama GameHelper e você ainda não a viu (mas verá). ~ Cap t urando a entrada do usuári o us ando a classe GameHelper

Es s e método recebe um argumento de String que ~aa para interagí= com o usuá: ic na l i nha de c omando . Qualquer c oisa que voce p a s s ar aqui s erá exibida no terminal imediatamente antes do método começar a

procur ar a en rreda do U'Uár ~

String guess

helper . getUserInput("insira um número");

De c laramos mna variável de String que a rmazenará a s t rin g d a entrada f orne c ida pelo usuári o ( .t3 nS 'l' r e tc .) ..
U ,

1

Um método d a classe GameHelper que solicita ao usuári o entrada na linha d e comando, a lê d epois que o usuário pressiona Enter e re torna o resul t ado como U!lla S tri ng .

\

Uma última classe: GameHelper
~......::; -

~I,-..
.

' 1~

Criamos a cl asse dot com. C. namos a classe do j ogo.

"f' ,-.. ~

E :::,d:::::,::'c:::::~:;~:::U::~i:~'
-,

Só falta a classe auxiliar - a do método getUserInput( ). O código para capturar entrada na linha de comando vai além do que queremos explicar agora. Ele abre caminho para muitos tópicos, o que é melhor deixarmos

iL
~

tJ =

~

~t'""

compHá lo chamada GameHelper. Insira todas as três classes (SimpleDotCom, SompleDotComGame, GameHelper) no mes mo diretói-io e faça com ele seja seu diretório de trabalho.

,m em,cl""
' ri '

Sempre que você logotipo predefinido, verá um código que tera que digi tar do modo em que se encontra e acreditar

~ncontr~ro

~CÓdigO

w ,.....-·--- enl-s Q.,-fu- ~ -~-n _ ..l~ ~ _ ":; ,,- " ,,_~ ~_----L...-~.~.. ~... '4 \...u Il\,.,lV lI d UlCIJlV . rvu c ..... V IIl l dL vv\,., ç UjJ l L>UU\,...l Ú \,.. V JIJ V ..... .

___

~'""'

33e-ee . . llp-()- - -·
" Sabem os co mo você aprec ia di gitar, mas para os raros momentos em que preferi r fa zer outra co isa. di sponibilizam os o Cód igo Predefinido e m wickedlysmart. com.

funciona posteriormente.

você está aqui...

83

- -- - - " - - -- - -

---------

---

classe GameHelper

\P~""-L;'-:

- /~6:

código preparatório

import java .i o . *; public class GameHelper public String getUserInput(String prompt) String inputLine try { BufferedReader is if

=

null;
");

System . out.print(prompt + "

~t,(>digo pré-definido

=

new BufferedReader (ne w InputStreamReade r (System.in) ) ; '\ O) return null;

inputLi?e = is.readLine() ; (inputLine.length () ( I OExcep ti on e) {

==

c atch

System . out . println("IOException : " + e); re turn i nputLine;

Agora podemos jogar
Veja o que acontecerá quando executarmos o código e inserimos os números 1, 2,3,4,5, 6. Parece fu ncionar bem.

o que é isso?
Opa!

Um erro?

Veja o que acontece quando inserimos 1, 1, l.

I

.,

Uma interação completa do jogo
(sua pontuação pode variar)

Uma interação diferente do jogo
(epa)

1·1

I'

_'i

É uma situação-limite!
Encontraremos o erro? Corrigiremos o erro? Não perca o próx imo capítulo, onde responderemos essas perguntas e muitas outras ... Mas por enquanto, veja se consegue ter um a idéia do que deu errado e de como corri gi r.

f"

1

fi.

~J

:~

~

84

capíluio 5

~
:~

~

~~.:

f'-_- h
V"'\

escrevendo um programa

i

Mais informações sobre os loops for
Abordamos todo o código do jogo neste capítulo (mas voltaremos a ele para terminar a versão sofisticada no próximo capítulo). Não quisemos interromper seu trabalho com alguns dos detalhes e informações secundárias, portanto retornaremos a eles aqui. Começaremos com os detalhes dos loops for e, se você é programador de C++. poderá ler apenas superficialmente essas últimas páginas ...

I

~

i ,.-..

I.. . .

Loops for comuns (não-aperfeiçoados)

. operador

o cóéLigo
x·epeti.dc corpo) aqui

incremente

for(int i

=

Oi

i < 100i i++)
test e booleano

1

{

/
}

ii"Jicial j ,za.qifo

eJcpressãc de

iteração

o que

significa em português simples: "repetir 100 vezes."

repita 100 vezes:

Como o compilador interpreta:
- criar uma variável i e configurar com O.

,,--,
,

_ repetir enquanto i for menor que 100. _ no fim de cada iteração do loop, acrescentar uma unidade a i.

Parte um: inicialização
Use essa parte para declarar e inicializar uma variável que será usada dentro do corpo do loop. Geralmente essa variável é usada como um contador. Na verdade você pode inicializar mais de uma variável aqui, mas veremos isso posteriormente no livro.

parte dois: teste booleano
É aqui que o teste condicional entrará. Independentemente do que houver nele, terá que ser convertido em um valor booleano (você sabe, verdadeiro oufalso). Você pode ter um teste, como (x>=4) , ou até mesmo chamar um método que retorne um booleano.

Parte três: expressão iterativa
Nessa parte, insira uma ou mais coisas que você deseja que ocorram a cada passagem do loop. Lembre-se de que elas acontecerão no final de cada loop.

-Percorrendo um loop
for (int i = O; i < 8; i++) System . out.println(i); System.out.println("done") ;
declare a variável int i configure i com O

saída:
~______~~I

entre no corpo do loop

exiba o valor de i
exiba \\done ll

---~~-~=~-~~ -- -~

(passe para baixo do loop)

-(a expressão interativa)

você estú aqtJ!

85

- L _ _ _ _ _ __ _ _ _

~

~

_ _ _ __ _ _ __ _ _ _ _ _ _ _ _ _ _ _ _ __ _

diferença entre ior e wi, i!e

Diferença entre for e while
Um loop while apresenta apenas o teste booleano; não tem uma expressão interna de inicialização ou iteração. Ele será útil quando você não souber quantas vezes o loop será executado e qui ser continuar a execução apenas enquanto alguma condição for verdadeira. Mas se você souber quantas vezes o loop será executado (por exemplo, dependendo do tamanho de uma matriz, 7 vezes, etc.), um loop for será mais simples. Aqui está o loop anterior reescrito usando-se white:
int i = O; ~----------------~---------------------------­ t emos que declarar e inicializa.r o conr:ado? wh il e (i < 8)
~~---------------------------------------------- temos que incrementar o contador

System.au t .println ( i ) ;
i++;

System . aut .println ( "dane" ) ;

++
Operador de pré e pós-incremento/decremento

o atalho para se adicionar ou subtrair 1 unidade de uma variável.
x++',
é o mesmo que:

x=x+1;
As duas instruções significam a mesma coisa nesse contexto: "adicione 1 unidade ao valor atual de x" ou "incremente x em 1 unidade"

E:

x- -;
é o mesmo que:

x=x-1;
É claro que isso não é tudo. A inserção do operador (antes ou depois da variável) pode afetar o resultado . Inserir o operador antes da variável (por exemplo, ++x) , significa "primeiro, incremente x em 1 unidade e, em seguida, use esse novo valor de x". Isso só será importante quando x++ fizer parte de alguma expressão maior e não de apenas uma instrução. int X = O; int z = ++x;

produzirá: x é igual a 1, z é igual a 1 Mas, se inserirmos o sinal ++ depois de x, teremos um resultado diferente:
int x = O; int z = x++;

produzirá: x é igual aI , mas z é igual a O! Z receberá o valor de x e, em seguida, x será incrementado.

o loop for aperfeiçoado
A partir do Java 5.0 (Tiger), a linguagem passou a ter um segundo tipo de loopfor chamadojór apeljeiçoado, que torna mais fácil a iteração por todos os elementos de uma matriz ou outros tipos de conjunto (você aprenderá sobre outros conjuntos no próximo capítulo). Na verdade isso é tudo que o loop for aperfeiçoado fornece --.uma maneira mais simp les de percorrer todos os elementos do conjunto, mas já que essa é a finalidade mai s comum de um loop for , valeu a pen a adicion á-lo à linguagem. Revisitaremos o loopfor apelfeiçoado no próxim o capítulo, quando falarmo s sobre conjuntos que não são matrizes.
86 capítulo 5

~-

~

-"'--

~

-tA

i;S!:

, .

f"'-

escrevendo , n i programa
Deç la,zoa uma

1T,

....

·i

·~.F~) I

de

um

elemento da.

ma~ríz~

'\
ii
I

for

~~ name:! (String

nameArray)

{

I
}
8:m.

Os elementos da matriz DEVEM ser comvativ€.:'s com o tipc declarado para a varíá . rel. .

/

,":1 cada i;.:>eraç§.o

T

um el.é1.nsnto diferente da

Suponllamos que

algum !JOllto ant.:r:..t:';"or do ';f')digc
.;;;
{llFred~(~ uI..ffaJ::y~~~ ~~BobNJ;

ti7ásse11los:
String[]
~!a
~1ê.me.Ai..~ray

matriz será atribuído ã variável Una.."ne N '"'

prí.üleira it:araçãc_"
!lã

a

Fê..~iat--~21

I1ame tez~:!l o Tfalcr
I

tFred"...

segu.."1d'a.

c valoz:: nriJa.!..yf(

C'!.,...'-

o que isso significa em português claro: "a cada elemento de nameArray, atribua o elemento à variável
' name ' e execute o corpo do loop. " Como o compilador interpretaria: - Criar uma variável de string chamada name e configurá-Ia com nulo . - Atribuir o primeiro valor de nameArray à variável name. - Executar o corpo do loop (o bloco de código dentro das chaves) . - Atribuir o próximo valor de nameArray a name.
.,.-..,
1 i':''1ft'''"Ua:;;em de P,Z°o!;;;{x'emaçi#'o (;ru.e

tiverem usado no o Ioop for

passadc~

a-1.gumas pessoas podem cila."TIar
ap~rfeiçaado

de

Hror eecll" ou ""ror in?'r~. . porQUe é assim ~~$ se incerpreta: "'para 'for)
elemento DO conjunt0 ... ~1f
(eacil) in)

C_~A

I",
1 --Ir.-

- Repetir enquanto ainda houver elementos na matriz. Parte um: declaração da variável de iteração

f~

l~

Use essa parte para declarar e inicializar uma variável que será usada dentro do corpo do loop. A cada iteração do loop, essa variável armazenará um elemento diferente do conjunto. O tipo da variável deve ser compatível com os elementos da matriz ! Por exemplo, você não pode declarar uma variável de iteração int para usar com urna matriz String[] . Parte dois: o conjunto atual Deve ser uma referência que aponte para uma matriz ou outro conjunto. Não se preocupe ai nda com os outros tipos de conj unto que não são matrizes - você os verá no próximo capítul o.

t~
Iri

I"
I~
!
I

f~

Convertendo uma string em um inteiro
int guess

Jr:.
,-.,

=

Integer .parseInt (stringGuess) ;

O usuário digitará seu palpite na linha de comando quando o jogo solicitar. Esse palpite chegará na forma de uma string ("2", " O", etc.), e o jogo passará essa string para o método checkYourself( ). Mas os locais das células são simplesmente os inteiros de uma matliz, e você não poderá comparar um inteiro com uma string. Por exemplo, isso não funcionará:
S t r i ng num = "2"; int x = 2; if (x == num) l/confronto incompatíve l!

1 ----

~k
Ir-\

-f'

~

Tentar compilar esse código fará o compilador rir e zombar de você:

Portanto, para contornar as diferenças, temos que converter a string "2" no illteiro 2. Embuti da na biblioteca de classes Java temos uma classe chamada Integer (certo, trata-se da classe Integer e não de um tipo primitivo int) e uma de suas tarefas é pegar strings que representam números e convertê-l as em números reais.
uma
c~asse

que

~

t

vem com o ~=.=a_~,-_____

__

usa uma. scri .. "1g

~

~ Integer.parselnt("3")

-..

87

convertendo t:PQ sprirnitiv("s

l.nnvArt,::mrln tinnc:: nrimiti\lnc:: _·õ- õ · · · . . , _.
_ ••• _. __ o . _ -

-~-

bits cio ladc.·
es~..!e::do

fcraui.
e2imina,áos
0.1 0..1 .1.10.

~ mas

.1.10.

longo

pode ser convert i do em

curto

você pode ~J perder algo

~
t.t'

No Capítulo 3 falamos sobre os tamanhos dos vários tipos primitivos e que você não pode inserir algo grande diretamente em um recipiente pequeno : long y = 42; int x = y;

II não será compilado

Um tipo longo é maior do que um inteiro e o compilador não terá certeza de onde esse longo saiu . Pode ter estado bebendo com outros l ongos e recebendo valores realmente altos. Para forçar o compilador a e spremer o valor de uma variáve l pr imiti v a maior em um tipo menor, você pode usar o operador de conversão . Ele tem esta aparênc i a :

I I até aqui tudo bem long y = 42; int x = (int) y; II x = 42 muito boml
Se você inserir a conversão, estará solicitando ao compilador que pegue o valor de y, converta-o para o tamanho de um inteiro e configure x com o que sobrar. Se o v al o r de y for maior do que o valor máximo de x, acabaremos com um número estranho (mas calculável* ) : long y = 40002; II 40002 excede o limite de 16 bits de um tipo curto short x = (short) y; II agora x é igual a -25534 ! Mesmo assim, o importante é que o compilador lhe permita continuar . E digamos que você tivesse um número de pont o flutuante e quisesse a penas a parte inteira ( int ) dele : float f int x

=

3.l4f; (int) f;

II

x será igual a 3 deixe como está .

Mas nem pense em converte r algo em um booleano ou vi ce-versa * Isso envolve os bits de sinais, o sistema binário, discutidos no começo do Apêndice B. c l ass Output {

' complementos de dois' e outros detalbes, que serão

public static vo id main(String [J args) Output o o.go () ; void go () new Output();

Seja a JVM

int y = 7 · for(int x
Y++i

ou
1; x < 8; x++)
4)

o arq uivo Java dessa
página representa um arquivo-fonte completo. Sua tarefa é personificar a . JVM e determ inar qual será a saída quando o programa fo r executado?

if (x >

System . out . print(++y + " O); if
(y >

14)
" + x);

System . out . println(" x break;

ou

~~)

,

"

88 capit! I!O 5

.j t

.~~

escrevendo um programa

ímãs com código
Um programa Java funcional está todo misturado sobre a geladeira. Você conseguiria reorganizar os trechos de código para criar um programa Java funcional que produzisse a saída listada a seguir? Algumas das chaves caíram no chão e são muito pequenas para que as recuperemos, portanto, fique à vontade para adicionar quantas delas precisar!

"'"',

I

1)

System.out . println(x

+

"

"

+

for (int

Y

4;

Y >

2;

y-)

~- -

.,

for(int

x

O;

x

<

4;

x++)

'I

~

pUblic

static main(String

n
"P'---~

[1

'I

~1

ri -~

0-

:.4-'
;~,~ '"

Mensagens misturadas
class MixFor5 static
= =

Um programa Java curto é listado a seguir. Um bloco do programa está faltando . Seu desafio é comparar o bloco de código candidato (à esquerda) com a saída que você veria se ele fosse inserido. Nem todas as linhas de saída serão usadas e algumas delas podem ser usadas mais de uma vez. Desenhe linhas conectando os blocos de código candidatos à saída de linha de comando correspondente. (As respostas estão no final do capítulo.)
[J
args) Candidatos: Saidas possiveis:

public

void main (String

int x int y

O;

30;

~':l '~ '~i-., .

for

(int for (int

outer inner

=

O;
=

outer
4;

<
>

3;
1;

outer++) inner-)

inner

~-;L;;:-

1

~
.

*~

y

= y

-

2;

if

(x == break;

6)

o
CiHldidato

x
y -

x

+

3;

gntra

aqui

Compare cada possí''iJ"eis

c andidato

COm

uma

das

saídas

) ....,

y

2;

~h'" "
·:f~

Sy,steITl . out .pri- tln (x n

+

1;i-. .
'1.,\

voce estú

89

quebra-cabeças:
Como um jogo de palavras cru zadas o aj udará a aprend er Ja ~a? Bem, ~ - ~--~- toda~ pala vn;~ tê~~relação com o Java. Além di sso, as pi stas

Cruzadas Java

a s

fornece m metáforas, trocadilhos e coi sas do tipo. Esses atalhos mentais disponibilizarão rotas altemativas para o aprendizado Java, diretamente e m seu cérebro!

,r-.. ,

Horizontais I . Palavra engraçada em informática que significa construir
4 . Loop de várias partes

Verticais
1. Estabelecer o primeiro valor
2. Tipo de incremento 3. Cavalo-de-batalha da classe

6. Teste primeiro

7.32 bits
10. Resposta do método 11 . Código preparatório
13. Alteração
15. O grande kit de ferramentas

5. O pré é um tipo de _ _ __

7. Um ciclo 8. Wh ile ou For
9. Atualizar uma variável de in stânci a
12. Contagem regress iva

17. Uma unidade da matriz

14. Compilare _ __

18. De instância ou loca l
20. Kit de ferram e ntas autom á tico 22. Parece
Ulll

16. Pacote de comunicação
19. Mel1'mge iro dos métodos (abre v.)

tipo primitivo, mas ...

21. Como se

25. Não conversível
26. Método ele Math
28. M étodo conversor
29 . Sai r antes

23. Ad icionar depo is
24. A casa cio pi 27. Valo r cio operaclor ++

30.

de iteração do loop for
~

-,~

escrevendo

,; programa

, -

Seja a JVM:
c1ass Output

Imãs com Código
c1ass Mu1tiFor ( ( pub1ic static void main(String [] args) for ( int x (

L

pub1ic static void main(String [] args ) Output o new Ou tput() ;
O .go ();

= o;

x < 4; x+ + ) (

void go () ( int y = 7; for(int x = 1; x < 8; x++)
y ++;

f o r(in t y = 4 ; y > 2; y - ) System.out . print1n(x + " " + y) ; (

if

(x

> 4)

(

Syst em . out . print(++y + " O); if 14) ( System.out.print1n(" x break;
(y >

if

(x

==

1)

(

X++i

" + x);

o que aconteceria se esse bloco de código viesse antes do loop for de 'y'?

L'
:1--.

Você se lembrou de considerar a instrução break? Como isso afetou a saída?

'I

h :I
'1-.

,h
'~L. ~

~ Oluções dos quebra-cabeças

Candidatos:

Saídas possíveis:
4S 6

x x x
X++;

x + 3; x + 6; x + 2;

36 6
S4 6

60 10 18 6

x--;
X

=X

+ O;

6 14 12 14

- ......--------------------

".

91

6 conheça o APl Java

-

Usando a Biblioteca Java

)

o Java vem com centenas de classes predefinidas. Você
não terá que reinventar a roda se souber como encontrar o que precisa na biblioteca Java, normalmente conhecida como APl Java.

Há coisas melhores a fazer. Se você pretende escrever códigos,
pode escrever somente as partes que forem exclusivas de seu aplicativo. Conhece o tipo de programador que vai embora toda tarde às 5 PM? Aqueles que não chegam antes das 10 AM? Eles usam

o APl Java. E nas aproximadamente oito páginas seguintes,

nós também usaremos. A principal biblioteca Java é uma pilha gigante de classes apenas esperando para serem usadas como blocos de construção, para que você construa seu próprio programa usando código em grande parte predefinido. A seção de códigos Java predefinidos deste livro são trechos que você não terá que criar do zero, mas mesmo assim precisará digitá-los. O APl Java está cheio de códigos que você não terá nem mesmo que digitar. Tudo que precisa fazer é aprender a usá-lo.

este é u:-", redO capíÍulo

93

ai nda temos
:

Como o código deve funcionar
Veja o que acontecerá quando executarm os o cód igo e in serirm os os números J, 2, 3, 4. 5, 6. Parece funcion ar bem.

Como o erro se manifesta
Veja o que acontece quando in serimos 2, 2, 2.

Uma interação completa do jogo
(sua pontuação pode variar)

Uma interação diferente do jogo
(epa)

Na versão atual, quando você acertar, terá apenas que repetir esse palpite mais duas vezes para eliminar!

Mas o que aconteceu?
public String checkYourself(Str i ng stringGues s) int guess É aqui que está o erro. Contamos um acerto a cada vez que o usuário adivinhou uma célula, mesmo quando esse local já tinha sido adivinhado! Precisamos de uma maneira de saber se quando o usuário deu um palpite, ele já não adivinhou essa célula . Se já tive r adivinhado , então, não iremos contá-Ia como um acerto.
=

{
convertê a String em um int

Integer . parseInt (stringGuess):
=

~

String result

"miss":

cria uma veriável para armazenar o ~<E:"--_'_-------- resl.ütado que retornaremos. Insere
'~1n:i.ssl'''' como o paãrão (isto é, presuJ nindo um "erroU)

estames

for

(int cell : locationCells) if (gu e ss cell) {

{

<E-------------

repete para cada célula da matriz

result = "hi t": numOfHits++:

( ______ tíveruos um

(~--------_.

co:mpara o pa lpi.t iS' do u suári o com es se
e~ement:o

(cél.ula) da matriz

~

acerco!

saí do loop, não e preciso testar as break : ( - - - - - - - - - - - - - - - - - - - - - - - outras células
II fim do tes te if
II fim do loop for

if

(numOfHits

==

loca ti onCells . length)

{

~-----

estamos fora do ~oopz mas vejamos se já terminamos (a-=ertamo5 3 vezes) €r a.lteramos a string do resLlcar'io .para ~ki.l1n

r esult = "kill":
II fim do te ste if

s,:ib·? o ::.."€!sultaóo para o usuéri.o

Syst em . ou t. pri ntln (re sult ) : re t.urn resul t :
II

~<E-------------------

(f'omiss!l,.
j..IIC( .....::i.

men<J$
vu

c:n.l6
J.

se.-;a alterado

~j........

ir.l..1.

I

re-,t"::..}':-na D reEt!l tado pe.ra o método C'-,'l~.. madDr

f im elo métoelo

conheça o APl Java

Como corrigir?
Precisamos de uma maneira de saber se uma célulaj á foi adi vinhada. Exami naremos algumas possibilidades , mas, primeiro, revisaremos o que sabemos até agora ... Temos uma linha virtual com sete células e um objeto DotCom ocupará três células consecutivas em algum local dessa linha. A linha virtu al abaixo exibe um objeto DotCom situado nas células das posições 4, 5 e 6.
r-

I'-

IO

I
1 2 3 4 5

~

A linha virtual, com os locais das três células do objeto DotCom,

6

o objeto DotCom tem uma variável de instância ele se encontra.
5

uma matriz int - que contém os locais das células em que

;l~

J
l~

\
locati o nCells (variáve l de instância do objeto DotCom)

A

« --1 2

':h
I~

variável de instáncia. da. lna triz que contém os locais das células do objeto DotCom. Esse objeto DotCom contém oS 3 valores 4, 5 e 6~ ESS&S são os números ~üe o usuário tem w~e adivinharA

J ...,_ . .J-1-:

(2)

Opção um
Poderíamos criar uma segunda matriz e, a cada vez que o usuário acertasse, armazenaríamos esse palpite nela, para em seguida a verif icarmos a cada vez que houvesse um acerto e saber se essa célula já foi adi vinhada.
I verdadeiro' em um índice específico dessa matriz significaria que a posição da verdadeiro célula nesse mesmo índice da OUTRA matriz (--- (locationCells) teria sido adivinhada.

k
falso falso

o valor

~1~

matriz hitCells (seria uma nova variável de instância de matriz booleana do objeto DotCom)

-----l>,~ I t o"' 1 L
_ _
1

~~~
óf

1
_

-2

Essa matriz contém três valores que representam o 'estado' de cada célula da matriz de posições de células do objeto ~ DotCom. Por ex~mp1o , se a célula do indice 2 for adi vinhada~ então; confi~are Q índice 2 da matriz nb.itCells" com 'verdadeiro'.

'-J--;}:- ,
'(

A opção um é muito complicada
A opção um parece dar mais trabalho do que gostaríamos. Significa que, a cada vez que o usuário acertar, você terá que alterar o estado da segunda matriz (a matriz 'hitCells'), ah - mas primeiro será preciso VERIFICAR a matriz ' hitCells ' para sabermos se essa célula já foi adivinhada. Funcionaria, mas tem que haver algo melhor.. .

V=-:

® Opção

dois

Poderíamos simplesmente manter a matriz original, mas alterar o valor de qualquer célula que f osse adi v inhada para -1 . Dessa forma, só teremos UMA matriz para v erificar e manipular um valor igual a - 1 no local de uma célula 4 -1 5 especifica significaria que a célula já foi

~

A

:5:.~

1

11 \

«

aãivirillada,

portanto só procuraríamos

números positivos na matriz.

1
~.

locationCells (variável de instânc ia do objeto DotCom)

~

)...,
I

A opção dois é um pouco mel hor, mas ainda bem complicada

~ . A opção dois é um pou65 menos c ompficada~ mas não é mu ito eficIente. Voce ainda teria quê percorrer todos À os três espaços (posições de índice) ela matriz, mesmo que um ou mais já fossem inválidos por tere m sido -'-À- - 'adivinhados ' (tendo o valor -1) . Tem que haver algo melhor.. .

l1----

você está aqui :>

95

código preparatório

\"';VY..L.~U

_..::.-' .:

--

preparatório

CD Opção

três

Excluiríamos cada local de célula quando ele fosse adivinhado e alteraríamos a matriz t ornando-a menor. Porém as matrizes não podem mudar de tamanho, logo, ter e mos que cri ar uma nova matriz e copiar as cél ul as r estantes d a matri z antiga para a nova ma t riz meno r.

matriz locationCells ANTES de qualquer cé lula ser adivinhada

A ma t riz i n icialmente t~~ um tamanho igu al a 3, de modo que percorreremos todas as t:rês c élulas (pos ições da matriz) para procurar uma coincidência ent:re o palpite do usuário e o valor da célula (4, 5, 6).

4

\
matriz locationCells DEPOIS da célula ' 5', que es t ava no índice 1 da matri z, ser adivinhada

o

Quando a célula ' 5' for adivinhada, criaremos uma nova matriz menor somen te com os locais das células restantes e a atribuiremos à variável de referência locationCells original.

A opção três seria muito melhor se a matriz pudesse ser reduzida, para que não tivéssemos que criar uma nova matriz menor, copiar os valores restantes nela e reatribuir a referência.

o

código preparatório original referente à parte do método checkYourself( ):

Tudo seria melhor se pudéssemos alterá-lo para:

Repita para cada local de cé l ula da matr iz int ......... fR;pit~ p-;:~r"'cad;' lo~al de cél~la ~eBcente
/ / Compare o palpite do usuário com o local
da cé l ula

/ / Compare o palpi te do usuár i o com
da célula

O

local

Se

o palpite do u suá r io estiver correto

Se

o palpite do usuári o estiver correto

Incremente o número de acertos ---------....j~. Remova essa célula da matr iz
/ / Verifique se essa foi a ú l t ima célula / / Verifique se essa foi a última célula

Se

o número de acertos for igua l a 3,

Se

agora a matriz est i ver vazia,

Retorne "elimi na ção" Caso contrário não t erá si do uma el iminação, portanto Retorne " co rr eto "

Retorne "eliminação" Caso contrário não terá sido uma eliminação , port ant o Re't orne " correto "

End If
Caso contrário o palpite do usuário n ão coincide, portanto Retorne "errado "

End If
Caso contrário o palpite do usuário não coin c ide, po rtanto Retorne "errado "

End If Fim da iteração

End If Fim da ite r ação

96

cap itulo 6

. ~ "' W

*

conheça o APl Java

I

~

I ,.....,

Se pelo menos eu conseguisse encontrar uma matriz que pudesse ser reduzida quando removêssemos algo. Uma que não tivéssemos que percorrer para ve rificar cada elemento, mas em vez disso pudéssemos apenas perguntar se ela contém o que estamos procurando. Então ela permitiria que excluíssemos seus elementos, sem que tivéssemos que saber exatamente em que posição eles estão. Isso seria um sonho. Mas sei que é apenas ilusão ...

'i

~

I .r--"

~

;h
:~ .
.~ y--..,

J~

ii

-~_.

" h
··'h~

"I

! 'c.

'~~ '"

Anime-se e conheça a biblioteca
Como em um passe de mágica, na verdade há algo assim. Mas não é uma matriz, é uma ArrayList. Uma classe da biblioteca Java principal (o APl).
A Java Standard Edition (que é a que você deve ter a menos que esteja trabalhando com a Micro Edition para dispositivos pequenos e acredite, você saberia) vem com centenas de classes predefinidas. Exatamente como em nossa seção de códigos predefinidos exceto por essas classes predefinidas já terem sido compiladas.

.~t:-<
:;" \

.~~~~-

,·1

~~ç~~1)/ ;'I~ ,~ ~
;r-J.-""

# ·· h

Isso significa que não é preciso digitar.
Apenas use as classes.

Uma das diversas classes da bibl i oteca Java. Vo c ê p o derá usá-la eln seu código como se a tivesse criado.

(No ta: n a verdade o método
add(Object element) tem uma

~~r---q:Ji Ser
::r-~

aparência um p ouco ma is estranha do que o mostrado a~li ••. Chegaremos ao método r eal posteríormente no livro~ Por enquanto, apenas consiélere o como () luétodo a d d ( ) ~1e receberá o você adicionar).
dos métodos de ArrayList"

você está

97

quando 8S matrizes não sã o suficientes

Alaumas r:o is;::)s
-..J . . - - -

01-- A I-.

VOr:P.
-

. - - - -- - --

OOr! A f;::) 7A r --- .

r.n m 0_ - -

~- -

Arr;::)vl = 7-

ist
«Egg»

0,'" l::;' '0

.,

Não /ela.

se preocupe com essa 110va sinta:u.e de sinaí s lnaior e menor
s~gnifica

agora; apenas "crie uma lista de objetos Egg com essa instrução".

" ."j ",
-"'~"

,;J
I"J

G) Criar

~ ArrayList<Egg> myList
algo nele

um objeto Ar~ ist

1\· ~.
new 'ArrayList<Egg>()
v __ \.! '

..

í

Um novo objeto }!.rrayList é criado na pilha. É pequeno porque está vazio.

® Inserir
Egg s

Agora o objeto ArrayList cresceu até o tamanho de urna
" c a i xa"

=

new Egg()

para arma.zenar o

obj eto Egg.

myList. add (s)

~

Inserir mais alguma coisa nele

Egg b

=

o objeto ArrayList cresceu

new Egg()

novamente para. a.rm.::.zena= c·

segundo objeto Egg.

myLi st. add (b)

® Saber
® Saber

quantos itens existem nele

int theSize

=

4~______________________________________

myList. size ()

,

o objeto ArrayLis t está armazenando 2 objetos, portanto o método size( retornará 2

se ele contém algo

boolean isIn

=

myList. contains(s)

objeto P.rrayList contém o objeto EGG ( -------------------------------- referenciado por 's', portanto contains( ) retornará verdadeiro
RK~dENTE

o

~ Saber onde está algo ( i sto é, seu i ndic e )

i nt idx

myList. ind e x Of (b)

~---------------------------------------

~

objeto ArrayList tem base O que signifi ca que o primeiro índice é O) e já que o objeto referenciado por 'h' á o segundo item da lista, i ndexOf( ) retornará 1
(o

o

Saber se ele está vazio

boolean empty

=

myList. isEmpty ()

ele definitivamente não está vazio, portanto iSEmpty( ) retornará falso

® Remover

algo dele

Ei veja - ele diminui!

myList. remove (s)

98 capilu!o 6

~

~~ h

conheça o APl Java
Preencha o resto da tabela a seguir examinando o código de ArrayList à esquerda e in serindo como você acha que ele ficaria se usasse um a matriz comum. Não esperamos que você acerte todos , portanto faça o rllelh or que pude r.

ArrayList
ArrayList<Str i ng> myList = new ArrayList<String>();

matriz comum
String [ ] myList = new String[2];

String a = new String ("whoohoo") ; myList . add(a) ;

String a

=

new String("whoohoo");

String b = new String ("Frog") ;
.(\

String b

=

new String("Frog") ;

myList . add (b) ;

int t heSiz e = myLi st.siz e ( ) ;

Object o = myList . get(l) ;

myList.remove( l );

boolean isIn = myList.contains(b);

,

Não existem

Perguntas Idiotas

A pergunta na verdade seria "Como vou saber o que existe no APl?" e essa é a chave para que você tenha sucesso como programador Java. Para não mencionar que também é a chave para você poder ser tão preguiçoso quanto quiser e ainda assim conseguir desenvolver softwares. Você ficará surpreso com quanto tempo conseguirá economizar, se alguém já tiver feito grande parte do trabalho pesado e tudo que terá que fazer será intervir e criar a parte divertida. . Mas mudaremos de abordagem. Uma resposta direta seria que você passasse algum tempo examinando o que existe no APl principal. A resposta detalhada se encontra no fim deste capítulo, onde você aprenderá como fazer isso. Mas esse é um grande problema. Não tenho apenas que saber que a biblioteca Java vem com ArrayList, o mais importante é saber que ArrayList é o objeto que fará o que eu quiser! Portanto, como passarei do estado de ter que fazer algo para a maneira como fazê-lo usando o APl? Agora você está realmente chegando ao âmago da coisa. Quando tiver terminado este livro, terá uma boa compreensão da linguagem e o resto de sua curva de aprendizado estará relacionado a saber como ir do problema à soiução, com ccâigitaçãô da meno r quarrwé:lue: ue: cúdigü- pussívd . Se: vucê -pUwr-espeíaí mais algümas páginas, começaremos a falar sobre isso no final deste capítulo.
você está aquI
~

P: R:

Quer dizer que o objeto ArrayList é avançado, mas como eu iria saber de sua existência?

P:

R:

99

diferença 8ntre ArrayList e as matrizes

Tudo sobre o Java
Entrevista desta semana : . - -- - ---.ArrayList, tudo sobre as matrizes

Use a Cabeça!: Então quer dizer que AlTayLists são como matrizes, certo? ArrayList: Até parece! Sou um objeto, graças a Deus. Use a Cabeça!: Se não estou enganado, as matlizes também são objetos. Elas residem na pilha junto com os outros objetos. ArrayList: É verdade, as matrizes ficam na pilha, mas uma matriz ainda é um projeto de ArrayList. Uma tentativa. Os objetos têm estado e comportamento, certo? Estamos de acordo nisso. Mas já tentou chamar um método em uma matriz? Use a Cabeça!: Já que você mencionou, acho que não. Mas que método eu chamaria? Só tento chamar métodos nos elementos que insiro na matriz e não na própria matriz. E posso usar a sintaxe das matrizes quando quiser inserir e extrair elementos delas. ArrayList: Tem certeza? Você está tentando me dizer que removeu realmente algo de uma matriz ? (Nossa, onde vocês são treinados? No McJava?) Use a Cabeça!: É claro que consigo remover algo de uma matriz. Se eu tiver a instrução Dog d = dogArray[1] consigo retirar o objeto Dog do índice 1 da matriz. ArrayList: Tudo bem, tentarei falar com mais calma para você conseguir acompanhar. Você não, repito, não removeu esse objeto Dog da matriz. Tudo que fez foi criar uma cópia da referência de Dog e atribuí-la a outra variável Dog. Use a Cabeça!: Ah, entendo o que você está dizendo . Não, realmente não removi o objeto Dog da matriz. Ele ainda está lá. Mas acho que posso configurar sua referência com nulo. ArrayList: Porém eu sou um objeto de primeira classe, logo, tenho métodos e posso realmente, você sabe,fazer coisas como remover a referência de Dog de minha lista e não apenas configurá-la com nulo. E posso alterar meu tamanho, dinamicamente (veja). Tente fazer isso com uma matriz! Use a Cabeça!: Bem, odeio entrar nesse assunto, mas há rumores de que você não . passa de uma matriz afamada porém pouco eficiente. Que na verdade você é apenas a classe encapsuladora de uma matriz, com métodos adicionais para coisas como o redimensionamento que eu teria que criar por conta própria. E já que chegamos a esse ponto, você não consegue nem armazenar tipos primitivos! Isso não é uma grande limitação? ArrayList: Você acredita realmente nessa lenda urbana? Não, eu não sou apenas uma matriz menos eficiente. Admito que haja algumas situações extremamente raras em que uma matriz possa ser apenas um pouco, repito, um pouco mais rápida para certas coisas. Mas vale a pena o minúsculo ganho no desempenho e desistir de todo esse poder? Veja toda essa flexibilidade. E quanto aos tipos primitivos, é claro que você pode inserir um tipo primitivo em um objeto ArrayList, contanto que ele seja encapsulado em uma classe encapsuladora primitiva (você verá mais detalhes sobre isso no Capítulo 10). E, a partir da Java 5.0, esse encapsulamento (e sua remoção quando você extrair o tipo primitivo novamente) ocorre automaticamente. Certo, reconheço que é verdade, se você usar uma ArrayList de tipos primitivos, provavelmente terá mais rapidez com uma matriz, por causa do encapsulamento e sua remoção, mas mesmo assim ... Quem usa tipos primitivos atualmen.te? Oh, veja que horas são' Estou atrasado para o Pilates. Teremos que voltar a esse assunto posteriormente.

100 capitulo 6

)

conheça o APl Java

Comparando ArrayList com uma matriz comum
ArrayList
ArrayList<String> myList
~

matriz comum
String [] myList
~

new ArrayList< Str ing>();

new String[2];

String a

~

new String ( "whoohoo") ;

Str ing a myList[O]

~

new String ("whoohoo") ;
~

myList.add(a) ;

a;

String b

~

new String ("Frog") ;

String b myList[l]

~

new String("Frog") ;
~

myList.add(b) ;
.. ("'""',

b;

int theSize

~

myList.size();

lnt theSize

~

myList.length; ~

Object o

~

myList.get(l) ;

Str ing o

~

myLlst[l] ;

myList.remove(l) ;

myList[l]

null;

. que ~ aqUI a ticar comeÇa ente \ rea\rn \ diterente... -

---1"-'r-

~

.-

.,.r------

boolean isln

~

myList.contains(b);

:[("'""',

~I~
~

-f-' I
7"'"'-

boolean isln = false; for (String item : myList) i f (b. equals ( i tem) ) ( isln = true; break;
}

(

}

.

~--r-.-· I o. '("'""',
>

r:;

~

Observe que com ArrayList, você estará trabalhando com um objeto de tipo ArrayList, portanto estará apenas chamando os métodos antigos comuns em um objeto como qualquer outro, usando o velho operador ponto.

~~

-.-.r-Comparando ArrayList com uma matriz comum

Com uma matriz, você usará a sintaxe especial das matrizes (como em myList[O] =foo) que não empregará em nenhum outro local exceto com matrizes. Ainda que uma matriz seja um objeto, ela vive em seu próprio mundo particular e você não poderá chamar nenhum método usando-a, embora possa acessar sua única variável de instância, length.

(!) Uma matriz

comum tem que saber seu tamanho na hora que é criada . Mas com ArrayList, você terá apenas que criar um objeto de tipo ArrayList. Sempre . Não é preciso saber seu tamanho. porque ele . crescerá e diminuirá quando objetos forem adicionados ou removidos.

New String[2] ( ' - - - - - - - - - - - - - - - - - - Precisa de um t amanho. New ArrayList<String>(
o tamanho não é necessário (embora você p o ssa fornecer um se quiser).

~

Para inserir um objeto em uma matriz comum, você terá que atribuí-lo a um local específico . (Um índice de O a uma unidade a menos qu e o tamanho da matriz) .

myList[IJ

~

b;

~(,--

___________________________

Precisa de um índ i ce

Se esse índice estiver fora dos limites da matriz (por exemp lo, se a matriz tiver sido declarada com um tamanho igual a 2 e agora você estiver tentando atribuir algo ao índice 3) . e la transbordará no tempo de execução. Com ArrayList. você poderá especificar um índice usando o método add(anInt, anObject) ou continuar usando add(anObject) e o objeto ArrayList continuará a crescer para fazer espaço para o novo item. mYList.add(b ) ; (~----------------- Sem indice.

~

As matrizes usam uma sintaxe própria que não é empregada em nenhum outro local em Java.
Os colchetes da matriz
faz6~ parte de uma sintaxe ôspe:;;::i.:::.l usad::t somence com :matrizes.

mYLis t [lJ

você está aqui

~

101

o código DotCom com falha

(4) Os
-

objetos ArrayList da Java 5.0 são parametri zados. 7 Ac abamo s de di z e r que, dl-feren-t-emen t e das ma-;:t:C:r-:C1 C::z-=e-=sC"",-o=s--=oLb=-=J'-e=t-=o-='--;A;-:::_ · s rrayLi s t não têm uma sintaxee·s pecial . . Ma s n a ve r d ade ele s us a m algo e special que foi adic i onado à J a v a 5 . 0 Tiger - tipos parametrizados.
A <String> com os sinais maior e menor é um Utipo

ArrayList<String >

d _ _ _ _ _ _ _ _ _ _ _ _ _ _ __

"

parametrizado", ArrayList<Stríng> significa simplesmente "uma lista de St:rings", diferentement.e de ArrayList<Dog>,
que significa
UtL'11el

lista de objetos

DogH~

Ant e s do Jav a 5. 0 , n ã o hav ia uma maneira d e decl a r a r o tipo do que s er i a ins eri do na ArrayList, portanto, para o c ompilado r, todas as ArrayLists eram simplesmente c o njun tos heterogêneos de objetos. Mas agora, com o uso da sintaxe <tipoEntraAqui > , podemos declarar e criar uma ArrayList que conheça (e limite) os tipos de objetos que pode conter. Examinaremos com detalhes os tipos parametrizados nas ArrayLists do capítulo sobre objetos Collection, portanto, por enquanto, não pense muito na sintaxe do sinal maior e menor <> que você verá quando usarmos ArrayLists. Você só tem que saber que se trata de uma maneira de forçar o compilado~ a permitir apenas u m tipo específico de objeto (o tipo dentro dos sinais maior e menor) na ArrayList.

código preparatório

Agora corrigiremos o código DotCom.
Lembre-se de que foi assim que deixamos a versão com falha:
publ i c class DotCom (
~~ ~-------------------------------------------------

Renomearemos a classe com DotCom
(em vez de SimpleDotCom), na versão avançada, mas esse é o mesmo código que você vi u no último capítulo.

int[ ] 1 0 cationCells; int numOfHits = O; pub lic v o id setLo cationCells ( int [] 10cation Cells = I ocs; Iocs )

_ .~

" I· .·
r< ~
A'

public String checkYourself(String stringGuess) int guess = Integer.parseInt(stringGuess); String resuIt for (int cell if (guess
result
=

ri

"miss 'l

i

10cationCells ) 'cell)
"hit /
!

i

numOfHits++; b reak;

É aqui que se encontra o erro. Contamos cada palpite como um ~---------------------------------------------- acerto, sem verificar se essa célula já foi adivinhada.

} II f o ra do l oop
if (numOfHits

==

10cati o nCells.length )

r e sult = "k i l l";

System . out . println(result) ; return resul t;
} II e ncerra o método II encerra a cla ss e

102 capitulo 6

conheça o APl Java

código
preparatóri.o

A nova classe DotCom aperfeiçoada

import java.util.ArrayList;
public class DotCom {

Ignore essa li nha por enquanto; ( - - - - - - - - - - - - - - - falaremos sobre ela no fim do capítulo.

private ArrayList<String> locationCells;

II private int numOfHits; II não precisamos disso agora

< ------(

~tera

a matriz de strings para uma ArrayList que contém str ings.

public void setLocationCells (ArrayList<String> loc) locationCells = loc;

public String checkYoursel f(String userlnput) String result
=

{ ( _ _ _ ______ Novo nome de

ar~ ~ento

aperfeiçoado.

Verifica se o palpite do usuário exista na ArrayList, procurando seu índice. int index = locationCells.indexOf(userInput); ~ Se e .Ie não estiver na lista, indexOf( ) retornará -1. ' (l.' ndex >= O) l. f , Se o ~ndice for maior ou igual a zero r

"missO;

{ d'________________
{

'

_______________ definitivamente o palpite do usuário estará na listar portanto remova-o locationCells.remove(index}; ~

if

(locationCells.isEmpty(})

Se a lista estiver vazia, essa será a ( - -- - - - - - - - linha eliminatória!

result "kill"; else { resu l t " hi t"; II encerra if

II encerra a instrução if externa
return result;

II encerra o método I I encerra a classe

Agora construiremos o jogo REAL: "Sink a Dot Com"
Temos trabalhado na versão 'simp les ', mas agora construiremos a real. Em v.ez de uma única linha, usaremos uma grade. E em vez de um objeto DotCom, usaremos três.
Objetivo: afundar todas as Dot Coms do computador no menor número de tentativas. Você receberá uma classificação ou nível, baseado em seu desempenho. Preparação: quando o programa do jogo for iniciado, o computador inserirá três DotComs, aleatoriamente. na grade virtual 7 x 7. Concluída essa etapa, o jogo solicitará seu primeiro palpite. Como você jogará: ainda não aprendemos a construir uma GUI, portanto essa versão funcionará na linha de comando. O computador solicitará que você insira um palpite (uma célula) , que deve se~ digitado na linha de comando (como "A3 ", "CS", etc). Em resposta a seu palpite, você verá um resultado na linha de comando, "C ~~_--,,,,, ?rret 9", "Errado" 21} "Você afundou a Pets.Com" (ou qualquer que seja a Dot Com de sorte do dia). Quando você ti ver eliminado t~das as três Dot Coms, o jogo terminaiã eXibindo sua classificação.

você está aqui.,.

103

)

criando DotCornBust
grade 7

x 7

,.----r-----r---.---~:..::.....:-=:;==-~--=:..:=-=;~--r D~ofcorn,_-comumagrade
A

Você vai construir o jogo Sink a 7x7e três Dot Coms. Cada Dot Com ocupa três células. parte de interação do jogo

B

D

E

F

G

A kMe. om

r
6

o
f

1

2

3

4

5

começa em zero como as matrizes ~ava

c a d a quadrado é uma "célula"

o que precisa ser alterado?
Temos três classes que precisam ser alteradas: a classe DotCom (que agora se chama DotCom em vez de SimpleDotCom), a classe do jogo (DotCornBust) e a classe auxiliar (com a qúal não nos preocuparemos agora).

o Classe DotCom
. Adicione uma variável name para armazenar o nome da DotCom ("Pets.com", "G02.com", etc.) para que cada objeto possa exibir seu nome quando for eliminado (consulte a tela de saída na página ao lado) .

Continuação da classe DotComBust...
Agora essa etapa será muito mais complexa do que antes, porque inseriremos as DotComs aleatoriamente. Já que não estamos aqui para manipul ar cálculos, incluiremos o algoritmo que fornecerá um local às DotComs na classe (predefinida) GameHelper. - Verifique cada palpite de usuário usando todas as três

G

Classe DotComBust (o jogo)

- Crie três objetos DotCom em vez de um. - Dê um nome a cada um dos três objetos DotCom. Chame um método de configuração em cada instância de DotCom, para que o objeto possa atribuir o nome a sua variável de instância name. - Ins ira as DotComs em uma grade em vez de em uma úni ca linha, não esquecendo de usar as três DotCol1ls .

DotComs , em vez de apenas uma.
- Continue com o jogo (isto é, aceitando os palpites do usuário e comparando-os com as DotComs restantes) até que

não haja mais· DotComs.

- Saia do método main. Mantivemos a versão simpl es em main apenas para ... Deixá-la simples. Mas não é isso que queremos no jogo real.

)"._~~.

-

conheça o APl Java

3 classes:

Usa para receber entradas do joga com

usuar~o

e criar

~ocais

para as

.DOCLOIllS

DotCornBust
A classe do jogo. Cria DotComs, recebe entradas do usuário, mantém o jogo até todas as DotComs serem el i minadas

DotCorn
Os objetos DotCom
reais.

GameHelper
A classe auxiliar (predefinida) . Sabe como aceitar entradas do usuário na linha de comando e cria locais para as DotComs .

As DotComs sabem seu nome, local e como verificar se um palpite de usuário coincide.

5 objetos:
Mais 4 ArrayLists: 1 para DotComBust e 1 para cada um dos três objetos DotCom .

DotCornBust

DotCorn

""

GameHelper

Quem faz o que no jogo DotComBust (e quando)


-r-.,

DotCornBust
A classe do jogo.

1

- - -- -- -)
objeto DotComBust

instancia

o método mainí ) da c lasse DotComBust instancia o objeto DotComBust que executa todo o jogo.

objeto DotComBust (o jogo) cria uma i:nst â n c i a de GameHelper. o ob j et o que a judará o jog o a fazer seu trabaLho.

o

objeto DotComBust

GameHelper

o

r
objeto DotComBust

objeto DotCamBust instancia uma ArrayList ~Je conterá os 3 objetos DotCom.

objeto ArrayList (para armazenar objetos DotCom)

'ices esü:; aqui

j.l-

105

estrutura detalhada do jogo

o

obj e ~o DotComBust cria três objetos DotCom (e os insere na~-rrayList)

objeto DotComBust objeto ArrayList (para armazenar objeto's DotCom) objetos DotCom

o objeto DotComBust solicita ao objeto auxiliar um local para um objeto DotCom (faz isso três vezes, uma para cada DotCom)

o objeto DotComBust fornece

um

local (que obtém do objeto auxiliar ) para cada um dos objetos DotCom na forma "A2" , "B2", etc. Cada ·objeto DotCom insere o local de sua célula em uma ArrayList

objeto ArrayList (para arma z enar células

objeto ArrayList

objeto ArrayList (para armazenar obje~os DotCom)

objeto ArrayList DotCom

o objeto DotComBust solicita ao
objeto auxiliar um palpite de usuário (o objeto auxiliar solicita ao usuár io e captura a entrada na linha de comando)

o objeto DotComBust percorre a lista de objetos DotCom e solicita a cada ~~ que verifique se contém o palpite do usuário . O objeto DotCom verifica sua ArrayList de locais e retorna um resultado
(Ucorzeto rr F

tterrado,r F etc .)

objeto ArrayList (para armazenar locais de células DotCom) objeto ArrayList

objeto DotComBust

objeto ArrayList (para armazenar objetos DotCom)
E a ss im o jogo continua.. ••

objeto ArrayList

Cap turando entradas do u suári o, solic~tando a c ada Do tCom que pro cure um acert o e d ando
prossegui me nto até ::.:odos os

abjetos DotCom serem e liminados

10q-"!,,g lpítulo 6

.r'·
conheça o APl Java

código preparatório

Código preparatório da classe DotComBust real
A classe DotComBust tem três tarefas principais: configurar o jogo, continuar o jogo até os objetos DotCom serem eliminados e terminar o jogo. Embora pudéssemos converter essas três tarefas diretamente em três métodos, dividiremos a tarefa intermediária (continuar o jogo) em dois métodos, para mantermos a granularidade menor. Métodos menores (o que significa blocos menores de funcionalidade) nos ajudarão a testar, depurar e alterar o código mais facilmente.
1..

DotComBust
GameHelper helper ArrayList dotComsList int numOfGuesses setUpGame(
)
)

1

startPlaying(

checkUserGuesses( finishGame(
)

)

W';;0H.i

0

Declare e crie a variável de instância GameHelper, chamada helper. Declare e instancie um objeto ArrayList para armazenar a lista de objetos DotCom (inicialmente três). Chame-o de dotComsList. Declare uma variável int para armazenar o número de palpites do usuário (para que possamos lhe fornecer uma pontuação no fim do jogo). Chame-a de numOfGuesses e configure-a com O. Declare um método setUpGame( ) para criar e inicializar os objetos
DotCom com nomes e locais. Exiba instruções resumidas para o usuário.

Declarações de variáveis

Declare um método startPlaying( ) que solicite palpites ao usuário

: Declarações de métodos

e chame o método checkUserGuess( ) até todos os objetos DotCom serem removidos do jogo.

Declare um método checkUserGuess ( ) que percorra todos os
objetos DotCom restantes e chame o método checkYourself( cada objeto DotCom. ) de

Declare um método finishGame ( ) que exiba uma mensagem sobre o desempenho do usuário, baseando-se em quantos palpites ele usou para eliminar todos os objetos DotCom. Método:

void setUpGame( )

II cria três objetos DotCom e os nomeia

Crie três objetos DotCom . Configure um nome para cada DotCom. Adicione os objet,os DotCom à dotComsList (a ArrayList) . Repita para cada um dos objetos DotCom da matriz dotComsList Chame o método placeDotCom( ) no objeto auxiliar, a fim de
obter um local selecionado aleatoriamente para esse objeto DotCom (três células, alinhadas vertical ou horizontalmente, em uma grade 7 X 7) .

Implementações de métodos

Configure o local de cada objeto DotCom baseando-se no
resultado da chamada a placeDotCom( ).

Fim da iteração Fim do método

......
."1f.; ~

r

.

você está

107

------------~

continuação das ;mplementaçôes de méto os

Continuação das implementações de métodos:
Método: void stllrtPlllying( ) Repita enqu anto exist i r al gum ob j et o Dot Com Capture a entrada do usuár i o chamando o método auxil i ar getUserInput ( Avalie o palpite do usuário com o método checkUserGuess( )
F i m da i teração Fim do mé t odo

Método: void

checkUserGuess (String userGuess)

I I verifica se houve o acerto (e eliminação) de algum DotCom

Incremente o número de p a lp i t es d o u suá r io na va ri áve l numOfGuesses . Configure a vari ável result d o l oc al (uma String) com "corret o", para o ca s o de o
u s uá r io ter ac e rtado o pa l pite.

Repita pa r a c a d a um dos ob jetos DotCom d a matr iz dotComsList Avalie o palpi te d o usuár io chamando o mé tod o checkYourself(
d o objeto DotC om .

Configure a variáve l d e re sultado com "corre t o" ou " e limi nar" s e apropr i ado. Se o resu ltado for "el i mi na r", remova o obj eto Do t Com de dotComsList.

Fim da iteração.
Exiba o valor d e result para o u suár io .
......... .

Fim d o método .
Método: void
finishGame (

Exiba uma mensage m g en é r i ca "f i m de jogo" e , e m s e guida : Se o número de p a lpite s do usuário for pequeno, Exiba uma mensagem d e c ongratu l a ç ão. Caso contrário, Exiba uma mens agem provocativa .

Fim do teste if . Fim do método.
Aponteseu lápis-------------------------------------------------------------------------------------~

Como devemos passar do código preparatório para o final? Começaremos com o código de teste e, em seguida, testaremos e construiremos nossos métodos passo a passo. Não ficaremos mostrando o código de teste neste livro, portanto chegou a hora de você pensar no que precisa saber para testar esses métodos. E que método testar e escrever primeiro? Tente criar um código preparatório para um conjunto de testes. O código preparatório ou até mesmo a discriminação dos pontos são o suficiente nesse exercício, mas, se você quiser tentar escrever o código de teste real (em Java), arregace as mangas .
código preparatório

Aponte s eu lápis
Comente você mesmo o código! çompare " anotações . . as ria pàrte inferior da próxima página com os números no código. . "Escreva .o número no 'espaço em frente ao' comentário correspondente. Você .usará cada comentário apenas uma . vez e precisará de todos.

import java. ut il .*; public cl a s s DotComBust

CI)(

priva t e GameHelpe r helper = n ew GameHelper() ; pr ivate Array List <DotCom > d otComs List = new Arr ayList <Dot Com> (); prlvate i nt numOfGuess e s = O; private void setUpGame () II pr i meiro cria alguns ob je tos DotCom e for n ece seus l ocais DotCom one = n e w DotCom( ); one . s etName (" Pets. com " ) ; DotCom two = new DotCom(); two . setName ("eToys . com") ; DotCom three = new DotCom (); three . setName ( "Go2 . com" ) ; \ d otComsLi st. add(one ) ; dotComsList . add(two) ; dotComsList.add(three); ~

l

I

®

J

108

ca pitu lo 6

f"\.~ ~ ".......

conheça o APl Java
System . out . println("Seu objetivo é eliminar três dot coms . "); System . out .println ("Pets. c om, eToys . com, G02 . com ") ; Sys tem . out . println ("Tente el iminar todas com o menor númer o de for (DotCom dotComToSet : dotComsList) ( ~ ArrayList<String> newLocation = helper.placeDotCom(3); ~ dotComToSet . setLocationCells(newLocation); ~ II encerra o loop for II ence rr a o método setUpGame pri vate void startPlaying ( ) while(!dotComsList . isEmpty{) ) String userGuess = helper . getUserlnput("Insira um palpite"); checkUserGuess(userGuess); } II encerra while finishGam e () ; II ence rr a o método startPlaying
"-

II'!"'
1---

I",

palPiteS");~ ®

(0

®

®

@

.,i

,'r--

pri vate void checkUserGuess (St ring u se rGues s ) numOfGuesses++; ~ St ring r esult = "errado "; fo r (DotCom do tComToTest : dotC omsLis t) ~ res u lt = do tComToTe st .checkYoursel f( use rGues s) ; ~ if (result. equa ls ("correto")) ( break;

@

®

if

(result . equals ( "eliminar") ) dotC omsList. remove (dot ComToTest) ; br eak;

1,

II encerra f or System.out . pr in tln(result) ; II encerra o método

®

1._
.~

Jl"'-'"

~ -­

~

i

]r--

'1

"1~~-

pr i vate void finishGame () System.out.println{"Todas as Dot Coms foram e l iminadas ' Agora seu conjunto está vazio ." ); if (numOfGuesses <= 18) ( System.out . println("Você só usou" + numO f Guesses + " palpites.") ; Sys tem. out . println{"Você saiu ante s de el i minar suas opções . "); else ( Sys tem. out .println(" Demorou demais . "+ numOfGuesses + " palpites."); Sys tem. out . println{"Não haverá pesca com es sas opções.");

1

II encer ra o método
public stat ic void rnain (String[J args) ( DotComBu st game = new DotComBust(); ~ game . setUpGame ( ) ; game. startPl ayi ng () ; II encerra o método

)

@

@

Faça o que quiser, mas NÃO vire a página! Não até ter terminado esse exercício. Nossa versão está na próxima página.
~

deClara e inicializa as varíáveís de que precisaremos

exibe instruções resumidas para o usuário c hama nosso próprio métod o fin ishGame captura a entrada do usuário chama o método de configuração nesse objeto DotCom para lhe passar o local que você acabou de obter do objeto auxiliar
-. cria três objetos DotCOill, fOI:7:1ece nomes p.ara elss e 0$ insere na A:rz'ayList

incrementa o número de palpites que o usuário usou sai do l oop antecipadamen te, não são necessários

I
I I
i,
~

I

out ro s testes __ repete para todos os objetos DotCom d a lista solicita ao objeto de jogo que inicie o loop principal de execução da part ida (solicita entradas do usuário e verifica palpites oontinuamente) ~ exibe uma mensagem informando ao usuár_io como ele j

se sai u na jogo
pres~~e lli~

solicita ao objeto auxilíar o local de um objeto DotCcm
repete para cada LotCOill da 2ista

'acerto', a menos que seja informado do contrário

chama
esse

nos~o

próprio mecodo

c1~eckUseZ"Gu$SS

-'- Contanto qUia

a lista de objetos DotCcm tJ.~i.J esr;eJ'< ije'"i."

objetD feio elindnado, portanto X"a.mova.-o da. lis ta de t"!b'1ât!"}~; DotCom ()~ â.."11 seguida, Sd.i~ do .1.oop

-1~
j

_

exibe o resuLtado para o usuá~io solioita ao objeto de jogo '~Je configure a partida
'·vlJ..::ic-

do :"mário:'

::o::~::~o~::-:e.;::

--~-'- ~- ~-~~._-

~·::::::i :f:'q'.J.'"

"

IY"}!"'''~

(ou elim.inação)

cría o objeto de jogo

você esta aqui

11>

109

o código de DotCornBust (o jogo)

código
preparatório

import jav a.util.*; public class DotComBust

Declara e inicializa as variáveis de que preciSare1l10S.

private GameHelper helper = new GameHelper(); priva te ArrayList<DotCom> dotComsList = new ArrayList<DotCom>(); private int numOfGuesses = o·

private vo id setUpGame () II pr imeiro cria alguns objetos DotCom e fornece seus locais DotCom one = new DotCom(); one.setName("Pets . com" ) ; DotCom two = new DotCom(); two. setName ("eToys . com" ) ; Cria três objetos DotCom r fornece nomes para eles DotCom three = new DotCom(); e os insere na ArrayList. three. setName ("G02 . com") ; dotComsL is t.add(one); dotComsList.add ( two) ; dotComsList . add(three); System.out.println ("Seu objetivo é e liminar três dot coms . "); System . out .println ( "Pets. com, eToys . com, G02. com") ; . System . out.println("Tente eliminar todas c om o menor número de pa lpltes" ) ; for (DotCom dotComTo Set : dotComsList) ArrayList<String> newLocation =

Cria uma ArrayLisé de objetos DotCom ( em outras palavras , uma lista que armazenará SOff1ENTE objetos DotC~~, da mesma forma que DotCom[] significaria tma matriz de objetos DotCom).
r--. ' .

~

Exibe instruções
resumidas para o usuáriD.

Repete para cada DotCom da lista. Solicita ao objeto auxi liar o helper. placeDotCom (3) ; ~( ____ local de tm objeto DotCom {uma ,ArrayList de Strings}. Chama o método de confiTJração nesse objeto DotCom para lbe passar o local ~Je você acabou de obter do objeto auxiliar .
Contanto que a lista àe objetos DotCom NÃO esteja vaz i a {o J significa rIJÃo, é o mesmo que (dotComsList.isEmpty( ) " '" false).

dotComToSet. setLocationCells (newLocation);

~( :.-----------­

) II encerra o loop for II encerra o método setUpGame
private void startPlaying () while(!dotComsList.isEmpty(»

(---------------------~

String userGues s = helper. getUserInput ("Insira um palpite "); checkUser Guess (userGuess);

Captura a ent rad a do usuário .

Chama nosso próprio método checkUserGuess. finis h Game( ) ; ( ___________________________________________ Chama nosso próprio método finishGame. II encerra o método startPlaying
~( :.---------------------­

II encerra wh ile

private void checkUserGuess (String u serGuess) Incrementa o número de palpites numOfGuesses++; (?-- - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - que o usuário usou. Presume um 'acerto'r a menos que String resul t =" errado" ; ""( - - - - - - - - - - - - - - - - - - - - - - - - ' seja informado do contrário. Repete para todos os objetos for (DotCom dotComToTest : dotComsList) ( ------------ - - ---------DotCom da lista. Solicita ao objeto DotCom que verifique o palpite do usuário, result = dotComToTest.checkYourself(userGuess); ( - - - - - - - procurando um acerto (ou if (resu lt . equa l s ("correto"» { eliminaçã.o) . break; ( ___________________________________________ Sai do loop an tecipadamente r não são necessários outros testes . if (result . ",quals("eliminar"» dotComsList. remove(dotComToTest) ; break;
)

Esse objeto foi eliminaão , portanto remova-o da lista de objetos DotCom e, em seguida., saia do loop. Exibe o resultado para o usuário.

II encerra for
System .out . print ln(res u lt) ;

II encerra o métod o

(-----------------------------

11 0 capitulo 6

,~

~~ .

conheça o APl Java
private void finishGame () System.out.println("Todas as Dot Coms foram eliminadas! Agora seu conjunto está vazio."); if (numOfGuesses <= 18) ( System . out.println("Você só usou" + numOfGuesses + " palpites."); System.out.println("Você saiu antes de eliminar suas opçôes."); e1se ( System.out . println("Demorou demais. "+ numOfGuesses + " palpites . "); System.out.println("Nào haverá pesca com essas opçôes.");
}

h
I"
i......

II encerra o método
.j

'-'
public static void main (String[] args) DotComBust game new DotComBust(); game.setUpGame();

Exibe . . . meneagem informa.ndo ao usuário como
ale se saiu
110

~

jogo~

r

I

h
~h
'i

cria o objeto de jogo. Solicita ao objeto de jogo que configure a partida. Solicita ao objeto de jogo que inicie o loop principal de execução da partida (solicita
entradas do usuário e verifica

game.startPlaying();

II encerra o método

palpites continuamente).

A versão final da classe DotCom
import java . util . *; public class DotCom private ArrayList<String> private String name;

locationcells;~

variáveis de instância àe DotCom: - uma ArrayList de locais de células - o nome do cbjeto DotCcm um método de configuração que atualiza o local do
objeto DoéCom.

public void setLocationCell s (ArrayList<String> 10c) 10cat i onCells = loc;

(Local aleatório fornecido

pelo método placeDotCom{
de GameEelper.) Seu método básico de

public void setName(String n) name -= TIi

{ ( - -- - - - - - - - -- - - - - - - - -

configuraçã.o

public String checkYourself (S t ring userlnput) String result = "errado"; int index = 10cationCells . indexOf (userlnput); ( - - -- - - - - - - - - i f (index >= O) (

o método indexOf( ) de ArrayList em ação! Se o palpite do usuárío coincidir com ~~a das entradas de ArrayList, indexOf( ) retornará seu local na lista~ Caso contrário, indexOf( )
retornará -1.

10cationCells.remove(index);

Usando o método remover ) de ArrayfJ:i.st paz"a excluir uma

if

(locationCells . isEmpty () ) result = "eliminar";

entrada" Usando o método isEmpty( } para saber se todos os locais for~~ adivinhados»

System.out . println("Ora! Você afundou" + name + " else ( result = "correto"; II encerra if II encerra if return result;

Retorna. 'errado ou : el,Iloi,;r;a,:,{;" f ~

j' 6'

correto #

II encerra o método II encerra a classe

você está

111

p
n

...,11
~1,

expressões booleanas

,--.J
.~

Expressões booleanas super-poderosas
Até agora, só usamos expressões booleanas simples em nossos loops ou testes if Usaremos expressões booleanas mais poderosas em alguns dos códigos predefinidos que você verá em breve e mesmo sabendo que você não vai olhar, achamos que esse seria um bom momento para discutirmos como aperfeiçoar suas expressões.

~-{
~!;

"-~
r----

Operadores "E' e 'Ou' (&&,

II>

n'P-

~J

it

Suponhamos que você estivesse criando um método chooseCamera( ), com várias regras sobre que câmera selecionar. Você pode querer selecionar câmeras no intervalo entre $50 e $l.000, mas em alguns casos vai preferir limitar o intervalo de preços com mais precisão. Talvez queira dizer algo como: 'Se o intervalo de preços estiver entre $300 e $400, então, selecione X'.
if (price >= 300 && price < 4 00) camera = "X"i {

~.:1
~l
-1'/

~~

,--..;1 .

Suponhamos que, das dez marcas de câmeras disponíveis, você tenha alguma lógica aplicável a apenas algumas da lista:
if (brand.equals("A") II brand.equals("B") ) II executa algo somente para a marca A ou a marca B

As expressões booleanas podem ficar muito grandes e complicadas:
if «zoomType.equals("optical") && (zoomDegree >= 3 && zoomDegree <= 8» II (zoomType.equals("digital") && (zoomDegree >= 5 && zoomDegree <= 12») { II executa uma operação relacinada ao zoom

Se você quiser adotar uma postura realmente técnica, talvez pergunte algo sobre a precedência desses operadores. Em vez de se tornar um especialista no enigmático universo da precedência, recomendamos que use parênteses para tornar seu código claro.

Operador de exceção (!= e !)
Suponhamos que você tivesse uma lógica do tipo "dos dez modelos de câmera disponíveis, uma certa coisa é verdadeira para todos exceto um".
if (model != 2000) { II executa algo que não é aplicável ao modelo 2000

ou pm-a comparar objetos como as strings ...
if (!brand .equals ( "X"» { II executa algo que não é aplicável à marca X

Operadores de abreviação (&&,

II>

Os operadores que examinamos há pouco, && e II , são conhecidos como operadores de abreviação . No caso de &&, a expressão será verdadeira somente se os dois lados forem verdadeiros. Portanto, se a JVM detectar que o Jado esquerdo de uma expressão && é falso, ela parará exatamente aí! Não se preocupará em examinar o lado direito. De maneira semelhante, com o operador II , a expressão será verdadeira se um dos lados for verdadeiro, portanto se a JVM detectar que o lado esquerdo é verdadeiro, ela considerará a instrução inteira verdadeira e não se importará em verificar o lado direito. . . Por que isso é bom? Suponhamos que vocêJivesse uma variável de referência sem ter certeza se ela foi atribuída a um objeto. Se tentar chamar um método usando essa variável de referência nula (isto é, no caso dela não ter sido atribuída a nenhum objeto), você verá uma exeeção Nu IlPointerException. Portanto, tente isto:
if (refVar ! = null && refVar.isValidType() ) { II executa a operação se o tipo for válido

Operadores sem abreviação (&,

D

Quando usados cm operações booleanas, os operadores & e I agem como seus correlatos && e II, exceto por forçarem a JVM a sempre verificar os dois lados da expressão. Normalmente, & e I são usados em outro contexto, para a manipulação de bits.

112

6

·r'

conheça o APl Java

j;--'"

Código pré-definido

Essa é a classe auxiliar do jogo. Além do método das entradas de usuário (que so li cita ao usuário e lê as entradas na linha de comando), a grande tarefa da classe auxiliar é criar os Jocai s dos objetos DotCom nas células. Se fôssemos você, não mexeríamos nesse código, exceto para digitar e compilá-lo. Tentamos mantê-l o bem si mples para que você não tivesse que digitar muito, mas isso s ignifica que ele não ficou muito legível. E lembre-se de que você não poderá compilar o classe de jogo DotComBust até ter essa classe.

import java . i o . *; impor t java.util . *; public class GameHelper Nota: como exercício private private pr i v ate private private static final String alphabet "abcdefg"; int gridLength = 7; int gridSize = 49; int [] grid = new int[gridSize]; int comCount = O;
adicional, você poãe tentar 'desativar' as linhas System.ouc.println( ) do método placeDotCom, apenas para vê-lo funcionar ! Essas instruções de exibição permitirão que você "trapaceie" ao forneCerem o local dos objetos DotCom , mas o ajudarão a testá-la.

Ir-

I

~

i

public String getUserlnput(String promp t) String inputLine = null; System.out . print(prompt + " ") ; try ( BufferedReade r is = new BufferedReader( new I nputStreamReader(System . in)); inputLine = is.readLine(); if (inputLine.length () == O ) return null; } catch ( IOException e) ( System.out.println("IOException : " + e); return inputLine . toLowerCase();

.

Ir
t~

I~

j

L-,

4

~ ..............

il-0
.

public Arr ayList<String> placeDotCom(int comSize) ArrayL is t<String> alphaCells = new ArrayList<String>(); String [] alphacoo rds = new String [comSize]; String temp = null; in t [] coords = new int[comSize]; int attempts = O; boolean success = false; int loca t i on = O; comCount++; int incr = 1; if (( comCount % 2) == 1 ) incr = gridLength; while ( ! success & attempt s++ < 200 ) location = (int) (Math . random() * gridSize); IISystem.out.print (U try U + location); in t x = O; success = true; while (succe ss && x < c omSize) if (grid[location] == O) coords[x++] = location; l ocation += incri if (location >= gridSize) ( success = false; if (x >O && (location % gridLength success = false;
O) )

II II II II II II II II II II

contém as coordenadas de tipo 'f6' string temporária para concatenação coordenada dos candidatos atuais contador das ten tativas atuais flag = encon trou um bom local? local inicial atual enésima dot com a inserir configura o incremento horizontal se dot com ímpar (inserir verticalmente) configura o increment o vertical

,..

II loop de pesquisa principal (32) II captura ponto inic ial aleatório II II II II II II II II
enésima posição de dot com a inserir presume sucesso procura locais a dj acentes não utilizados se ainda não esti verem sendo usados salva o local tenta o 'próx imo' local adjacente fora dos limi tes - 'embaixo' falha

II for a dos limit es - canto direito II falha II encontrou local já utilizado

,r

else II System. out .print (U used succe ss = fal se;

U +

location);

II falha II fim de while II converte o l ocal em coordenadas alfabéticas

.-

in t x = O; int r ow = O; ~ olumn = J) ;_ II System. out .println (" ln"); while (x < comSize) grid[coords[x]] = 1;

II marca os pon tos da grade corno 'usados'

você está aqui

~

113

~~

__..7;{t

pacotes cJo APl
I I captura o valor da linha row = (int) (coords [xl / gridLength); -----i /'-;/' captura- D-·--va-rur"-numé-r-i-c:o --da--co 1 una . co l umn = coords lx r -% gr-:Uir;-e rrqctr;--"- ' .-- -/1 converte em alfabético temp = String.valueOf(alphabet.charAt(co l umn}}; alphaCells.add(temp.concat(Integer . toString(row}}} ; x++; E'S'S:ã é in.st:l"ução que lhe II System.out.print(" coord "+x+" = .. + alpbaCells.get(x-l)); informará exatame11te onde (} objeto DotCcrn está localizado~ I I System. out .println (" \n"); return alphaCells;

"j "-:_:..J
/\

.

Usando a biblioteca (o APl Java)
Você conseguir concluir o jogo DotComBust, graças'à ajuda da ArrayList. E agora, como prometido, é hora de aprender como pesquisar na biblioteca Java.

No APl Java, as classes estão agrupadas em pacotes.

Para usar uma classe do APl, você terá que saber em que pacote ela está.
Todas as classes da biblioteca Java pertencem a um pacote. O pacote tem um nome, como javax.swing (um pacote que contém algumas das classes de GUI do Swing sobre as quais você aprenderá em breve). AlTayList está no pacote chamado java.util, que, por surpresa, contém uma pilha de classes utilitárias. Você aprenderá muito mais sobre os pacotes no Capítulo 16, inclusive como inserir suas próprias classes em seus próprios pacotes. Por enquanto, queremos apenas usar algumas das classes que vêm com a Java.

É simples usar unia classe do APl em um código que você criar. Basta tratar a classe como se você mesmo a tivesse criado ... Como se a tivesse compilado e lá estivesse ela, esperando ser usada. Com uma grande diferença: em algum local de seu código você terá que indicar o nome completo da classe de biblioteca que deseja usar, e isso significa nome do pacote + nome da classe.
Caso não saiba, você já usou classes de um pacote. System (System.out.println), String e Math (Math .random( )), todas elas pertencem ao pacote java.Iang.

Você precisa saber o nome completo· da classe que deseja usar em seu código
ArrayList não é o nome completo dessa classe, assim como 'Kathy' não é um nome completo (a menos que seja como Madonna e Cher, mas não entraremos nesse assunto). O nome completo de ArrayList na verdade é:
java.util.ArrayList

Você tem que informar ao Java que ArrayList deseja usar. Há duas opções: " IMPORTAR
Insira uma instrução de importação no início do arquivo de seu código-fonte:
import java.util.ArrayList; public class MyClass { ...

114

6

conheça o APIJ;:)'!;;;

ou
G DIGITAR
Digite o nome completo em todos os locais de seu código. Sempre que uSLí.-lo. Em qualquer local que usá-lo. Quando você declarar e/ou instanciá-Io:

,.........

java . util . Ar r ayList<Dog> list = new java . uti l. ArrayLi st <Dog>() ;

Quando usá-lo como o tipo de um argumento:
public void go (java . util . ArrayList<Dog> list) { }

Quando usá- lo como um tipo de retomo:
public java.util . Ar rayList <Dog> foo() (. . .)

* A menos que a classe se encon u'e no pacote java.lang.
. r-.

Não existem

rf' i~
'[

Perguntas Idiotas

L-,

P: Por que é preciso ter um nome completo? Essa é a única finalidade de um pacote?
Os pacotes são importantes por três razões principais. Primeiro, eles ajudam na organização geral de um projeto ou biblioteca . Em vez de termos apenas uma pilha extremamente grande de classes, elas se encontram todas agrupadas de acordo com tipos específicos de funcionalidade (como a GUI , as estruturas de dados, coisas relacionadas a bancos de dados , etc.). Em segundo lugar, os pacotes lhe fornecerão o escopo de um nome, o que o ajudará a evitar conflitos se você e 12 outros programadores de sua empresa decidirem criar uma classe com o mesmo nome. Se você tiver uma classe chamada Set e em outro local (inclusive no APl Java) também houver uma classe chamada Set, você terá uma maneira de informar à JVM que classe Set está tentando usar. Em terceiro lugar, os pacotes fornecem um certo nível de segurança, porque você podera restringir o código que escrever de modo que só outras classes do mesmo pacote possam acessá-Io. Você aprenderá tudo sobre isso no Capítulo 16 .

t~
,
i

R:

i!r'~
.-

l~

. ~~

l~
10

-

I; i ir ;L ::a:~~:::~Sa:~~I~cos .. ~
j~

i~

Certo, voltamos ao assunto da colisão de nomes. Como um nome completo poderia realmente ajudar? O que fazer para eVitar que duas pessoas forneçam a uma classe o mesmo nome de pacote?
A Java tem uma convenção de nomeação que geralmente impede que isso ocorra , contanto que os desenvolvedores a adotem. Veremos isso com mais detalhes no Capítulo 16.

P: R:

t~
r

De onde saiu esse 'x'?

(ou, o que significa um pacote começar com javax?)

r '"' · "

N

a primeira e segunda versões da Java (1.02 e 1.1), todas as classes que vinham com a linguagem (em outras palavras, a biblioteca padrão) se encontravam em pacotes que começavam comjava . É claro que sempre houve o pacotejava.lang - aquele que não é preciso importar. E havia ojava.net, ojava.io, ojava.util (embora não houvesse na época algo como a ArrayLlst) e alguns outros, inclusive o pacotejava.awt que continha classes

~<-,.'~->;o.-"_ . _,

." :

surgiram outros pacotes não incluídos na bibli oteca padrão. Essas classes eram conhecidas como e~!ellsões e ex istiam em duas versões principais: padrão e não-padrão . As extensões padrão eram aquelas que a Sun considerava otcl é!~~não !2ªcotesQQerin~Qtai~~açesso antecipado ou beta que podiam ou não ser publicados.

TOdas as extensões padrão, por convenção, começavam com um 'x' acrescido ao pacotejava comum ini cwl. A mãe de todas as extensões padrão foi a bibl ioteca Swing. Ela incluía vános pacotes, todos começando co mjavax.swillg você está aqui,.. 115

»

quando as matrizes não são sufic.ien:es

Mas as extensões padrão podem ser promovidas a pacotes de primeira classe da biblioteca, illcorporados ao Java, padrão, porém autónomos. E foi isso o que aconteceu com o Swing, a partir da versão 1.2 (que acabou se tornando a primeira versão chamada de 'Java 2'). "Interessante", todos pensaram (inclusive nós). "Agora todas as pessoas que têm Java terão as classes Swing e não precisaremos descobrir como instalá-las com nossos usuários finais."

_________ _

------ isCRIMINAÇÃO DOS PONTOS D
- ArrayList é LIma classe do APl Java. - Para inserir algo em uma ArrayList, use add( ). - Para remover algo de uma ArrayList, use remove( ). " Para saber onde algo se encontra Ce se existe) em uma ArrayList, use indexOf( ). - Para saber se uma ArrayList está vazia, use isEmpty( ). - Para saber o tamanho (quantidade de elementos) de uma ArrayList, use o método size( ). - Para saber o tamanho (quantidade de elementos) de uma matriz antiga comum, lembre-se, você usará a variável length. - A Array List será redimensionada automaticamente para o tamanho necessário. Ela crescerá quando objetos forem inseridos e diminuirá quando objetos forem removidos . - Você declarará o tipo da matriz usando um parâmetro de tipo, que é o nome de um tipo entre os sinais maior e menor. Exemplo: AnayList<Button> significa que a AnayList poderá conter somente objetos de tipo Button (ou subclasses de Button como você aprenderá nos próximos capítulos). - Embora uma ArrayList armazene objetos e não tipos primitivos, o compilador "encapsulará" automaticamente (e "removerá o encapsulamento" quando você o utilizar) um tipo primitivo em um tipo Object e inserirá esse objeto na AnayList em vez do tipo primitivo. (Veremos mais sobre esse recurso posteliormente no livro.) - As classes estão agrupadas em pacotes. - A classe tem um nome completo, que é uma combinação do seu nome com o nome do pacote. A classe ArrayList na verdade se chama java. util.Anay List. - Para usar a classe de um pacote diferente de java.lang, você terá que informar ao Java o nome completo da classe. - Você usará uma instrução de importação no início de seu códigofonte ou poderá digitar o nome completo em todos os locais que usar a classe em seu código.

o problema era ir além do óbvio, no entanto, porque,. quando os pacotes são promovidos, fica bem CLARO que eles têm que começar comjava e nãojavax. Todo mundo SABE que os pacotes da biblioteca padrão não têm esse "x" e que ele só é encontrado nas extensões. Portanto, imediatamente (e queremos dizer no sentido literal) antes de a versão l.2 ser concluída, a Sun alterou os nomes dos pacotes e excluiu o "x" (entre outras alterações). Livros foram impressos e apareceram nas lojas tendo o código Swing com os novos nomes. As convenções de nomeação continuavam intactas. Tudo estava correndo bem no universo Java.
Exceto pelos cerca de 20.000 desenvolvedores que perceberam que com essa simples alteração no nome viria o desastre! Todos os seus códigos que faziam uso do Swing teriam que ser alterados! Desespero! Pense em todas as instruções de importação que começavam comjavax ... E, no último momento, histéricos , quando suas esperanças chegavam ao fim, os desenvolvedores convenceram a Sun: "dane-se a convenção, salvem nossos códigos." O resto é história. Portanto, quando você se deparar com um pacote da biblioteca que comece comjavax, saberá que no início ele era uma extensão e então conseguiu uma promoção.

Não existem

Perguntas Idiotas
A instrução import tornará minha classe maior? Ela fará realmente com que a classe ou o pacote importado seja compilado em meu código? Você é programador de C? A import não é igual a include. Portanto, a resposta é absolutamente não. Repita comigo: "uma instrução import lhe fará digitar menos". É isso que ocorrerá . Você não terá que se preocupar com o fato de o seu código ficar maior, ou mais lento, por causa de muitas importações. A instrução import é simplesmente uma maneira de você fornecer à Java o nome completo de uma c/asse. Certo, então porque nunca tive que importar a classe String? Ou System?
116 capítu lo 6-.: :
....;::..::...::..-i'..,. _

P:

R:

instruçã~

Lembre-se de que é possível obter o pacote java .lang como se ele tivesse sido "pré-importado" sem maiores formalidades. Como as classes de java.lang são tão fundamentais, você não terá que usar o nome completo. Há apenas uma classe java.lang .String e uma classe java.lang .System e a Java sabe muito bem onde encontrá-Ias. Tenho que inserir minhas próprias classes em pacotes? Como fazer isso? Posso fazê-lo? No dia-a-dia (que deve ser evitado), sim, você vai querer inserir suas classes em pacotes. Discutiremos isso com detalhes no Capítulo 16. Por enquanto, não inseriremos nossos exemplos de código em um pacote.

R:

P: R:

P:

conheça o APl Java

Ir"'

1'-'"

I

I-

o Java

Repetiremos mais uma vez, para o caso improvável de você ainda não ter entendido:

Torne fácil lembrar
Rosas são se você nã ve~elhasmaçãs são o lmportartera' que azedas digita Você deve . lnforntar a que Usar, a m o Java o nome java . lang. um:n?S que essa classe :omPl eto de toda classe início de s lnstrução import e encontre no pacote Contrá' eu CÓdigo - fonte' para a classe ou rlo, você ter' e a maneira f' . pacote no em todos os lo . a que digitar o aCll . Caso calS que u sá- la . nome completo d a cla sse,

lI

Como manipular o APl
Duas coisas que você quer saber:
J

I"",

t .. ;,
,

O Que classes

existem na biblioteca?

"Bom saber que há uma ArrayList no pacotejava.util. Mas como poderia descobrir isso sozinha?"
-J ulia, 31, modelo de trabalho manual

Quando encontrar uma classe, como descobrir o que ela consegue fazer?

O

Pesquise em um livro

Use os documentos HTML do APl

O·REILl.':"·

"oce

b~t} ;:>(!\.I!Io-

117

conhecendo o APl

o

Pesquise em um tivro

Folhear um livro de referência é a melhor maneira de descobrir o que existe na biblioteca Java. Você pode facilmente encontrar uma classe que pareça útil, apenas examinando as páginas.

java.util.Cunency
RetlfTl1ed B)'." java.text.DecimaIFormat.getCurrencyO, java.text.DecimaIFormatSymbols.getCurrency(), java.text.NumberFormaLgetCurrency(). Currency.getlnstanceO

nome da classe -----------------------) nome ão pacote -----------------------)

Date
java.util

Java 1.0

cloneable serializable comparable

r-, .

This c1ass r~presen!S dates and times and lers you work wirb lhem il1 a sysleru-ind ependem ,vay. You can create a Date by specifying the number of miIJiseconds from tbe epoch Cmiclllight GMT, ]anuary 1st, 1970) ar tlle year, month, date, and , optionally, the " ho ur, minute, and second. Years are specified as the number of years since 1900. lf you d escrição da c l as se ----------------~) call the Date constJUctor with no arguments, tlle Date is initialized to the current time and date. The instance metbods or the c1ass allow you to get and set the various date " and time lields, to compare dates and times, and to convert dates to and fram string representations. As of Java 1.1, man)' of the date merhods have been deprecated in favor of the metll0ds of the Calendar class.

ICloneable II Comparable IISerializa~'el
public classOate implements tlo.neable, Comparáble, Serializable (

Q§iJ..... .

Date

II Public Constructors
' public Dàte(); . public Date(long date) ; ; ,,public Dàt~~irjQÜ); ~"·. t pUblic Date ~ntyear, int month, int date); ~ PUblic Date(intyear: int month, int date, int hrs, int mini; # public Date(intyear, int month, int date, int hrs, int min , int sec); ;/PropertyAócessor Methodi; (by property name) ' .. public long getTime(); public void setTime(long time); II P uMe Instance Meth.ods public boolean afterÜava.util.Date wIIen); public boolean beforeÜava.util.Date when); 1.2 publi c int compareToO ava.util.Date anotherDate); li Methods implementíng Comparable 1.2 public int compareTo(Object o); !IPublic Methods Overriding Object 1.2 public Object cloneO; pUblic boolean equals(Object obj); public int hashCode(); pUbliC" S tring toString(); II D eprecated Public Methods # . public intgetDate(); # public int getDay(); putilic int getHoursO; public int getMinutes{); public int get Moi.ih(); # public int getSeconds(); li public int getTimezoneOffset(); # pUblic int getYear(); • publi c stati c long pa rse(Stri ng s): public void setDate(int date); # public void setHours(int hours); public void setMinutes(int minutes); # public vO{d'setMonth(int month);

métod os (e o ut r a s coisa s s obre as qua is fal aremos posteriormente)

.---

-----

118'--' cap itulo 6

- - ---

--.;...

conheça

0

.AP! J-j\!;;;

e Use os documentos HTML do APl
o Java vem com um fabuloso conjunto de documentos on-line, estranhamente chamado de
APL Java. Eles fazem parte de um conjunto maior chamado Java 5 Standard Edition Documentation (que, dependendo do dia da semana em que você examinar, a Sun pode estar chamando de "Java 2 Standard Eelition 5.0") e seu downloael têm que ser feito separadamente; eles não vêm incorporados ao c1ownloael da Java 5. Se você tiver uma conexão de Internet ele alta velocidade, ou muita paciência, também poderá pesquisá-los em java.s un.com. Acredite, aposto que você vai querer esses documentos em seu disco rígido .
.L

Os documentos do APL são a melhor referência para a obtenção de mais detalhes sobre uma classe e seus métodos. Suponhamos que você esteja pesquisando no livro de referência e encontre uma classe chamada Calendar, em java.uti!. O livro lhe informará alguma coisa sobre ela, o bastante para que você saiba que é realmente isso que quer usar, mas será preciso saber mais sobre os métodos. O li vro de referência, por exemplo, lhe informará o que os métodos usam como argumento e o que retornam. Vejamos ArrayList. No livro de referência, você encontrará o método indexOf( ) que usamos na classe DotCom. Mas, se você soubesse apenas que há um método chamado indexOfO que usa um objeto e retorna o índice (um inteiro) dele, ainda teria que saber uma coisa crucial: o que acontecerá se o objeto não estiver na ArrayList? Examinar a assinatura do método isoladamente não lhe infom1ará como ele funciona. Mas os documentos do APl informam (pelo menos , na maioria das vezes). Os documentos do APL lhe informarão que o método indexOf( ) retomará -1 se o parâmetro de objeto não estiver na ArrayList. É assim que saberemos se é possível us<1-10 como uma maneira de verificar se um objeto existe na ArrayList e também para conhecer o índice, se o objeto estiver nesse loca!. Mas, sem os documentos do APL, podemos achar que o método indexOf( ) não funcionará se O objeto não estiver na ArrayList.

Examine os pacotes selecione um (c2ique nele) para limitar a lista do painel a seguir somente às c~asses desse pacote.
e

®
Examine as classes e selecíone uma (clique ne2a) para escolher a que preencberá a janela principal do navegador.

Ctasses
~írlW\Q\in.1C!iQu

~ ~
~t:lru

Atlstf'ilC1Oueu8
AbsfroClSeOtenUilíLst

~

árulMl tY..m*
ç.!!!.WJl$1! CQtieç'lco.'
~

l2o-ah<l O rui9ll.1à.t~Qlj<? e :H :.and$ ~> C)

i'\ p{X:'ncts ail \)( lhe dCmClJ ~'i in l b{;~ spctifi. ·-iI CnUcclj(m )ü lhe dJ1U !lf úlis list.-iI) tlle order lhal tiley are rcmmcd by lhe 'pecil1cd Colle.:lÍol1 ', II.:mlor.
b;x{)luf.l ~dd;;'l1-fi:\'!:. ...n:idex, Ç9..u,;;.Ç":~q. t;.<.' u;.:t!:r.i,i!~ ~ C l

Qru'i.
Q~

lmClli.JU of lhe ~l-em~nl<;
,~tí(·.In.)\,lfio"

ln

me spenfh:d Coll-é:ction mm Lhis:

lbl • .-;I:J:r1mg :lt

thc..:

r----~~-------------------------------------------

você está aqui

f>

119

---'

-

exercício: imãs corn códi90

Você conseguiri a reorganizar os trechos de código para criar um programa Java "...-- - =--"--f~u-n ~ -c ionaf que produzisse a saída li stada a seguil-?-Nota: Para fazer esse exercício, você t1 -:')ô ~ . ~""'oP ~ precisará de um NOV O tipo de informação - se procurar ArrayList no APl, encontrará ~ um segundo método add que usa dois argumentos:
Add(int index, Object o)

"-

"-,,,

Ele permitirá que você especifique para a ArrayList onde inserir o objeto que você está ad icionando.

public static void if (a.cont . a1.ns("t WO"» a . add ( "2 . 2" ) .

--' ,....

"'~

public

static

void

main
+

(String[J
");

args)

system . out.print(element

system.out.println("

");

if

(a . contains("three" » a . add("four") ;

class if

ArrayListMagnet
!=

(a.indexOf("four")

a . add (4.

"4 . 2" ) ;

\j~~~~-

fJ
a
for new ArrayList<string> () ; (String e1 ernent

120 _ capitulo 6

Cruzadas Java 7.0

conheça o APl Java Como esse jogo de pala vras cruzad as o ajudará a aprender Java? Be m. todas as pa lavras têm re lação com a Java (ex ceto e m uma te ntati va de confundi -lo) . Dica: quando esti ver em dúvida, lembre-se de ArrayList.

Horizontais
1. Não consigo me comportar

Verticais
3. Unidade endereçável 4. Segundo menor
S. Padrão fracionário

2. Onde a ação ocone em Java 6. Or, perante o tribunal 7. A posição certa 9. A origem de uma bifurcação 12. Aumenta uma ArrayList 13. Muito extenso 14. Cópia do valor 16. Não é um objeto 17. Uma matriz aperfeiçoada 19. Extensão

8. A maior unidade da biblioteca
lO. Deve ter bai xa densidade

11. Está aí em algum lugar 15. Como se 18. O que ~ o mpras e matrizes têm em comum 20. Acrônimo da biblioteca 25. Método da escassez 26. O que gira

·r

21. Termo correlato ao do item 19 22. Petiscos espanhóis dos nerds. (Nota: isso não tem nada a ver com Java. ) 23. Para dedos preguiçosos 24. Onde os pacotes dom inam
_ _ _ ls q '\\l.IJV
- - 1l1lln

r

Mais dicas:

-

SIÇJl(up.dsd SOA lll.lodu - CAll [ B lu m ()~:'iB I;JJ 1lI0 j O~N ZlJ )Il lll

'l l ' Il

BP

O ~S lI ;J1 X 3

cp ;lJqlU;J'l ' Çl

UIIlUI O:J OA IIl llll.ld o dl.L '9 1 Isq'\CJ.lV cp ~jqlU;J'l . L i,OlSod ;l.Iqos J;JS ;Jp oel

OpU;;'ZUj !'IS;J ;) 13 '8 1

_ __ _ _----""'Ac.'.l O il~IUl l.ld '0 I W ISi[ '\\l.I.I V a p ;;'S-;).Iqlll;J'l

'v
T

;;.nb O 'l

. r

soelll

8

'l

... -----~.;:

você pstá aqui

lo-

121

soluções cios eXercícios

dos

Exercír.in~

____
public class ArrayListMagnet public static void main (String[] args)

ArrayList<String> a = new ArrayList<String>(); a.add(Q, "zero"); a.add(1, "one"); a . add (2, "two" ) ; a.add(3, "three"); printAL la) ;

I l

i

if

(a.containsl"three")) a.add("four");

'1 a. remove (2) ;
printAL(a); if
~

________________~
!= 4)

la.indexOfl"four ") a . add I 4 , "4. 2 " ) ;

(

printAL la) ; ii la.contains("two")) a . add I "2 .2" ) ;

/--:-~-~
void printALIArrayList<String> aI) eIement : aI) (
");

,

,,1 :i
/'""'-

..t

System.out.printlelement + "
}

System.out.printlnl"

O);

Respostas das Cruzadas Java

ponte seu: lápis
~_

1,'. •

Escreva seu PRÓpRIO conjunto de pistas I Examine ~c cada palavra e tente escrever suas próprias pistas. _.,. Tente torná-Ias mais fáceis, mais difíceis ou mais técnicas do que as já mostradas.

Horizontais
l. 6. 7.
9. 12. 13. 14.
/6.

Verticais
2.

3. 4.

5. 8.
10.

lJ.
JS. 16. /8. 20. 21.

/7.
19.

21.
22.

23.
24.

122

7 herança e

Melhor Viver em Objetópolis

Planeje seus programas com o futuro em mente. Se
houvesse uma maneira de escrever código Java de tal modo que se pudesse tirar mais férias, o quanto isso seria bom para você? E se pudesse escrever códigos que outra pessoa conseguisse estender facilmente? E se pudesse escrever códigos que fossem flexíveis, para aquelas irritantes alterações de último minuto nas especificações, isso seria algo no qual estaria interessado? Então este é seu dia de sorte. Por apenas três pagamentos facilitados de 60 minutos, você poderá ter tudo isso. Quando chegar ao Planejamento do Polimorfismo, você aprenderá as 5 etapas para a obtenção de um projeto de classes mais adequado, os 3 truques do polimorfismo, as 8 maneiras de criar um código flexível e, se agir agora uma lição bônus sobre as 4 dicas para a exploração da herança . Não demore, uma oferta dessa grandeza lhe fornecerá a liberdade para projetar e a flexibilidade para programar que você merece. É rápido, é fácil e já está disponível. Comece hoje e forneceremos um nível extra de abstração! ------ --- ------- - ---

123

o poder da herança

A guerra das cadeiras __ -- - --... ._-_. revisitada --._Lembra-se do Capítulo 4, quando Larry (o profissional dos procedimentos) e Brad (o sujeito da 00) estavam competindo pela cadeira Aeroll? Vejamos alguns trechos dessa história para examinarmos os aspectos básicos da herança.
Larry: Você tem código duplicado! O procedimento de rotação aparece em todos os quatro itens Shape. É um projeto estúpido. Você tem que manter quatro "métodos" de rotação diferentes. Em que isso poderia ser bom ? Brad: Oh, acho que você não viu o projeto final. Deixe que eu lhe mostre como a herança da 00 funciona, Larry.

Square
ro tate () playSou nd ( )

Circle
r ot ate () playSound()

j,
r ]

Triangle
rotate () playSound ( )

J

~

Amoeba
rot ate () playSound ( )

j

] .

t ~

Procurei o que O quatro classes

as

tinham em comum.
r
r-...

~ Elas são formas e todas giram e reproduzem som. Portanto Portanto extrai os recursos comuns e os inseri em uma nova classe chamada Shape.

Shape
rotate () playSound ( )

Vo cê pode ler i sso como "Square herda de Shape", "Circle herda de Shape" e assim por diante. Removi r otate( ) e playSound( ) das outras f ormas, portanto agora há apenas uma cópia a manter. Diz -s e que a clas se Shape é a superclasse das outras quatro classes. As outras quatro são as subclasses de Shape. As subclasses herdam os métodos da superclasse. Em outras palavras, se a classe Shape tiver uma funcionalidade, então, as subclasses automaticamente terão essa mesma funcionalidade.

Superclasse

Shape

Em seguida, vinculei as outras quatro classes de formas a nova classe Shape, em um relaci onamento chamado herança.

/".

.j

.

r---. \
~,

•. J

Square

E quanto ao método rotate( ) de Amoeba?
Larry: Não é esse o problema aqui - que a forma de ameba tinha um procedimento de rotação e reprodução de som totalmente diferentes? Como a ameba pode fazer algo diferente se ela herda sua funcionalidade da classe Shape? Brad: Essa é a última etapa. A classe Amoeba sobrepõe os métodos da classe Shape. Portanto, no tempo de execução, a JVM saberá exatamente que método rotate( ) executar quando alguém so licitar que o objeto Amoeba gire.

~ Fiz com que a classe Amoeba

Shape

Superclasse (mais abstrata)

sobrepusesse os métodos rotate( ) e playSound( ) da superclasse Shape. Sobrepor significa apenas que uma subclasse redefinirá um de seus métodos herdados quando precisar alterar ou estender o comportamento desse método .

Square
rotate( ) Il código de rotação Ilespec ífic o da ameba playSound ( ) Il código de reprodução de som I/espec i.fico da ameba

Métodos de sobreposição

Subclasses (mais específicas)

herança e polimorfisrno

,
h

o
Entendendo a herança

poder do cérebro

Como você representaria um gato doméstico e um tigre, em uma estrutura de herança? Um gato doméstico seria a versão especializada de um tigre? Qual seria a subclasse e quem seria a superclasse? Ou os dois são subclasses de alguma outra classe?

~
I
'''-'''

Como você projetaria uma estrutura de herança? Que métodos seriam sobrepostos? Pense nisso. Antes de continuar lendo.

Quando você projetar usando herança, inserirá código comum em uma classe e, em seguida, informará a outras classes mais específicas que a classe comum (mais abstrata) é sua superclasse. Quando uma classe herda de outra, a subclasse herda da superclasse. Em Java, dizemos que a subclasse estende a superclasse. Um relacionamento de herança significa que a subclasse herdará os membros da supercl asse. Com o termo "membros de uma classe" queremos nos referir às variáveis de instância e métodos. Por exemplo, se HomemPantera for uma subclasse de SuperHerói , a classe HomemPantera herdará automaticamente as variáveis de instância e métodos comuns a todos os super-heróis inclusive roupa, malha, poderEspecial, usarPoderEspecial() e assim por diante. Mas a subclasse HomemPantera poderá adicionar novos métodos e variáveis de instância exclusivos e sobrepor os métodos que herdar da superclasse SuperHerói. SuperHerói
Superclasse (mais abstrata)'-:) roupa malha poderEspecial usarPoderEspecial(
)

variáveis de instância

(estado, atributos)

métodos (comportamento)

subclasses (mais especificas)

usarPoderEspecial( colocarRoupa( )

métodos de ~ sobreposição

O HomemOvoFrito não precisa de nenhum comportamento que seja exclusivo, portanto ele não sobrepõe nenhum método. Os métodos e variáveis de instância de SuperHerói são suficientes. No entanto, o HomemPantera apresenta requisitos específicos quanto à roupa e aos poderes especiais, portanto usarPoderEspecial( ) e colocarRoupa( ) são sobrepostos na classe HomemPantera. As variáveis de instância não são sobrepostas porque não precisam ser. Elas não definem nenhum comportamento especial, logo, uma subclasse pode fornecer a uma variável de instância herdada o valor que quiser. O HomemPantera pode configurar a malha que herdou com roxo, enquanto o HomemOvoFrito configurará a sua com branco.

você está aqui ~

125

a maneira como a herança funciona

Um exemplo de herança
public class Doctor ( boolean worksAtHospital; void treatPatient( ) II faz um check-up

.. _---

-

- ~~~~~~~~~~~~-

publi c class Fa mi l yDoctor ext e nds Docto r boolean makesHou seCal l s; void giveAdv ic e () ( II dá conselhos

public class Su r geon extends 'Doctor{ void treatPatient() ( II executa cirurgia

void makelncision () ( II faz incisão (eca ! )

superclasse

;:1
uma variáv el de instânci a

Doctor
worksAtHospita l treatPatient(
)

": r::,"i~'
-/-

"'~,: .

-,

sUbcla~
Surgeon
Sobrepõe o método treatPatient( ) herdado Adiciona um novo método treatPatient( makelncision(
) )

.... ,

1

~ FamilyDoctor
makesHouseCalls giveAdvice(

1

um método

,

Ad ici ona uma nova variáve l de instância Adiciona um novo método

._-

)

Quantas vari áveis de instância tem Surgeon ? Quantas vari áveis de instância tem Famil yDoctor? Quantos métodos tem Doctor? Quantos métodos tem Surgeon ? Quantos métodos tem FamilyDoctor? Uma classe FamiJ yDoctor pode usar o método treatPati ent( )? Um a cl asse Famil y Doctor pode usar o método makelnc ision( )?

~ 26

__ ~apítuío 7

herança e polimorfismo

h

h
I"

Projetemos a árvore de herança de um programa de simulação de animais
Suponhamos que você fosse solicitado a projetar um programa de simulação que permitisse ao usuário reunir vários animai s diferentes e m um ambiente para ver o que acontece. Não temos que codificá-lo agora, estamos mais interessados no projeto. Recebemos uma lista com alguns dos animais que estarão no programa, mas não todos. Sabemos que cada anima! será representado por um objeto e que os objetos se moverão dentro de um ambiente, fazendo o que cada tipo específico for programado para fazer.

E queremos que outros programadores possam adicionar novos tipos de animais ao programa a qualquer momento.
I
I V'""'

í........

Primeiro temos que descobrir as características comuns abstratas que todos os animais apresentam e inseri-Ias dentro de uma classe que todas as classes de animais possam estender.
~procure objetos que possuam atributos e comportamentos em comum.

1-'"'
I 'r,

o que esses seis tipos têm em comum? Isso o ajudará a abstrair os
comportamentos (etapa 2) . Como ess es tipos estão rel acionados? Is so o ajudará a definir os relacionamentos da árvo re de heran ça (etapas 4-5)

t.r--.
I

I
I

I ........

I

i

I

1----'

i..-..

II
1

Ir'"

Usando a herança para evitar a duplicação de código em subclasses
Temos cinco variáveis de instância:

~projete uma classe que represente o estado e

o comportamento comuns. Esses objetos são todos anima is, portanto criaremos uma superclas se comum chamada Animal. Inseriremos métodos e variáveis de instância que todos os animais podem precisar.

picture - O nome do arquivo que representa a figura
JPEG desse animal

ir

I~
I r-

food -o tipo de alimento que esse animal come. No momento, só podemos ter dois valores: meat ou grasso hunger -um inteiro que representa o nível de fome do
animal. Sua alteração depende de quando (e quanto) o animal come.

Animal
picture food hunger boundaries location makeNoise ( eat ( ) sleep ( ) roam( )

1 '"

I"

boundaries - valores que representam a altura e largura
do 'espaço' (por exemplo, 640 X 480) em que os animais circularão.

location - as coordenadas X e Y de onde o animal se
encontra no espaço. Temos quatro métodos:

Ir'
1 °

Ir

makeNoise( ) - comportamento para quando o
tiver que fazer algum ruído.

I~

eat( ) - comportamento para quando o animal
encontrar sua fonte de comida preferida, carne (rneat) ou capim (grass).

E
. ;;=.:::'

sleep( ) - comportamento para quando considerarmos o
animal sonolento.

roam( ) - comportamento para quando o animal não esti v·er cOllimdo uu-dornThTdLJ(IJfÜ vé:tvetfne"'l""e"'ec;7~" l L" L,"lr""Ú-----­

apenas circulando até encontrar uma fonte de alimento ou chegar ao limite do espaço) .

-

você está aqui,.

127

-. ~

projetando a heranç2

Todos os animais comem

rl~ mp.sm~ mrmp.i r~? _

Suponhamos que concordássemos com uma coisa: as variáveis de instância de todos os tipos de animais serão iguais. Um leão terá seu próprio valor para a figura , comi da (estamos pensando em carne), fome, limi tes e local. Um hipopótamo terá valores diferentes para suas variáveis de in stância, mas ele ainda terá as mesmas vari áveis que os outros tipos de anim ais tiverem. O mesmo ocorrerá com o cão, o tigre e ass im por diante. Mas e quanto ao comportamento?

Que métodos devemos sobrepor?
Um leão faz o mesmo ruído de um cão? Um gato come como um hipopótamo? Talvez em sua versão, mas, na nossa, comer e fazer ruídos são específicos do tipo de animal. Não sabemos como codificar esses métodos de uma maneira que eles sejam adequados a qualquer a{limal. Certo, isso não é verdade. Poderíamos escrever o método makeNoise( ), por exemplo, de um modo que tudo que teria que fazer seria reproduzir um arquivo de som definido em uma variável de instância desse tipo, mas isso não seria muito especializado. Alguns animais podem fazer ruídos diferentes em situações distintas (como um ruído para comer e outro quando ele salta sobre um inimigo, etc.). Portanto exatamente como a Ameba sobrepôs o método rotate( ) da cl asse Shape, para ter um comportamento mais específico (em outras palavras, exclusivo), teremos que fazer o mesmo em nossas subclasses de Animal.
Defina se uma subclasse precisa de comportamentos (implementações de métodos) que sejam especificos desse tipo de subclasse em particular.

Animal
picture food hunger boundaries location

Examinando a classe Animal, definimos que eat( ) e makeNoise ( ) devem ser sobrepostos pelas subclasses

Melhor sobrepormos esses dois métodos, eat( ) e makeNoise( Js para que cada tipo àe animal possa definir seu próprio ~ comportamento específico ao comer e fazer ruidoso Por enquanto, parece que sleep ( } e roam ( J pode.m permaneoer genéricos.

r oam ( )

Procurando mais oportunidades de usar a herança
A hierarquia de classes está começando a se compor. Cada classe está sobrepondo os métodos makeNoise( ) e eat( ), para que não haj a confusão entre o latido de um cão e o miado de um gato (o que seria um insulto para os doi s grupos). E um hipopótamo não comerá como um leão. Mas talvez possamos fazer mai s. Temos que examinar as subclasses de Animal e ver se duas ou mais podem ser agrupadas de alguma maneira, recebendo um código que seja comum apenas a esse novo grupo. o lobo e o cão apresentam semelhanças. Assim como o leão, o tigre e o gato.

Animal
picture food hunger boundaries location
Hmmm.., S!!!rá que

cc.

Procure mais oportunidades de usar a abstração, encontrando duas ou mais subclasses que possam ter um comportamento em comum .

LioXl r

Tiger

e

Cat tém a1.go em

makeNoise( eat( ) sleep ( )

Examinamos nossas classes e vimos que Wo lf e Dog podem ter algum comportamento em comum, o mesmo ocorrendo com Lion, Tiger e Cat o

Wolf e Dog sec animais caninos ... Talvez haja algo que as DUAS classes pudessem usar.~.

128 capitulo 7

F

~~

__ o

herança e polimorfisÍ'lo

~ Termine a hierarquia de classes
Como os animais já têm uma hierarquia organizacional (a divisão em reino, gênero e família), podemos usar o nível que fizer mais sentido ao projeto das class es . Usaremos as "famílias" b i ológicas para organizar os animais , cr iando uma classe Feline e uma cla sse Can ine. Decidimos que a classe dos caninos poderia usar um métodos roam ( ) em comum, porque eles tendem a se mover em grupos . Também vimos que os felinos poderiam usar um método roam ( ) em comum, porque tendem a evitar outros de seu próprio tipo. Deixaremos que a classe Hippo continue a us ar seu método roam ( ) herdado - o método genérico que ela herdou de Animal . Terminamos o proj eto por enquanto, mas voltaremos a ele posteriormente neste capítulo .

Animal
picture food ' hunger boundaries location makeNoise( eat ( )

!~
I

I

~

.

"
makeNo is e( eat ( )

makeNois e ( eat ( )

makeNoise( eat( )

Que método será chamado?

makeNois e ( eat ( )

A classe Wolf tem quatro métodos. Um herdado de Animal, um herdado de Canine (que na verdade é a versão sobreposta de um método da classe Animal) e dois sobrepostos pela própria classe Wolf. Quando você criar um objeto Wolf e atribuí-lo a uma variável, poderá usar o operador ponto nessa variável de referência para chamar todos os quatro métodos. Mas que versão desses métodos será chamada? Animal
~-

cria

lli~

novo objeto Wolf

Wolf w = new Wolf( w.makeNoise( w . roam( };
w. eat ( );

);

makeNois e ( eat ( ) sleep ( )

cna!na a versão de Wolf chama a versão de Caníne chama a versão de Wolf chama a versão de Animal

w. sleep (

"· ' à..
~r
':~ ~

makeNoise(

~e_a_t_(_)_ _..-11·! ...

li

"-

,",'o

:,. -

você está aqui

~

129

.-""

..
projeto prático de uma árvore de he"ança Quand o você chamar um método em uma referência de objeto, estará chamando a versão mais específica do método para esse tipo de objeto. . - . ----- . Em outras palavras, o inferior vence!
I:-

~

"Inferior" significando o mais baixo na árvore de herança. Canine é inferior a Animal e Wolf é inferior a Canine, portanto chamar um método na referência a um objeto Wo lf significa que a JVM examinará primeiro a classe Wolf. Se não encontrar uma versão do método nessa classe, começará a retroceder na hi erarqu ia de herança até achar algo que atenda.

Projetando uma árvore de herança
Classe
Roupas Short Camisa

Superclasse
-

Subclasse
Short, Camisa

superclasse (mais abstrata)

subclasses

Roupas Roupas
Tabela de herança Diagrama de classes da herança

Defina os relacionamentos que fazem sentido. Preencha as duas últimas colunas.

Classe
Músico Cantor de rock Fã Baixista Pianista clássico

Superclasse

Subclasse

Desenhe um digrama de herança aqui .

Dica: nem todas as classes p odem ser conectadas a alguma outra classe. Dica: você pode aumentar ou alterar as classes listadas.

Não existem

Você disse que a JVM iniciará subindo a árvore de herança. a partir do tipo de classe em que o método foi chamado (como no exemplo de Wolf na página anterior). Mas o que acontecerá se ela não conseguir encontrar algo correspondente?
Boa pergunta! Mas você não tem que se preocupar com isso. O compilador garante que um método específico possa ser chamado para um determinado tipo de referência, mas não informa (ou verifica) a classe de onde esse método veio realmente no tempo de execução. No exemplo de Wolf, o compilador procurará um método sleep( ), mas não se importará com o fato de ele ter sido definido (e herdado) na classe Animal. Lembre-se de que, se uma classe herdar um método, ela terá o método. Onde o método herdado foi definido (em outras palavras, em que superclasse ele foi definido) não faz diferença para o compilador. Mas no tempo de execução, a JVM sempre usará o método correto. E por correto queremos dizer a versão mais específica desse objeto em particular.

P:

Perguntas Idiotas

R:

Usando É-UM e TEM-UM
Lembre-se de que, quando uma classe herda de outras, dizemos que a subclasse estende a supercl asse. Quando você qui ser saber se uma coisa deve estender outra, aplique o teste É-UM. O triângulo É- UMA Forma, sim , isso faz sentido. O Gato é É-UM Felino, isso também faz sentido 130
capítu~o J

herança

o Cirurgião É-UM Médico, continua fazendo sentido
Banheira estende Banheiro, soa sensato.

Até você aplicar o teste É-UM.
Para saber se você projetou seus tipos corretamente, pergunte "Faz sentido dizer X É-UM tipo Y?". Se não fizer, você saberá que algo está errado no projeto, portanto, se aplicarmos o teste É-UM, Banheira ÉUM Banheiro é definitivamente falso. E se invertermos para Banheiro estende Banheira? Isso ainda não faz sentido, Banheiro É-UMA Banheira não funciona. Banheira e Banheiro estão relacionados, mas não através da herança. Estão associados por um relacionamento TEM-UM. Faz sentido dizermos "O Banheiro TEM-UMA Banheira?". Se fizer, isso significa que Banheiro (Bathroom) tem uma variável de instância Banheira (Tub). Em outras palavras, Bathroom tem uma referência a Tub, mas não estende Tub e vice-versa.
'""""'

Faz sentido dizer Uma Banheira É-UM Banheiro? Ou um Banheiro É-UMA Banheira? Bem, para mim não. O relacionamento entre minha Banheira e meu Banheiro é do tipo TEM-UM. O Banheiro TEM-UMA Banheira. Isso significa que Bathroom tem uma variável de instância Tub.

o

Banheira Banheiro
,.......,

,
Bubbles
int radius; int colorArnt;

I'!
.,
I~

int size Bubbles b;
~ "

! i
'f'

Tub bathtub; h Sink theSink;

Bathroom TEM-UMA variáve1 de instancia Tub e Tub TEM-UMA variável Bubbles. Mas ninguém herda (estende) nada de ninguém.

". !

l,

I '"

Mas espere! Há mais!
O teste É-UM funciona em qualquer local da árvore de herança. Se sua árvore de herança tiver sido bem projetada, o teste É-UM deve fazer sentido quando você perguntar a qualquer subclasse se ela É-UM de seus supertipos.

I ~

~~r

I:
I"

Se a classe 8 estende a classe A, ela É-UMA classe A. Isso será verdadeiro em qualquer local da árvore de herança. Se a classe C estender a classe 8, ela passará no teste É-UM tanto com a classe 8 quanto com a classe A.
Em uma árvore de herança como a mostrada aqui, você sempre poderá dizer "Wolf estende Animal" ou "O Lobo É-UM Animal". Não faz diferença se Animal é a superclasse da superclasse de Wolf. Na verdade, contanto que Animal esteja em algum local da hierarquia de herança acima de Wolf, Lobo É-UM Animal sempre será verdadeiro. A estrutura da árvore de herança de Animal mostra claramente que: "o Lobo É-UM Canino, portanto pode fazer qualquer coisa que um Canino faria. E o Lobo É-UM Animal, logo, pode fazer qualquer coisa que um Animal faria." Não faz diferença se Wolf sobrepõe alguns dos métodos de Animal ou Canine. No escopo geral (dos códigos), vVolf pode executar esses quatro métodos. Com.o os executa ou em qlle classe eles sc70 sobrepostos não faz diferençã~ Wolf pode executar makeNoise( ), eat( ), sleep( ) e roam( ) porque estende a classe Animai.
\laCE;

Animal
Canille est$ude 2L"1imal

Wolf estende Canine Wolf estende Animal

makeNoise( eat ( ) sleep ( ) roam( )

o

Canino :IÉ-UM .>,:n.imal

o Lobo É-Ul<l Canino

131

;::ou:

explorando o poder dos objetos

Como saber se

VOC P -CODstn Üll

SLJaheranca corretamente?--~

-

•..

- ~------- ~-

É claro que há mais coisas envolvidas do que o que foi abordado até agora, mas examinaremos outras questões referentes à 00 no próximo capítulo (onde acabaremos detalhando e aperfeiçoando parte do projeto que construímos neste capítulo). Por enquanto, porém, uma boa diretriz é usar o teste É-UM. Se "X É-UM Y" fizer sentido, é provável que as duas classes (X e Y) ~ residam na mesma hierarquia de herança. Há chances de terem comportamentos iguais ou sobrepostos.

Lembre-se de que o relacionamento É-UM da herança funciona somente em uma direção!

o Triângulo É-UMA Forma faz sentido, portanto Triângulo pode estender Forma.
Mas o inverso - a Forma É-UM Triângulo - não faz sentido, portanto portanto a Forma não deve estender o Triângulo. Lembre-se de que o relacionamento É-UM impliça que, se X É-UM Y, logo, X pode fazer qualquer coisa que Y faria (e possivelmente mais).

Aponte seu lápis
~

Insira uma marca de seleção ao lado dos relacionamentos que fazem sentido.

D
D D D D D D D D D

Forno estende Cozinha Guitarra estende Instrumento Pessoa estende Funcionário Ferrari estende Motor Ovo·Frito estende Alimento Beagle estende AnimalEstimação Contêiner estende Jarro Metal estende Titânio GratefulDead estende Banda Loura estende Inteligente Bebida estende Martini Dica : aplique o teste É-UM

D
Não existem

Perguntas Idiotas
Vimos como uma subclasse faz para herdar um método da superclasse, mas e se a superclasse usar a versão do método da subclasse?

Uma superclasse não conhece necessariamente todas suas subclasses. Você pode criar uma classe e tempo depois outra pessoa pode estendê-Ia . Mas mesmo se o criador da superclasse não conhecer (e quiser usar) a versão de um método da subclasse, não existe algo do tipo herança inversa ou regressiva. Pense bem , as crianças herdam dos pais e não o contrário.

P: R: P:

qUiSe~

muit~

Em uma subclasse, digamos que eu quisesse usar um método tanto com a versão da superclasse quanto com minha versão de sobreposição existente na subclasse? Em outras palavras, não quero substituir totalmente a versão da superclasse, apenas adicionar algo mais a ela.

.

".

Você pode fazer isso! E é um recurso importante do projeto. Pense na palavra "estende" significando "quero ---estender a funciona lidade da superclasse" .
. 132 capitulo 7·

R:

herança e pOlimorfismo
public vo id roam( ) ( .. _--super . roam() ; ~ II meu própri o método roam (------------ retorna à execução de codigo especifico da subclasse

---_

Você pode atribuir os métodos de sua superclasse de uma maneira que eles contenham implementações de métodos que funcionarão para qualquer subclasse, mesmo se as subclasses tiverem que 'adicionar' mais código. No método de sobreposição de sua subclasse, você pode chamar a versão da superclasse usando a palavra-chave super. É como dizer "primeiro execute a versão da superclasse e, em seguida, volte e termine com meu próprio código ...".

Quem fica com o Porsche e quem fica com a porcelana?
(como saber o que uma subclasse pode herdar de sua superclasse)
Uma subclasse herda membros da superclasse. Os membros incluem as variáveis de instância e métodos, porém mais adiante neste livro examinarmos outros membros herdados. Uma superclasse pode selecionar se quer ou não que uma subclasse herde um membro específico pelo nível de acesso que esse membro receber. ·Há quatro níveis de acesso que abordaremos neste livro. Indo do maior ao menor nível de restrição, os quatro níveis de acesso são:

privado

- .. - padrão

-"

protegido --

público

Os níveis de acesso controlam quem vê o quê, e são essenciais a um código Java robusto e bem-projetado. Por enquanto enfocaremos apenas os acessos público e privado. As regras desses dois são simples:

membros públicos são herdados membros privados não são herdados

':r

Quando uma subclasse herda um membro, é como se ela própria o definisse . No exemplo de Shape, Square herdou os métodos rotate( ) e playSound( ) e para o ambiente externo (outros códigos) essa classe simplesmente possui os doi s métodos . . Os membros de uma classe incluem as variáveis e métodos definidos na classe mais qualquer coisa herdada de uma superclasse.
Nota: veja mais detalhes sobre os acessos padrão e protegido no Capitulo 16 (implantação) e
no }l.pêndice E.

=r ,-..
. -~

Ao projetar empregando a herança, você está usando ou abusando?
. Já que algumas das razões para a existência dessas regras só serão reveladas posteriormente neste livro, por enquanto, . Simplesmente conhecer algumas regras o ajudará a construir um projeto de herança mais adequado . USE a herança quando uma classe for o tipo mais específico de uma superclasse. Exemplo: Salgueiro é um tipo mais específico de Árvore, portanto Salgueiro estender Árvore faz sentido. CONSIDERE a herança quando tiver um comportarnento (código implementado) que deva ser compartilhado entre várias classes do mesmo tipo geral. Exemplo: Square. Circle e Triangle precisam girar e reproduzir SO I11, portanto inserir essa funcionalidade em uma superclasse Shape pode fazer sentido e proporcionará mais facilidade na manutenção e extensibilidade. Lembre-se, no entanto, de que, embora a herança seja um dos recursos-chave da programação orientada a objetos, não é necessariamente a melhor maneira de conseguirmos reutilizar comportamentos. Ela lhe ajudará a começar, e geralmente é a melhor opção de projeto, mas os padrões de projeto o ajudarão a conhecer outras opções mais sutis e flexíveis. Caso não conheça os padrões de projeto, um bom acompanhamento a este ljvro seria Use a Cabeça I Design Patterns. NÃO use a herança apenas para poder reutili zar o código de outra classe, se o relacionamento entre a supercl asse e a subclasse violar uma das duas regras acima_ Por exemplo. suponhamos que você escrevesse um código especial de impressão na classe Alarme e agora tivesse que imprimir o código da classe Piano, portanto precisaria que Piano estendesse Alarme para que herdasse o código de impressão. Isso não faz sentido' Um Piano não é um tipo mai s específico de Alarme. (Logo , o código de exibição deveria estar em uma classe Impressora. da qual todos os objetos imprimíve is pudessem se beneficiar através de um relacionam ento TE~l.JM . ) .- ~ ____ . __ _

.{

Não use a herança se a subclasse c a superclasse não pas sarem no teste É-UM . Pergunte sempre se a subc lasse É-UM tipo mais específico da superclasse . Exemplo: Chá É-UMA Bebida faz sentido. Bebida É-UM Chá não.

você está aqui >-

133

,---..

explorando o poder dos objetos

--~ ._--_. - -

.--- - -- - - - --

,...--- DISCRIMINAÇÃO DOS PONTOS
- A subclasse estende a superclasse. - Uma subclasse herda todas as variáveis de instância e métodos públicos da superclasse, mas não suas variáveis de instância e métodos privados. - Os métodos herdados podem ser sobrepostos; as variáveis de instância não (embora possam ser redefin.idas na subclasse, mas isso não é a mesma coisa, e quase nunca é preciso fazê-lo). - Use o teste É-UM para verificar se sua hierarquia de herança é válida. Se X estende Y, então, X É-UM Y deve fazer sentido. - O relacionamento É-UM funciona em uma única direção. Um hipopótamo é uma animal, mas nem todos os animais são hipopótamos. - Quando um método é sobreposto em uma subclasse e é chamado em uma instância dela, a versão sobreposta do método é que é chamada. (O inferior vence.) - Se a classe B estende A e C estende B, a classe B É-UMA classe A e a classe C É-UMA classe B, portanto a classe C também É-UMA classe A.

Mas o que toda essa herança lhe proporcionará?
Você se beneficiará muito da 00 projetando com a herança. Poderá eliminar código duplicado generalizando o comportamento comum a um grupo de classes e inserindo esse código em uma superclasse. Assim, quando precisar alterá-lo, terá apenas um local a atualizar, e a alteração repercutirá instantaneamente em todas as classes que herdarem esse comportamento. Bem, não se trata de mágica, na verdade é muito simples: faça a alteração e compile a classe novamente. Apenas isso. Você não terá que mexer nas subclasses!

Basta distribuir a superclasse recém-alterada, e todas as classes que a estenderem usarão automaticamente a nova versão.
Um programa Java nada mais é do que uma pilha de classes, portanto as subclasses não precisam ser recompiladas para usar a nova versão da superclasse. Contanto que a superclasse não trave nada na subclasse, tudo estará bem. (Discutiremos o que a palavra ' travar ' significa nesse contexto posteriormente no livro. Por enquanto, pense nela como a modificadora de algo na superclasse de que a subclasse dependa, como os argumentos ou o tipo de retorno de um método específico ou o nome do método, etc.)

CD você

evitará código duplicado.
local e deixe as subclasses superclasse. Quando quiser SÓ precisará fa zê -lo em um todas as subclasses) ficará

Insira o cód i go comum em um herdarem esse CÓdigo de uma alterar esse comportamento, local e todo mundo (is to é, sabendo da alteração.

Q)você definirá um protocolo comum para um grupo de classes.

A herança lhe permitirá garantir que todas as classes agrupadas sob um certo supertipo tenham todos os métodos que o supertipo tem. *
Em outras palavras , você definirá um protoco lo comum para um conjunto de classes J 'elacionadas através da herança. Quando você definir métodos em uma superclasse, que possam ser herdados por subclasses, estará anunc. ando um tipo de protocolo para outros códigos que diz "todos os meus i subtipos (isto é, as subclasses) poderão fazer essas coisas, C0111 esses métodos que têm essa assi na tu ra .. ." Em outras pal avras. você estabe lecerá um contrato.
134

càpiüt!o 7

.--. ~

~

Jk

[ "1f~ .".'-'
.herança e polimorfismo

),-,.-

A classe Animal estabelece um protocolo comum para todos os seus subtipos:
Animal
fazerRuído( comer ( ) dormir ( ) circular (
l'i

I~

I"j

'.1

Você está dizendo para o resto do mundo queÇlU~~~~!: anima l pode fa.zer essa.s quatro coisas. Isso incluí os argumentos e tipos de retorno do método .

E lembre-se de que, quando dizemos qualquer animal, estamos nos referindo à classe Animal e qualquer outra classe que a estenda, O que significa também, qualquer classe que tenha a classe Animal em algum local acima dela na hierarquia de herança. Mas ainda nem chegamos na parte realmente interessante, porque deixamos o melhor - o polimOlfismo - por último. Quando você definir um supertipo para um grupo de classes, qualquer subclasse desse supertipo poderá ser substituída onde o supertipo for esperado. Como é mesmo? Não se preocupe, ainda não acabamos de explicar. Após avançarmos duas páginas, você será um especialista.
*Quando dizemos "todos os métodos" estamos nos referindo a "todos os métodos que podem ser herdados", o que por enquanto significa "todos os métodos públicos", porém essa definição será melhorada posteriormente.

E me preocupo porque...
Porque você se beneficiará do polimorfismo.

o que importa

para mim porque ...

Porque você poderá chamar o objeto de uma subclasse usando uma referência declarada como o supertipo.

E isso significa para mim que...
Você poderá escrever códigos realmente flexíveis. Códigos que serão mais claros (mais eficientes e simples). Códigos que não serão apenas mais fáceis de desenvolver, mas também muito mais fáceis de estender, de maneiras que você nunca imaginou no momento em que originalmente os escreveu. Isso significa que você poderá tirar aquelas férias tropicais enquanto seus colaboradores atualizam o programa e talvez eles nem precisem de seu código-fonte. Você verá como isso funciona logo abaixo. Não o conhecemos, mas pessoalmente, achamos as férias tropicais particularmente
motivadoras ~

Para ver como o polimorfismo funciona, temos que voltar para examinar a maneira como normalmente declaramos uma referência e criamos um objeto...
As 3 etapas de declaração e atribuição de objetos

1 ,---'----.. . ,\

---~/'"

2 ' 3 ~ - . . -~ -./", - ,. . ...-.. \

Dog myDog = new Dog()i

"Declare uma variável de referência Dog myDog
= new Dog ( );
7

n -----

Sol-tc.L-taa JvlY1 paL~dT espaçu !:->c:LL a U.lUCl variá vc::l J.ç ..."-e; f2:r- Gu'--..:.. . . . . Z'". variável de refer ênc ia será sempre do tipo Dog . Em .outras palavras, um controle remot o que tenha botões que controlem um objeto Dog, ma s não um ob jeto Car, Bu ttton ou Socket .

Dog

você está aqui

~

135

como o polimorfismo funciona

Et Crie

um objeto
----------------------------------------------------------------------~------~.---

Dog myDog =

new Dog ( );
objeto Dog

Solicita à JVM para alocar espaço pa ra um novo objeto Dog na pilha de lixo coletável.

EtVincule
Dog myDog

O

objeto e a referência
new Dog( );

------)

Atribui o novo objeto Dog à var iável de refer ência myDog . Em outras p alavras, programa o controle remoto.

Dog

objeto Dog

que o tipo da referência E o tipo do objeto sejam iguais. Nesse exemplo, os dois são do tipo Oog.
Dog

o importante é

Esses tipos são iguais . O variável de refer ência foi declarado como Dog e o objeto foi criado como novo objeto Dog( ).

d~S

tiP~da

~ .•

Mas com o polimorfismo, a referência e o objeto podem ser diferentes.
Animal myDog = new Dog( );

Esses dois NÃO ' são tipos iguais. O tipo da variável de referên cia foi declarado como ~~~~!, mas o objeto foi declarado como nov o objeto Dog( ) .

\

1

No polimorfismo, o tipo da referência pode ser uma superclasse com o tipo do objeto real.
Quando você declarar uma variável de referência, qualquer objeto que passar no teste É-UM quanto ao tipo declarado para ela poderá ser atribuído a essa referência. Em outras palavras, qualquer coisa que estender o tipo declarado para a variável de referência poderá ser atribuída a ela. Isso permitirá que você faça coisas como criar matrizes polimórficas.

Certo, talvez um exemplo ajude.
Animal[) animals animals animals animals animals for animals = new Animal [ 5);
[O)
[ 1)

(----------------

De c lara uma matriz d e ti po Animal . Em ou tra s p al avras, uma matriz que conterá obj etos de tipo Animal .
Mas olbe o que você pode fazer .•. Pod e inser ir QUALQUER s ubc l a sse de Animal na matri z Animal!

[2)
[3 ] [4)
=

new new new new new O; i

Cat () ; Wolf (); Hippo (); Lion ();
<

~g{) ~

(

( i nt i

animals .l e ng th ; i++)

{

(o objet i vo ão exemplo ): voc ê pode percorrer a lna t r .í.:z e chamar um dos :métodos d a c lasse Animal ~ e todos os objetos s e comport:arii.o da forma c orretai
Quando

E aqui e s tá a mel h or parte do polimor f ismo

' i ' fez: igual a 0, um objeto Do g es ta.:rá no índice O da ma.tri z, portanto você acion ará o método eat( ) de Dog. Quando 'i' ror iqual a 1, você acionara o método e·at ( ) de Cat anima l s [i] . roam () ; ( - - - - - - - - - - - - - - -- ---------- C mesmo aconte;:ará CC-t"tl. =oa..m( ; ..

animals[i) . eat() ; ~(~-----------------------

136 capitul?- l,=-~c

.

herança e polimorfismo
;.,..-...,. -

!"
I

Mas espere! Há mais!
Você pode ter argumentos e tipos de retorno polimórficos.
Se você declarar a variável de referência de um supertipo, digamos, Animal, e atribuir um objeto da subclasse a ela, digamos, Dog, pense em como isso irá funC~'onar quando a _ referência for o argumento de um método.. .
class Vet { publ ic vo i d giveShot(An i mal a) { II faz coisas horríve i s com o animal na II out r a ex tremidade do pa r âmetro ' a ' a . make No i se() ;
'!.;: ;:: .

i"

I" I '"

c l as s PetOwner { publ i c void start( ) new Ve t( ); Vet v
( ~

parâmetro de Animal pode usar QUALQUER tipo de animal como argument o. Quando o veterinário tiver aplicado a injeção r o parâmetro solicitará a o ani:mal que façaRuidos( } e r independentemente do animal que estiver na pilba, seu método makeNoise( ) será exec utado.

o

o método giveShot( ) d e Vet pode u sar qualquer Dog d new Dog(); ________________________ objeto ?_~ima l que você fornecer para ele. Contanto Hi ppo h = new Hippo ( ) ; ( ______________________ que o objeto qJe voce passar como argumento seja uma subclasse de Animal, ele fun cionar á.
v.give Sho t (d);
( ~

___________________________

o o

método makeNo i s e ( método makeNoise(

d e Dog será e x ecut ado

v . g i v e Sho t (h); ( ______________________________

de Híppo será executado

AGORA entendi! Se eu escrever meu código usando argumentos polimórficos, onde declarar o parâmetro do método como um tipo da superclasse, poderei passar qualquer objeto da subclasse no tempo de execução. Interessante. Porque isso também significa que posso escrever meu código, tirar férias , e outra pessoa poderá adicionar novos tipos de subclasse ao programa sem que meus métodos deixem de funcionar ... (A única desvantagem é que estou torna ndo a vida mais fácil para aquele idiota do Jim .)

Com o polimorfismo, você pode escrever um código que não tenha que ser alterado quando novos tipos de subclasse foram introduzidos no programa.
Lembra da classe Vet? Se você criar essa classe usando argumentos declarados com o tipo Animal, seu código poderá manipular qualquer subclasse de Animal. Isso significa que, se outras pessoas quiserem se beneficiar de sua classe Vet, tudo que elas terão que fazer será se certificarem de que seus novos tipos estendam a classe Animal. Os métodos de Vet ainda funcionarão, ainda que essa classe tenha sido criada sem conhecer nenhum dos novos subtipos de Animal com que trabalhará.

--------. 0
poder do
cérebro
Por que podemos ter certeza de que o polimorfismo funcionará dessa maneira? Por que é sempre segure supor que GJ-t-HHfl-Hê-f tipg de su-hf:-!~~e terá os D1étodQS que 8.Ch8.ffiQS e st.~ r chamando no tipo da supere/asse (o tipo da referência da superclasse no qual estamos usando o operador ponto)? você está aqui ...

137

sobrepondo métodos

..----,

-

;

",I

N:ão _exist~m _ _

Perguntas Idiotas
Há algum limite prático quanto à criação de níveis de subclasses? Até onde podemos ir? Se você examinar o APl Java, verá que a maioria das hierarquias de herança é ampla horizontalmente, mas não verticalmente. A maioria não passa de um ou dois níveis verticais, embora haja exceções (principalmente nas classes de GUI). Você perceberá que geralmente faz mais sentido manter as árvores de herança achatadas, mas não se trata de um limite rígido (bem, não de um que você tenha que obedecer). Acabei de pensar em algo... Se você não tiver acesso ao código-fonte de uma classe, mas quiser alterar a maneira como um método dessa classe funciona, poderia usar subclasses para fazer isso? Para estender a classe "inválida" e sobrepor o método com seu próprio código aprimorado? Sim. Esse é um recurso interessante da 00 e às vezes evita a necessidade de reescrever a classe a partir do zero ou de procurar o programador que ocultou o código-fonte. Podemos estender qualquer classe? Ou é como ocorre com os membros que quando a classe é privada não é possível herdá-los... Não há classes privadas, exceto em um caso muito especial chamado classe interna, que ainda não examinamos. Mas há três coisas que podem impedir uma classe de gerar subclasses. A primeira é o controle de acesso. Ainda que uma classe não possa ser marcada com private, ela pode

P ·. R:

P:

não ser pública (o que i>_ corrE3_9uaJ2do nã.9_ q~~é1ramos a classe como public) . Uma classe não-pública pode gerar subclasses somente a partir de classes do mesmo pacote que ela. As classes de um pacote diferente não poderão criar subclasses (ou mesmo usar) da classe não-pública. A segunda coisa que impede uma classe de gerar subclasses é o modificador cuja palavra-chave é final. Uma classe final significa que ela está no fim da linha de herança. Ninguém, em hipótese alguma, pode estender uma classe final. O terceiro problema é que, se uma classe tiver somente construtores private (examinaremos os construtores no Capítulo 9), ela não poderá gerar subclasses. Qual o interesse em criar uma classe final? Qual a vantagem de impedir que uma classe gere subclasses? Normalmente, não marcamos nossas classes como finais. Mas se você precisar de segurança - a segurança de saber que os métodos sempre funcionarão da maneira que você os criou (por não poderem ser sobrepostos) -, uma classe final proporcionará isso. Várias classes do APl Java são finais por essa razão. A classe String , por exemplo, é final porque, bem , imagine a confusão se alguém alterasse a maneira como as Strings se comportam! Podemos fazer com que um método seja final, sem que a classe inteira tenha que ser? Se você quiser evitar que um método específico seja sobreposto, marque-o com o modificador final. Marque a c/asse inteira com final se quiser garantir que . nenhum dos métodos dessa classe seja sobreposto.
.

.;:j.'

~i

J r--I
~I ~r

rJ

P:

~ .

R:

R:

P:

R:

P: R:

Mantendo o contrato: regras para a sobreposição
Quando você sobrepuser o método de uma superclasse, estará concordando em obedecer o contrato. O contrato que diz, por exemplo, "não uso argumentos e retorno um booleano". Em outras palavras, os argumentos e tipos de retomo de seu método de sobreposição devem parecer para o ambiente externo exatamenfe como o método sobreposto da superclasse.


~

Appliance
boolean turnOn( boolean turnO ff( )

Os métodos são o contrato.
Para o polimorfismo ser eficaz, a versão de Toaster para o método sobreposto de Appliance tem que funcionar no tempo de execução. Lembre-se de que o compilador examinará o tipo da referência para decidir se você poderá chamar um método específico nela. No caso da referência ele Appliance a um objeto Toaster, o compilador só se preocupará em saber se a classe Appliance tem o método que você está chamando na referência. Mas no tempo de execução, a JVM não exam inará o tipo da referência (Appliance), mas o objeto Toaster real na pilha. Portanto, se o compil ador já tiver aprovado a chamada do método,
138 -capitulo 7 ~"occc.

Essa NÃo é uma s obreposição! Não podemos alterar os argumentos em um méto do de sobreposição!

Toaster
boolean turnOn(int level) Na verdade isso é uma
sob=eC1L~GA vá ! ~daT

E

não

uma sobrePOSIÇÂO.

:IR -:r

n
"1".....,

herança e polimorfismo

i~ ­

I~

a úrnca maneira dele funcionar será se o método de sobreposição ti ver os mesmos argumentos e tipos de retorno. Caso contrário, alguém com uma referência de Appliance poderia chamar turnOn( ) como um método sem argumentos, ainda que haja uma versão de Toaster que use um int. Qual será chamada no tempo de execução? A de Appliance. Em outras palavras, o método turnOn(illt leveI) de Toaster não é uma sobreposição!

CD

Os argumentos devem ser iguais e os tipos de retorno devem ser compatíveis.
o contrato da superclasse define como outros códigos podem usar um método. Independentemente do argumento que a superclasse usar, a subclasse que sobrepuser o método deve usar esse mesmo argumento . E independentemente do tipo de retorno que a superclasse declarar, o método de sobreposição deve declarar o mesmo tipo ou um tipo da subclasse . Lembre -se de que um objeto da subclasse tem que pode r fazer tudo que sua superclasSe decla rar, portanto é seguro retornar uma subclasse onde a supe rclasse for esperada.

Appliance
public boolean turnOn( ) publ i c boolean turnOn( )

- - --. 1 -.I

-

INVÁLIDO!
Não é uma sobreposição vál ida, porque você restrin giu o nível d e acesso, Nem é uma sobr e CARGA val i d a , porque você não alterou os argumentos.

®

O método não pode ser menos acessível.
Isso s igni fica que o nível de ac ess o deve ser ~o mesmo, ou mais amigável. Ou seja, você não pode, por exemplo, sobrepor um método público e torná - lo privado . Que surpresa seria pa r a um código que chamasse o que pensava (no tempo de comp il ação) ser um mé todo públic o , se repentinamente a JVM se opusesse porque a versão de sobrepos ição c hamada no temp o de execução é privada !

/

Até agora falamos sobre dois níveis de acesso : privado e público . Os outros dois estão no capítulo sobre implantação (Lance seu código ) e no Ap~ndice B. Também há outra regra a r espeito de sobreposição relacionada à manipulação de exceções, mas esperaremos o capítulo sobre exceções (Compor t amento arri scado) para abordar esse assunto.

Sobrecarregando um método
A sobrecarga de métodos nada mais é do que termos dois métodos com o mesmo nome, porém listas de argumentos diferentes. Ponto. Não há polimorfismo envolvido com métodos sobrecarregados! A sobrecarga lhe permitirá criar diversas versões de um método, com listas de argumentos diferentes, para a conveniência dos chamadores. Por exemplo, se você tiver um método que use somente um int, o código que o chamar terá que converter, digamos, um double em um int antes de chamar seu método. Mas, se você sobrecarregou o método com outra versão que usa um double, tornou tudo mais fácil para o chamador. Veremos mais Sobre isso quando examinarmos os construtores no capítulo sobre o ciclo de vida dos objetos.
Já que um método de sobrecarga não tem que obedecer ao contrato de polimOliismo definido por sua superclasse, os métodos sobrecarregados têm muito mais flexibilidade.

Um método sobrecarregado é apenas um método diferente que por acaso tem o mesmo nome. Não há nenhuma relação com a herança e o polimorfismo. Um método sobrecarreg ado NÃO é o mesmo que um método sobreP-QJlJ,Q.

CD Os tipos
®

de retorno podem ser diferentes.
contant o que as

Você poderá alterar o s t i pos de retorno de métodos sobrecarregados, l istas de argumentos sejam diferentes .

Você nãoj)oQe al!erar SOMENTE

O

tipo de retorno.

Se somen te o tipo de retorno for diferente, essa nã o será uma sobrecarga válida - o compilador pr esumirá que você está ten tando sobrepor o método . E nem mesmo isso será válido, a menos que o tipo de retorno seja um subtipo do tipo de retorno declarado na

você está aqui

~

139

exercício: mensagens rnistuíad8S
superclasse. Para sobrecarregar um método, você DEVE alterar a l i sta de argumentos, embora possa alterar o tipo de ret orno para qualquer -coISã: - -

1
~.!

Â::·

':-i' ..

® Você pode variar os

níveis de acesso em qualquer direção.

~

~.1

Você poderá sobrecarregar u m método com outro que se ja mais restritivo. Não haverá problema, j á q ue o novo método não é obri gado a obedecer ao contr ato do método sobrecarregado.

Exemplos válidos de sobrecarga de métodos:
public class Overl oads String uniqueID; public int addNums (int a, int b) return a + b; {

public double addNums (double a, ·double b) return a + b;

{

public v oid setUniqueID (String theID) { II um extenso código de val idação e então: uniqueID = theID;

public void setUniqueID (int ssNumber) String numString = "" + ssNurnber; setUni queID(numString) ;

Mensagens misturadas

b=5.:s:; 11
o programa:

a = 6;

56

a = 5;

65

Um programa Java curto é listado a seguir. Um bloco do prograrm está faltando! Seu desafio é comparar o bloco de código candidat o (à esquerda) com a saída que você veria se ele fosse inserido. Nem todas as linhas de saída serão usadas e algumas delas podem ser usadas mais de uma vez. Desenhe linhas conectando os blocos de código candidatos à saída de linha de comando correspondente.
c l ass C extends B { void m3() { System .out.print ( "C's m3,

class A { int i v ar = 7; vo id m1 () { System.out.print("A's m1, voi d m2 () { System . out . print("A's m2, void m3() { System.out.print("A's m3 ,

"+(ivar +

6)) ;

");

");

");

class B extends A { void m1() { System . out . print("B's m1,

publi c class Mixed2 { public stat ic vo id main(String [] args) { A a new A() ; B b = new B(); C c = new C(); A a2 = new C(); O código candidato entra aqui (três linhas) 
.._

") ;

_ _ _ _ _ _... ~

I

códigos candidatos:
b.ml (); c.m2 () ; a . m3 (); c . m1 () ; c . m2 (); c .m3 () ;

saída:
a.m1 () ; b.m2 (); c.m3 (); a2 . m1 (); a2 . m2 (); a2 . m3 ();

A 's mI, A's m2, C's m3, B ' s m1, A' s m2, A's m3,

6

} }

} }

A's mI, B's m2, A's m3 , B's m1, A's m2, C's m3, 13 B's m1, C's m2, A' s m3, B's m1, A's m2, C's m3,
6

A's m1, A ' s m2, C ' s m3, 13

140 ca~iJL;1? 2J

~= " 'I I,...,:··

herança e polimorfismo

Seja o compilador
Qual dos pares de métodos A-B listados à direita, quando inseridos nas classes à seriam compilados e produziriam a saida mostrada? (O método A é inserido na classe Monster e o método B é inserido na classe Vampire.)

public c l ass M onsterTestDrive ( public static v oid main(String [ ) args ) Monster [) ma = new Monster(3); ma[O) new Vampire(); ma[l) = new Dragon(); ma(2) = new Monster(); for(int x = O; x < 3; x++) ma[x ) .frighten(x ) ;

1

boolean frighten (int d) ( System.out.println("arrrgh" ) ; return true;

boolean frighten(int x) ( System . out.println("a bite?"); return false;

2
class Monster

class Vampire extends Monster {

"

"
e

boolean frighten(int x) System.out.println("arrrgh") ; return true;

int frighten(irit f) { System. out .println ("a bite?") ; return 1;

3
class Dragon extends Monster ( boolean frighten(int degree) System . out.println("breath fire"); return true;

"
e

boolean frighten ( int x) ( System.out.println("arrrgh") ; return false;

boolean scare(int x) ( System.out.println("a bite?"); return true;

4

"

boolean frighten(int z) System. out. println ("arrrgh") ; return true;

boolean frighten(byte b) System.out.println("a bite?"); return true;

._-_._ - - - --

-

- -- --

- - --

- --

- --

você está aqui

~

141

quebra-cabeças: quebra-cabeças na piscina
~ ~Quebra-cabeças

na Piscina

Sua tarefa é pegar os trechos de código da piscina e
~~~~~-Oinseri-los nas linhas em bran~odo código. Você pode

~
public c las s Rowboa t public r owTheBoat() ( System. out . print("stroke natasha" );

usar o mesmo trecho mais de uma vez e talvez não precise empregar todos os trechos. Seu objetivo é criar um conj unto de classes que sejam compiladas e executadas juntas como um programa. Não se iluda é mais difícil do que parece.

public class private int void length = len; public int getLength()

-

- '-

)

(

public move () System.out.print("

");

public class TestBoats ( ~~__ ~~__ main('String[ ) args){ ~~~~_ bl = new Boat () ; Sailboat b2 = new - - - -- ( ) ; Rowboat new Rowboat(); b2 . setLength(32) ; bl. (); b3. () ; ~_____ .move() ;

~-:~-~

public class public

Boat (
_ _ _ _ r) {

System.out.print("~~~~~_")

;

Saída

Rowboat Sailboat Testboats

int int bl in t b2 int b3

h os t sail rowTheBoat

b2 b3

r eturn continue break natasha

length len

string vo i d s tatic public

subclasses extends drift move

.,'-"

--.=

herança e polimorfismo

Seja o Compilador

o conjunto 1 funcionará.

h
h

O conjunto 2 não será compilado por causa do tipo de retorno (int) de Vampire.

k
I,....

Soluções dos exercícios

1 --. h

)

h h h
.~ J~

/

.-

j

O método frighten( ) de Viuupire (B) não é uma sobreposição OU sobrecarga válida do método frighten( ) de Monster. Alterar SOMENTE o tipo de retorno não é suficiente para a criação de uma sobrecarga válida e, já que um int não é compatível com um booleano, o método não é uma sobreposição válida. (Lembre-se de que se você alterar SOMENTE o tipo de retorno, terá que ser para um tipo que seja compatível com o tipo de retorno da versão da superclasse, então teríamos uma sobreposição.) Os conjuntos 3 e 4 serão compilados, mas produzirão:
arrrgh breath fire arrrgh

1 ,-,

Lembre-se de que a classe Vampire não sobrepôs o método frighten( ) da classe Monster. (O método frighten( ) do conjunto 4 de Vampire usa um byte e não um int.)

_ t
1 --l~i~~f

Mensagens misturadas

códigos candidatos:
b.m1 (); c .m2 () ; a.m3 () ; c . m1 () ; c . m2 () ; c .m3 (); a.m1( ) ; b.m2 (); c .m3 (); a2 .m1 (); a2 .m2 (); a2 .m3 ();

saída:
A' s m1, A' s m2, B's m1, A's m1, C's m3,
6

J'"'

}} } }
~""""'"--

A's m2, A's m3 , B's m2, A's m3, C's m3, 13

il~'
~ I~-

B's m1, A' s m2, B's m1,

C's m2, A's m3, C's m3,
6

B's m1, A' s m2, A's m1, A' s m2,

C's m3, 13

Saída

drift

drift

hoist sail

public class Rowboat

extends Boat (

public class TestBoats (

public void rowTheBoat () ( System.out.print("stroke natasha");

public static void main(St ri ng[] args) ( . Boat b1 = new Boat () ; Sailboat b2 = new Sailboat () ; Rowboat b3 = new Rowboat();
b2.setLength(32); b1. move () ; b3.move () ;

public clas s

Boat { private i nt length public vo i d setLength (int len ) (
length = len; public int getLength ( )

b2 . move ();

return length
public

public class
{

void . mGV8 -()

System . out. print

("drift

")

;

Sailboat extends Boat ( void move () ( ·· --~;ystem ~out . pr int("hoist sail ") ;
publi c

você está aqui»

143

Polimorfismo Real

li

~J~~
:I '

.

J-",
.....

'J.---

-----

o_h
~R'. ""':~:' ..
'~ . ~., ..

~~

,'1

,"'c

'i}:~

-_

~;, ~-,
~
"

~'I

..

,<f':. - ,

A herança é apenas o começo. Para explorar o polimorfismo,
precisamos de interfaces (mas não do tipo GUI). Temos que ir além da simples herança até um nível de flexibilidade que você só conseguirá projetando e codificando com especificações de interfaces. Algumas das partes mais interessantes do Java não poderiam ao menos existir sem interfaces, portanto mesmo se você não projetar com elas por sua própria conta, ainda terá que usá-Ias. Mas você vai querer projetar com elas. Precisará projetar com elas.
Vai se perguntar como cOfJseguiu viver sem elas. O que é uma

interface? É uma classe 100% abstrata. O que é uma classe abstrata? É uma classe que não pode ser instanciada. Em que isso é útil? Você verá em breve. Mas se pensar no final do último capítulo e em como usamos argumentos polimórficos para que apenas um método de Vet pudesse usar subclasses de Animal de todos os tipos, bem, isso apenas arranhou a superfície. As interfaces representam o prefixo poli de polimorfismo. O ab de abstrato. A cafeína em Java.

este é um novo capítulo

145

projetando com a hera nça

A estrutura da classe não está tão ruim. Foi projetada para que os códigos duplicados fossem mantidos em um nível mínimo e sobrepusemos os métodos que achamos que deveriam ter implementações específicas da subclasse. Foi construída para ser adequada e flexível a partir de uma perspectiva polimórfica, já que podemos projetar programas usando a classe Animal e seus argumentos Ce declarações de matrizes), para que qualquer subtipo de Animal - inclusive aqueles em que não pensamos no momento em que escrevemos nosso código - possa ser passado e usado no tempo de execução. Inserimos o protocolo comum a todos os objetos Animal (os quatro métodos que queremos que todos saibam que qualquer objeto Animal tem) na superclasse Animal e estamos prontos para começar a criar novos objetos Lion, Tiger e Hippo.

-~~,:j~
,..--;,

:1"

".-"1

pictu re food hunger boundarie s location makeNo\se( eat( 1

makeNoise( eat ( )

makeNoise( eat ( ) makeNoise( e at ( )

makeNois~(

eat( ) .'

makeNoise( eat ( )

Sabemos que podemos dizer:
Wolf aWolf new Wolf () ;

~

fI-----W lf o
Esses dois têm o mesmo tipo.

Uma

referência de Wolf ii um
objeto ftlol f

\

E sabemos que podemos dizer:
Referência d e Arli.ma l li um objeto E:i.ppo

Animal aHippo

new Hippo ( ) ; Animal

Esses d o i s IvÃO têm c meSlT,Q t ipo .

\

146

capitu!G 8

-I ,'""'r-

interfaces e classes abstia tas

k

h

Mas aqui é que começa a ficar estranho:
an~

h
-1 ,"",-

~

I:~~

Animal anim

new Animal( ) ;

----------~-----

I'""'

Animal

Esses àoís têm o mesmo tipo , Qual é aparência de um cc

\

/

mas~,~

Qual a aparência de um novo objeto Animal( )?

objetos estranhos .

Quais são os valores das variáveis de instância? Algumas classes não deviam ser instanciadas!
. Faz sentido criar um objeto Wolf, um objeto Hippo ou um objeto Tiger, mas o que exatamente é um objeto Animal? Que fomm ele tem? Que cor, tamanho, quantidade de pernas ... Tentar criar um objeto de tipo Animal é como ter um pesadelo em que acontece um acidente no teletransporte de Jornada nas Estrelas™. Aquele em que em algum local do processo de teletransporte algo errado acontece ao buffer. Mas como lidar com isso? Precisamos de uma classe Animal, devido à herança e o polimorfismo. Mas queremos que os programadores instanciem somente as subclasses menos abstratas da classe Animal, e não a própria classe Animal. Queremos objetos Tiger e objetos Lion e não objetos Animal. Felizmente, há uma maneira simples de impedir que uma casse seja instanciada. Em outras palavras, de impedir que alguém use "new" com esse tipo. Se marcarmos a classe com abstract, o compilador impedirá que qualquer código, esteja onde estiver, crie uma instância desse tipo. Você ainda poderá usar esse tipo abstrato como um tipo de referência. Na verdade, em grande parte é por isso que você tem essa classe abstrata (para usá-la como um argumento ou tipo de retorno polimórfico ou para criar uma matriz polimórfica). Quando você estiver projetando sua estrutura de herança de classe, terá que decidir que classes serão abstratas e quais serão concretas. As classes concretas são aquelas específicas o suficiente para ser instanciadas. Uma classe ser concreta significa apenas que não há problemas em se criar objetos desse tipo. Criar uma classe abstrata é fácil- insira a palavra-chave abstract antes da declaração da classe:
-abs t ract class Canine extends Animal ( pi"ibli'c vo id roam () { }

o compilador não permitirá que você instancie uma classe abstrata
--Um a-C' ~~' õ ' ~~~-~·~ .c~~~ ____ ; ·
UI
la CJ~ e

seI

dO~llalii ~lg lllLICd

LluC

Illll

b U(;lU

,

l'VU \...d U

-'·6

oe ' o ..... .l.H.H

,~u.<>..i nct8n c;" d
I,AU IU, I I V l ' I A . .................u

...... ... .....

c.@-S-&f.. _ ... a -s-se-• . ~Ç':e

~

~

A

d R!TI_a pO rl" __ e!R

usar essa classe abstrata como um tipo de referência na declaração, para fins de polimorfismo, mas não terá que se preocupar com o fato de alguém criar objetos desse tipo . O compilador garante isso.
você está aqui»

147

classe abstratas e cemcretas
abstr a ct public c lass Canine ex tends Animal

.. _ ~

pub li c cla ss M ke Can ine a public void go( ) {
:=S50 ~sti corret.o,. porque você S€. pre p!jã€>rá atribuir cm m ~ ~__________________ o}:;jet;o da $ubc2a.sse a u..~a rerexAência ca superc1.asse~ mesmo Canin e C ; .se a s u perclasse for a.bstre_ ta, C = new Do g ( ) ; )

c = n e w Canine() ; ( ------------------- a classe Canine está w~r~ada com aebtract portanto o ~ompilador I~O permitirá que você faça isso.
í

,.

c . r oam() ;

Uma classe abstrata praticamente* não tem uti lidade, valor, razão de existir, a menos que seja estendida. No caso da classe abstrata , quem se encarregará do trabalho no tempo de execução serão instâncias de uma subclasse de sua classe abstrata .
• Há uma exceção aqui - uma classe abstrata pode ter membros estáticos (consulte o Capítulo 10).

Abstrato versus concreto
Uma classe que não é abstrata é chamada de classe concreta. Na árvore de herança de Animal, se tornarmos Animal, Canine e Feline abstratas, isso deixará Hippo, Wolf, Dog, Tiger, Lion e Cat como as subclasses concretas. Examine o APl Java e você encontrará válias classes abstratas, principalmente na biblioteca de GUls. Qual a aparênci a de um componente de GUI? Component é a superclasse das classes relacionadas às GUls para coisas como botões, áreas de texto, barras de rol agem, caixas de diálogo e o que mais pudermos imaginar. Você não criará a instância de um objeto Component genérico e o inserirá na tela, criará um objeto JButtoll. Em outras palavras, você instanciará somente uma subclasse concreta de Component, mas nunca o próprio objeto Component.
abstrata

interfaces e classes abstratas

-o
abstrato

poder do cérebro
OU

Camelot Vineyards 1997 Pinot Noir foi uma boa safra ...

concreto?

Como saber quando uma classe deve ser abstrata? Vinho provavelmente é abstrata. Mas e quanto a Tinto e Branco? Provavelmente abstratas também (para alguns de nós são mesmo). Mas em que ponto da hierarquia as coisas se tornam concretas? Você acha que PinotNoir é concreta ou também é abstrata? Parece que o Camelot Vineyards 1997 Pinot Noir é concreto. Mas como ter certeza? Examine a árvore de herança de Animal acima. As opções que fizemos para que classes são abstratas e quais das que são concretas parecem apropriadas? Você alteraria algo na árvore de herança de Animal (que não fosse ádicionar mais objetos Animal, é claro)'?

Métodos abstratos
Além das classes, você também pode marcar os métodos como abstratos. Uma classe abstrata significa que ela deve ser estendida; um método abstrato significa que ele deve ser sobreposto . Você pode chegar à conclusão de que alguns (ou todos) comportamentos de uma classe abstrat~ não terão sentido, a menos que sejam implementados por uma subclasse mais específica. Em outras palavras, não é possível pensar na implementação de um método genérico que pudesse ser útil para as subclasses. Qual seria a aparência de um método eat( ) genérico?

"~.

"-;l.
"o'

:1 ~-- Um método abstrato não tem corpo!
,~,.~:- . ,

jt

, ~,

. ...-..

__

Como você já decidiu que nenhum código faria sentido no método abst~'ato , não inserirá um corpo no método. Portanto, não haverá chaves ___ - sImplesmente tennine a declaração com um ponto-e-vírgula
pUblic ,.,.,bstra, ~.t void eat ( ); ,., a " .,",
""-~~.

~A-'

.

Nenhum corpo no método! ' T e r m i n e - o com um ponto-e-vírgula~

Se você declarar um método como abstrato, também DEVE marcara classe como abstrata. Não é possível ter um método abstrato em uma classe nãoabstrata.
Mesmo se você inserir apenas um método abstrato em uma classe, terá que torná-la abstrata. Mas é possível combinar métodos abstratos e não abstratos na classe abstrata . .

-

Não existem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Perguntas Idiotas
Qual é a vantagem em se ter um método abstrato? Pensei que a finalidade de uma classe abstrata seria termos um código comum que pudesse ser herdado pelas subclasses.
As implementações de métodos herdáveis (em outras palavras, métodos com corpos reais) são algo bom de _se inserir em uma superclasse. Quando isso faz sentido. E em uma classe abstrata , geralmente não faz sentido, porque você não conseguirá críar ·um código genenco que ~ejé:l útíi f.!dl d d~ ~ut;dasses. A vantagem de um método abstrato é que ainda que você não tenha inserido nenhum código de método real, terá definido parte do protocolo --=-- - para um grupo de subtipos (subclasses) .

P:

R:

,r--.

vocô está aqui

li>-

149

você deve implementar os n,étodos abstratos

p.

o qüe é

bom porquê ...

Por causa do polimorfismo! Lembre-se, o que queremos é a possibilidade de usar um tipo da superclasse (geralmente abstrato) como argumento, tipo de retorno ou tipo de matriz de um método. Dessa forma, você poderá adicionar novos subtipos (como uma nova subclasse de Animal) ao seu programa sem ter que reescrever (ou adicionar) novos métodos para lidar com esses novos tipos. Imagine o que você teria que alterar na classe Vet, se ela não usasse Animal como o tipo de argumento de seus métodos. Seria preciso ter um método separado para cada subclasse de Animal! Um método que usasse um objeto Lion, um que usasse um objeto Wolf, um que usasse ... Percebeu? Portanto, com um método abstrato, você está dizendo, "todos os subtipos desse tipo têm ESSE método" para se beneficiar do polimorfismo.

R:

'"
~

. 1
I

t

,-... i,i ,- -, ,--...

Você DEVE implementar todos os métodos abstratos

Implementar um método abstrato é como sobrepor
um método.
Os métodos abstratos não têm um corpo; eles existem somente por causa do polimorfismo. Isso significa que a primeira classe concreta da árvore de herança deve implementar todos os métodos abstratos. No entanto, você pode retardar o processo sendo o máximo possível abstrato. Se tanto Animal quanto Canine forem abstratas, por exemplo, e as duas tiverem métodos abstratos, a classe Canine não terá que implementar os métodos abstratos de Animal. Mas, assim que chegarmos à primeira subclasse concreta, como Dog, essa subclasse terá que implementar todos os métodos abstratos tanto de Animal quanto de Canine. Mas lembre-se de que uma classe abstrata pode ter tanto métodos abstratos quanto não-abstratos, portanto Canine, por exemplo, podelia implementar um método abstrato de Aninmal, para que Dog não tivesse que fazê-lo. Mas se Canine não fizer nada com os métodos abstratos de Animal, Dog terá que implementar todos eles. Quando dizemos "você deve implementar o método abstrato", isso significa que deve fornecer um corpo. Significa que você deve criar um método não-abstrato em sua classe com a mesma assinatura (nome e argumentos) e um tipo de retorno que seja compatível com o declarado para o método abstrato. O que você vai inserir nesse método é problema seu. O Java só verificará se o método está lá, Em sua subclasse concreta.
Aponte seu lápis

Classes abstratas versus concretas
Passemos toda essa retórica abstrata para uma prática concreta. Na coluna do meio listamos algumas classes. Sua tarefa será imaginar aplicativos onde a classe listada possa ser concreta e aplicativos em que ela possa ser abstrata. Demos palpites nos primeiros para ajudar. Por exemplo, a classe Árvore seria abstrata no programa de um viveiro de árvores, onde as diferenças entre um Carvalho e um Álamo são importantes. Mas em um programa de simulação de golfe, a árvore pode ser uma classe concreta (talvez uma subclasse de Obstáculo), porque ele não dá importância ou faz a distinção entre diferentes tipos de árvore. (Não existe uma resposta cOlTeta; isso vai depender de seu projeto,)

Concreta
simul ação de um curso de golfe

Exemplo de classe
Árvore Casa

Abstrata
aplicativo de viveiro de árvores aplicativo de arquitetura

aplicativo de fotografia por satélite

Cidade Jogador de Futebol Cadeira aplicativo de treinamento

150 capítulo 8
--' -

interfaces e ciasses abstratas

r

f,.-..
I,~

~--,
", Aponte seu lápis (continuação)
~

_. t=

~-

Concreta

Exemplo de classe
Cliente Pedido de Compra Livro Loja Fornecedor

Abstrata

I~

Clube de Golfe Carburador Forno

~
I

'

, ';-'

''"-

,

o polimorfismo em ação
Suponhamos que quiséssemos criar nosso próprio tipo de classe de lista, que armazenasse objetos Dog, mas vamos fingir por um momento que não conhecemos a classe ArrayList. Na primeira versão, daremos a ela apenas um método add( ). Usaremos uma matriz Dog simples (Dog[]) para armazenar os objetos Dog adicionados e atribuiremos o tamanho 5. Quando chegarrnos ao limite de 5 objetos Dog, você ainda poderá chamar o método add( ) mas ele não fará nada. Se não estivermos no limite, o método add( ) inserirá o objeto Dog na matriz na próxima posição de índice disponível e, em seguida, incrementará esse próximo índice disponível (nextIndex).

.

""--

Construindo nossa própria lista específica de objetos 009
(Talvez a pior tentativa já feita de criar nosso próprio tipo de classe ArrayList, a partir do zero.)
public class MyDogList private Dog [] dogs new Dog[5];
(~-

Usa uma matriz Dog antiga em segunào plano.

private int nextlndex = O;

Incrementaremos isso sempre que um ~( ~------------ novo objeto Dog for adicionado.

MyDogList
Dog[] dogs int nextlndex

public void add(Dog d) if

{
~

(nextIndex < dogs.length) dogs[nextIndex] = d;

.....

add(Dog d)
-;>'i7'&M'
'0

J

Se ainda não tivermos chegado ao limite da matriz de cães, adiciona o objeto Dog e exibe a mensagem.

System.out.println ( "Cão adicionado em " + nextIndex); nextIndex++; ~<~------------------- Incrementa, para rornecer o próximo índ ice que será usado.

Bem, agora também temos que armazenar objetos Cat.
Temos algumas opções aqui: 1) Criar uma classe separada, MyCatList, que armazenará objetos Cat. Muito complicado. 2) Criar um única classe, DogAndCatList, que terá duas matrizes diferentes como variáveis de instância e dois métodos add( ) distintos: addCat(Cat c) e addDog(Dog d). Outra solução complicada. 3) Criar a classe heterogênea AnimalList, que usará qualquer tipo de subclasse de Animal (já que sabemos que, _se .a ~~ Recificação for alterada para adicionar objetos Cats, não demorará a termos também algum outro tipo de animal adicionado) . Preferimos essa opção, portanto alteraremos nossa classe para torná-:'Tã'maÍs genérica e Usar objetos Animal em vez de apenas objetos Dog. Realçamos as alterações-chave (a lógica é a mesma, é claro, mas o tipo foi alterado de Dog para Animal em todos os locais do código) . .
você está aqui
~

151

a superclasse superior:

public class NyAnimalList

(

ilif1 EO"'.rO objet:o ;lTÀim2l1; est:: . ::s..mOSJ criêvedo 1~ttn ::r.tO',?'O o.bj e.to de :.~~,.~..F_!:_0:~ tipo )-lnimal.

cxifindo

MyAnimalList
Animal[] animals int nextIndex add(Animal a)

..~

private Animal[] animals private int nextIndex = O;

(Lembre-se Ó$ qtJE

v-o :~é

.Dáo pode
u.rn

criar

;
!

public void add(Ani~a{ a) ( pa.ra CONTER -esse tipo .. ) if (nextInde~ < ~nimals.length) animals[nextIndex] = a; System . out.println("Animal adicionado em " + nextIndex); nextIndex++;

tipo abst;rf~t;O,. l"nas PODE criar u.m obj€to de matriz declarado

public class AnimalTestDrive{ public static void main (String[] args) ( MyAnimalList list = new MyAnimalList(); Dog a = new Dog(); Cat c = new Cat(); list. add (a) ; list.add(c);

<1 O alguns dos métodos E quanto aos objetos que não forem animais? Por que não @ de ArraJFLi s t ., Há criar uma classe genérica o bastante para poder armazenar muitos outros~} qualq uer coisa? r-----A~r-r-a-y~L-:i-s-t---""'I
<o"

ersã

( Esset:5 são apenas

Você sabe para onde isso está nos levando. Queremos alterar o tipo da matriz, e o argumento do método add( ), para algo que esteja acima de Animal. Algo ainda mais genérico, mais abstrato do que Animal. Mas como podemos fazê-lo? Não temos uma superclasse para Animal. Mais uma vez, talvez tenhamos ... Lembram-se dos métodos de ArrayList? Observe como os métodos remove, contains e indexOf usam um objeto de tipo .. . Object!

Todas as classes em Java estendem a classe Object.
A classe Object é a mãe de todas as classes; é a superclasse de tudo . Mesmo se você se beneficiar do polimorfismo, ainda terá que criar uma classe com métodos que usem e retornem seu tipo polimórfico. Sem uma superclasse comum para tudo em Java, não haveria uma maneira de os desenvolvedores criarem classes com métodos que pudessem usar os seus tipos personalizados ... Os tipos que eles mio conheciam quando criaram a classe ArrayList. Portanto, você esteve criando subclasses da classe Object desde o início sem nem mesmo saber disso. Toda classe que você criar estenderá Object, sem que seja preciso declará-lo. Mas você pode considerar isso como se tivesse criado uma classe dessa forma:
public class Dog extends Object {}

boolean remove elem) Removerá o informado no parâmetro de índice. Retornará 'verdadeiro' se o elemento estiver na lista. boolean contains (oBj~êt elem) Retornará ' ~e~d~deiro' se houver urna coincidência com o parâmetro de objeto. boolean isEmpty( ) Retornará 'verdadeiro' se a lista não tiver elementos. int indexOf (Object e l em) Retorna;á · ~indice do parâmetro de objeto ou -1. p}jj~E~ get (int index) Retornará o elemento que estiver nessa posição na lista . boolean add <ç'J;)jeCi:: e l em) Adiciona o elemento à lista (retorna 'verdadeiro') . II outros
dos métodos de ArrayLi st usam poLim6rfico supe:rioT, O}J.7ect. "" á ÇfLl8 i c1.assé uma subcl.a$Sê de
podem

Porém espere um minuto, Dogjá estende algo, Canine. Sem problemas. O compilador fará tirw Canine estender Object. Mas Canine estende Animal. Sem prob lemas, o compilador fará todil com que Animal estenda Object.

Qualquer classe que não estender explicitamente outra classe estenderá implicitamente Object.
Então, já que Dog estende Canine, não estenderá diretílmente Object (embora o estenda indiretamente) e () mesmo é verdade para Canine, mas Animal estende diretamente Object.

usar qualquer coisa j

~!= .

k~:"

interfaces e classes abstratas

h

h
~
h

Mas o que é essa ultrasupermegaclasse Object?
Se você fo sse a Java, que comportamento iria querer que todo obj eto tivesse? Hmmmm ... Vejamos ... Que tal um método que lhe permita descobrir se um obj eto é igual a outro? E um que possa lhe informar o tipo de classe real desse objeto? Talvez um método que forneça um código de hashing para o objeto, para que você possa usá-lo em tabelas de hashing (falaremos sobre as tabelas de hashing da Java no Capítulo J7 e Apêndice B). Ah , pensei em algo interessante - um método que exiba uma mensagem na forma de string para esse objeto. E quer saber? Como se por encanto, a classe Object tem realmente métodos para essas q~ atro coisas. Isso não é tudo, mas esses são os métodos que nos importam realmente.
~equalS(Object o)

Object
boolea n equa l s( ) Class getClass( ) int hashCode( ) String toStr ing (
~rlpenas

liLGUNS

dos métodos da.

:i
)

c lass e Objecto

~

t-

Toda

c~ a sse

q"Ji?

SuaClasseAqui

I~

i

~!
;

®getClass ( )
Cat c = n ew Ca t () ; Syst e m.out . println(c . get Class(»

você cri ar herdará todos os métodos da classe Objecto AS classes que ia criou herdaram métodos que você nem sabia que tinl1.a.

Dog a new Dog() ; Cat c = new Cat() ; if (a.equals (c» ( System .out . println ("t rue" ) ; else ( System . out . prin t l n ( "fa lse" ) ;

I nforma se dois objetos são consi derados ' iguais' (fal a remos sobre o que si gnifi c a r ealmente 'igual ' no Apên dice B) .

Retorna a classe em que o obieto foi instanciado.

® hashCode (

)

® toString (

)
;

Cat c = n ew Cat () ; System.out.pr intln(c . hashCode(»;

Cat c = new Cat(); System.out . println ( c.toString (»

~~ibe

o código de hashi ng do objeto (por enquanto, c onsidere-o como uma identificação exclusiva).

Exibe uma mensage.'1l na forma áe string com o nome áa

classe e al guns outros números que raramente illt eressam .

- - - - Não existem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ' if. -.

;.;r -

k". R:
~1

t ~;,:
" r--"lj'

~",·~-~·:· - R:

!: P:

Perguntas Idiotas
A classe Object é abstrata?

Não. Bem , não no sentido formal em Java . Object é uma classe não-abstrata porque tem códigos de implementação de métodos que todas as classes podem herdar e usar independentemente, sem ser preciso empregar a sobreposição.

P:

Então podemos sobrepor os métodos de Object?

Alguns deles. Mas outros estão marcados com final , que significa que você não poderá sobrepô-los. aRpercomden,damfos que sobreponha hashCode( ), equalsO e toStringO em suas próprias classes , o qu-evocê en era a azer posteriormente no livro. Mas alguns dos métodos, como getClassO, executam coisas que devem ~-=-- funcionar de uma maneira específica e garantida . você está aqui
li-

°

153

...--=-"" _ ....

--

Object e éS (iãSSBS aost:-ãlas métodos reais dos quais todos os objetos do Java .- • Se os métodos de ArrayList"são - --·-- - -precrsâm no tem-po de execüção (e inseri-rü-s na classe suficientemente genéricos para usar Object, o que Object significa que todas as outras classes os herdarão). Alguns dos métodos mais importantes de significa dizer ArrayList<DotCom>? Achei que estivesse limitando a ArrayList a só conter objetos Object estão relacionados a segmentos e os DotCom? estudaremos posteriormente no livro.

.--..,

- '._, 1
!

o.

- I ----- ,

R: E você a estava limitando. Antes do Java 5.0, as
ArrayLists não podiam ser limitadas. Eram todas essencialmente o que você terá no Java 5.0 atualmente se escrever ArrayList<Object> . Em outras palavras, uma ArrayList limitada a qualquer coisa que fos$e um objeto, o que significa qualquer objeto em Java, instanciado a partir de qualquer tipo de classe! Abordaremos os detalhes dessa nova sintaxe <tipo> posteriormente no livro. Certo, voltando ao fato de a classe Object ser não-abstrata (portanto, acho que isso significa que ela é concreta), COMO permitir que alguém crie um objeto de tipo Object? Isso não é tão estranho quanto criar um objeto Animal? Boa pergunta! Por que é aceitável criar uma nova instância de Object? Porque em algumas situações você . pode querer usar um objeto genérico como, bem , um objeto. Um objeto leve. Sem dúvida, o uso mais comum de uma instância de tipo Object é na sincronização de segmentos (sobre a qual você aprenderá no Capítulo 15). Por enquanto, deixe isso em segundo plano e suponha que raramente criará objetos de tipo Object, ainda que possa fazê-lo. Então estaria correto dizer que a finalidade principal do tipo Object é podermos usá-lo como argumento e tipo de retorno polimórfico? Como em ArrayList? A classe Object serve a duas finalidades principais : agir como um tipo polimórfico para métodos que tenham que ser usados em qualquer classe que você ou outra pessoa criar, e fornecer códigos de

P: Se é tão bom usar tipos polimórficos, por que
não fazer com que TODOS os métodos usem e retornem o tipo Object? Vejamos ... Pense no que aconteceria . Em primeiro lugar, você invalidaria a importância da 'segurança de tipos ', um dos melhores mecanismos de proteção do Java para seu código. Com a segurança de tipos, o Java garantirá que você não solicite ao objeto errado para fazer algo que queria pedir a outro tipo de objeto. Como solicitar a uma Ferrari (que você acha que é uma Torradeira) que cozinhe a si mesma. Mas a verdade é que você não precisa se preocupar com esse cenário causticante da Ferrari, mesmo se realmente usar referências de Object para tudo. Porque, quando os objetos são referenciados por um tipo Object, a Java interpreta que ele está referenciando uma instância de tipo Object. E isso significa que os únicos métodos que você pode chamar nesse objeto são os declarados na classe Object! Portanto, se você escrevesse este código :
Objec t o = new Ferrari (); o . goFast(); (( Não é válido!

R:

~

P:

R:

P:

R:

Não conseguiria nem fazê-lo passar pelo compilador. Já que o Java é uma linguagem fortemente tipificada, para se certificar o compilador verificará se você está chamando um método em um objeto que seja realmente capaz de responder. Em outras palavras, você pode chamar um método em uma referência de objeto somente se a classe do tipo da referência tiver o método. Abordaremos isso com muito mais detalhes um pouco mais adiante, portanto não se preocupe se o ' cenário não tiver ficado muito claro.

o USO de referências polimórficas de tipo Object tem um preço ...
Antes de você começar a usar o tipo Object em todos os seus argumentos e tipos de retorno ultra-flexíveis, terá que considerar um pequeno problema do uso do tipo Object como uma referência. E lembre-se que não estamos fa lando da criação de instâncias de tipo Object; estamos falando sobre a criação de instâncias de algum outro tipo, porém com o uso de uma referência de tipo Object. Quando você inserir um objeto em uma ArrayLi st<Dog>, ele será inserido como um objeto Dog e também sairá como um objeto Dog:
ArrayList <Do g> myDogArrayList = new ArrayLis t<Dog> () ; cri a uma Array List dec lereda para armazenar ob jotos Dog.

Dog aDog = new Dog(); ~--~--------------------------.--- Cria um objeto Dog~ myDogArrayList . add( aDog) ; ~--------------------Dog d :::; myDogArrayList . get(Q);
4!~----------------

Adiciona o objet:o Dog à lista .

:.:..'=r.:c...::.tU..!.
l"a-~a\..-el

o .-.::::.bJ~cc> ~}og da .!1.St'a. a
à~~ rp<F~'r'êYJ(""';e n~f!
.;; ine.to~o

Uffi5.

nova
;.$,50

tCoJ1s1derF'
l..i.ID

=omo

Bt:::

geL (

,

àac~are$se

t'::po de

reta.:-na

Dc~

porque você usou Arra.y·Li 5t: <IJog:;. ..

J

154 . ca pitu!Q

~3."._

.

interfaces e ciasses abstratas
Mas o que acontecerá quando você declará-Ia co mo ArrayL ist<Object>? Se quiser criar uma ArrayList que use literalmente qualquer tipo de obj eto, terá que declará-Ia desta forma:
ArrayList<Object > myDogArrayList Dog aDog

=

new ArrayList<Object> (); Cria
~

~.,......----

'::r_iZ

uma A..rr:iyLisc
qualqü~=

d~'3claradâ

pa.ra

concer

cipv ae objeto.

=

new Dog();

~<~---------------

cbjeto Vog .

myDogAr rayL ist. add (aD og );

c!---- - - - - - - - - Ad.i.cicn<l o QJ':;jet c Dog à .lista .. }

'"~

[Essai;' duas etapas sã.o Iguais .

1

E

O

que acontecerá quando você tentar cat>turar o objeto Dog e atribuí-lo a uma variável de referência Dog?
Do g d
Não será campi~aão!! Quando você usar ArrayList<Obj€ct>~ o método get( ) retornará o tipo Objecto O compilador só saberá que o objeto bera", d$ Object (em algum local de sua á.rvore de herança)~ mas não saberá que se trata de flag!!

Em uma ArrayList<Object> só serão capturadas referências de tipo Object, independentemente de qual for realmente o objeto ou de qual era o tipo de referência quando você adicionou o objeto à lista.

.. r.-

Os objetos serão inseridos como BolaFutebol, Peixe, Guitarra e Carro

Mas sairão como se fossem de tipo Object.

Os objetos saem de uma ArrayList<Object> agindo como se fossem instâncias genéricas da classe Object. O compilador não terá como saber se o objeto que está sendo capturado é de algum tipo diferente de Object.

Quando um cão não age como um cão
O problema de tratarmos tudo polimorficamente como um tipo Object é que os objetos parecem perder (mas não permanentemente) sua verdad,eira essência. O cão parece perder sua natureza canina . Vejamos o que acontece quando passamos um objeto Dog para um método que retorna uma referê ncia ao mesmo objeto Dog, mas declara o tipo de ~.'±: ~. retorno como Object em vez de Dog. =z~~";,~'-

'riK'

'K:"..~
'C
'nl

public void go()

{
Essa linha não funcionará! Ainda que o método r etorna sse ~~a referência ao mesmo objeto Dog referenciado palo ( _ _ _ _ argumento, o tipo de retorno Object significa que o compilador não permitirá que você atribua a referência retornada a out r a coisa que não seja Objecto

Dog aDog = new Dog();

o

Dog sameDog. = getObject (aDog) ;

> C

?~::~

public Object get Obje c t (Obj ec t return o ;

~
o)

(

Estamos retornando uma referência ao mesmo objeto Dog, como o método get( ) f~~ciona quando temos ArrayList<Object> em vez de ArrayLíst<Dog>.

c!------------------------------ ;:;f:~;a~:n:!P~á~;d:~t:;::: o~;;:t~ ::::l~=:::

:

o compilador não sabe se o que foi retornado pelo método é realmente um objeto Dog, portanto ele não permitirá que você o
.~t~-ibua

a

w.ma v~_riável de referência Dog#

(Você verá por que na próxima página.)

\ioce 8St8 aqUi >-

155

=j
~""
public void go () Dog aDog = new Dog() ; Obj e c t sameDog = getOb ject( a Dog) ;
não seja mu lte ut: il ,. a,t:Y- bu_i:t, i em bre ve ) I' porçr:ue. Qt7.ll.LQtt:8R COl:SA Zl LtWa referência cc tipo Obj~~G;:." jé. qu.& toclas $:S cJasses passariam no teste E-tJJ'\J de ObjGict ,> .s !t! Java todos os objetos s&o uma i l1stá1'1c.ia de tipo Obj€~ctr porque todas as c.lasses têm Object no tqpo de sua árvore de herança~
..

·1 ~-:. " i
~O"~ _

"O
'ct\

o

>

pub l i c Obj ec t getOb ject (Object o) r et urn O i

Objetos não latem.
Portanto, agora sabemos que, quando um objeto é referenciado por uma variável declarada com o tipo Object, ele não pode s~r atribuído a uma variável declarada com o tipo real do objeto. E sabemos que isso pode acontecer quando um tipo de retorno ou argumento é declarado com o tipo Object, como seria o caso, por exemplo, quando o objeto é inserido em uma ArrayList de tipo Object através de ArrayList<Object>. Mas quais são as implicações disso? Seria um problema termos que usar uma variável de referênci a Object para referenciar um objeto Dog? Tentemos chamar métodos de Dog em nosso Cão-Que-O-Compilador-Pensa-QueÉ-Um-Objeto.
objeto

Quando você capturar uma referência de objeto em Arra.:,p·r.ist <Obj ect > (ou qualquer
método que decla1..'+e Object cc:mo o tipo de

~

retorno) % ela retornará como tL"n tipo de referência Object polimórfico~ Portanto f você terá u.ma E~:f~;:~n.9;_:f:.?: de Object (nesse casai a uma instância de Dog~

Object o = al . get(index); int i
Não será compilado!

= o. h ashCode();
) ;

Isso é adeq'..lado. A classe Object tem urr. método hashCode ( ), portanto você pode chamar esse .método em QUALQUER objeto em Java ..
você não pode fazer isso! A classe Object não
sabe
o

que significa ba.rk( ) .. Ainda

ç{1.Ie

VOCÊ

sai ba que o que está no índice é na verdade um objeto Dog~ c crunpiladox não sabe aisso~

o compilador decidirá se você pode
chamar um método com base no tipo da referência e não no tipo do objeto real.
-- ----

hashCode(

)

objeto

- - - ---

-~

-

--

---~-

Mesmo se você souber que o objeto é válido (" .. .mas ele é mesmo um objeto Dog, juro .. ."), o compilador o verá como um tipo Object genérico. Para o compilador, você terá inserido um objeto Button. Ou um objeto Microwave. Ou alguma outra coisa que realmente não sabe latir. O compilador verificará a classe do tipo de referência - e não do tipo de objeto - para saber se você pode chamar um método usando essa referência.

o método
D~z

que você estii.rer

chamando em uma x'ererê:ncia

Object
e qu als ( ) getC l ass( hashCode( toSt r ing(

existir na classe desse tipo de referência, Não importa ~Jal é o objsco réal~

~-----

o.hashCode(

);

li,

referência no ,.<~ foi. decls.X'flda. com o tipo object;;
cn&~ar

portanto você s6 pode.
classe Object
~

métodos S$ 01es ex:iBt Ír'Blu ,na

Entre em contato com seu objeto interior.
Um objeto contém tudo que ele herda de cada uma de suas superclasses. Isso significa que todo objeto - independentemente de seu tipo de classe real - também é uma instância da classe Object. Ou seja, qualquer objeto em Java pode ser tratado não só como um objeto Dog, Button ou Snowboard, mas também como Objecto Quando você escrever uew Suowboard( ), capturará um único obj eto da pilha - um objeto Snowboard - , mas ele estará envolvendo um núcleo interno que representa sua parte Object (com "O" maiúsculo).

.r\'

. ~ ,,-::-:--:.

EI

[,......, -

=-Object
equals( getClass( hashCode(

. interfaces e

cla;s~~ abstiatôS

r~

r~

Um lÍnico o-bjeto

Snowboard
equ?.ls (.
getClássf hasbC'.::.-ie:

Snowboard herda métodos

da superclasse Object e adiciona mais quatro.

. ~.

o

Snowboard

?J (/J'-V

turn( ) shred( ) getAir ( ) loseControl(

~~o . sn~O .

Há apenas UM objeto na pilba aqui. VW objeto Mas ele con~ém tanto partes referentes à classe Snowboa~ ~~anto partes referentes à classe Objecto
Snowboard~

'Polimorfismo' significa 'muitas formas' Você pode tratar um snowboard como um snowboard ou como um objeto.
Se uma referência é como um controle remoto, esse terá cada vez mais botões conforme você descer pela árvore de herança. Um controle remoto (referência) de tipo Object terá apenas alguns botões - os botões para os métodos expostos pela classe Object. Mas um controle remoto de tipo Snowboard incluirá todos os botões da classe Object, mais qualquer novo botão (para novos métodos) da classe Snowboard. Quanto mais específica a classe, mais botões ela poderá ter. É claro que isso nem sempre é verdade; uma subclasse pode não adicionar nenhum método no vo, mas simplesmente sobrepor os métodos de sua superclasse. O ponto-chave é que mesmo se o objero fo r do tipo Snowboard, lima referência de Object a esse objeto não terá como saber quais são os métodos específicos de Snowboard.

Quando você inserir um objeto em uma ArrayList<Object>, poderá tratá-lo somente como um tipo Object, independentemente do tipo que ele tinha quando foi inserido. Quando você capturar uma referência em ArrayList<Object>, ela terá sempre o tipo Object. Isso significa que você capturará um controle remoto de tipo Objecto

Object o

=

s;

o c ontrole remoco (referénciaJ SnOt-lboard tem ;mais botões do que um Controle rew~to Objecto Ele consegue enxez'g-ar a natureza completa do
-"-u7h - r lJj"etó bnOt9,Ooara.

o'iJ'
menos

~

Sno..J9
botões que c C!~nsr~lt!).
remnt0

poae

acessar coaos

os mé todos de Snot'lboa.rà . . inclu s ive o s métodos berdados de Object e às

A referencia Object s ó consegue ver as partes de tipo Object do objato Snow.board . Ela pode Eicessar somente os métodos aa elasl;€!
Obj$ct" Tem
m€LiOS

.cla sse SnowDoarc ..

Sn0T4oo;:ird.

você o.stá aqui

~

157

Convertendo uma referência de objeto novamente em seu tipo real.
Espere um minuto ... Qual a vantagem de se ter um objeto Oog se ele for capturado em ArrayList<Object> e não puder executar nenhum dos seus métodos? Tem que haver uma maneira de retornar o objeto Oog a seu estado original. ..

e
objeto

--------=-:--.

Continua sendo um ol~jeto Dog, mas se você quiser chamar seus métodos, precisará de uma referência declarada com o tipo Dog. Se tiver certeza* de que se trata realmente de um objeto Dog, você poderá criar uma nova referência Dog desse objeto copiando a referência Object e forçando essa cópia a entrar em uma variável de referência Dog, usando uma conversão (para Dog). Você pode usar a nova referência para chamar métodos de Dog.
converte o tipo Obj ect o = aI. get (index) ; Object novamente Dog d = (Dog) Oi ~ para um tipo Dog que sabemos d.roam()i estar aí~

Dog Converta o suposto tipo 'Object' (que sabemos na verdade ser um objeto Dog) para o tipo Dog, para que você possa tratá-lo como o objeto Dog que ele realmente é. "Se você não tiver certeza se é um objeto Dog, poderá usar o operador instanceof para verificar. Porque, se estiver errado quando fizer a conversão, verá uma exceção ClassCastException no tempo de execução e produzirá uma interrupção inesperada.
if (o instanceof Dog) Dog d = (Dog) o;

Portanto, agora você sabe o quanto o Java se preocupa com os métodos da classe da variável de referência.
Você só pode chamar um método em um objeto se a classe da variável de referência o tiver. Considere os métodos públicos de sua classe como um contrato, o que você se compromete a fazer para o mundo externo.
Quando criamos uma classe, quase sempre expomos alguns dos métodos a códigos externos a ela. Expor um método significa torná-lo acessível, geralmente marcando-o como público. Imagine esse cenário: você ec;tá escrevendo o código de um pequeno programa de contabilidade empresarial. Um aplicativo personalizado para a "Simon 's Surf Shop". Como está acostumado à reutilização, você encontrou uma classe Account que parece atender perfeitamente as necessidades, de acordo com sua documentação. Cada· instância de conta representa a conta de um cliente na loja. Portanto, aí está você, cuidando de sua tarefa, chamando os métodos credite ) e dehit( ) em um obj eto de conta quando percebe que precisa capturar o saldo de uma conta. Sem problemas - há um método getBalance( ) que deve atender satisfatoriamente.

158 f:8pítulo 8

interfaces e ciElsses abstratas

Porém ... Quando você chamou o método getBalance( ), o processo inteiro foi interrompido no tempo de execução. Esqueça a documentação, a classe não tem esse método. Droga! Mas isso não acontecerá realmente, porque sempre que você usar o operador ponto em uma referência (a.fazerAlgo( », o compilador examinará o tipo da referência (o tipo que 'a' foi declarado para ter) e verificará essa classe para se certificar se ela tem o método e se o método usa realmente o argumento que está sendo passado e retorna o tipo de valor que estamos esperando.

Account
debit(double amt} credit(double amt} double getBalance(}

Apenas lembre-se de que o compilador verifica a classe da variável de referência e não a classe do objeto real para o qual a referência aponta.

E se você tiver que alterar o contrato?
Certo, suponhamos que você fosse um objeto Dog. Sua classe Dog não é o único contrato que define quem você é. Lembre-se de que você herdará os métodos acessíveis (o que geralmente significa públicos) de todas as suas superclasses. É verdade que sua classe Dog define um contrato. Mas não todo o seu contrato.

Thdo que existir na classe Canine fará parte de seu contrato. Thdo que existir na classe Animal fará parte de seu contrato. Thdo que existir na classe Object fará parte de seu contrato.
De acordo com o teste É-UM, você é todas essas coisas Canino, Animal e Objeto.

Mas e se a pessoa que projetou sua classe tivesse em mente o programa de simulação de animais e agora quisesse usar você (a classe Dog) em um tutorial da feira de ciências sobre objetos Animal.
~~~c.

Tudo bem, talvez você possa ser reutilizado para isso. Entretanto, e se posteriormente ela quiser usá-lo no programa de uma Pet Shop? Você não tem nenhum comportamento de animal doméstico (Pet). Um objeto Pet precisa de métodos como serAmigável( ) e brincar( ).

Bem, agora suponhamos que você fosse o programador da classe Dog. Sem problemas, certo? Apenas adicione mais alguns métodos a ela. Você não estará prejudicando o código das outras pessoas adicionando métodos, já que não está mexendo nos . métodos existentes que outro código pode estar chamando em objetos Dog. Consegue identificar alguma desvantagem nessa abordagem? (Adicionar métodos de Pet à classe Dog?)

o

poder do cérebro

Pense no que VOCÊ faria se fosse o programador da classe Dog e precisasse alterá-la para que também pudesse ter métodos de Pet. Sabemos que simplesmente adicionar novos comportamentos (métodos) de Pet à classe Dog será satisfatório e não interromperá o código de ninguém. Mas ... Esse é o programa de uma Pet Shop. Ele tem mais d~ que apenas objetos Dog! E se alguém quiser usar sua classe Dog em um programa que tenha cães selvagens? Que opções você acha que teria, e sem se preocupar com a maneira como a Java manipula as coisas, apenas tente imaginar como gostaria de resolver o problema da alteração de algumas de suas classes Animal para incluir comportamentos de Pet. Faça uma pausa imediatamente e pense nisso, antes de olhar a próxima página onde começaremos a resolver o problema. (Tornando, portanto, o exercício completamente inútil, eliminando sua Grande Chance de queimar algumas calorias cerebrais.)

Examinemos algumas opções de projeto para a reutilização de algumas de nossas ~lasses-em-b..4+!-~mgPet... S;Hh-t'.o~p~.------

~Pt:"

Nas próximas páginas, vamos analisar algumas possibilidades. Ainda não estamos preocupados se o Java conseguirá realmente Jazer o que nos ocorrer. Estaremos avançando quando tivermos uma boa idéia de algumas correlações.

você está

?-

159


alterando
claSSE:S

exisientes

Q)

Opção um Tomaremos o caminho mais fácil e inseriremo s o s métodos de Pet na classe Animal. Vantagens: Todos os objetos Animal herdarão instantaneamente os comportamentos de Pet. Definitiv amente não teremos que mexer nas subclasses de Animal, de modo que qualquer subclasse de Animal criada no futuro também se beneficiará da vantagem de herdar esses métodos. Portanto, a classe Animal poderá ser usada como o tipo polimórfico de qualquer programa que queira tratar os objetos Animal como objetos Pet. Desvantagens: Bem . . . Quando foi a última vez que você viu um hipopótamo em uma loja de animais domésticos? E um l eão? Um lobo? poderia ser perigoso fornecer comportamentos de animal doméstico a animais selvagens, Além disso, é quase certo que tenhamos que mexer em classes de Pet como Dog e Cat, porque (pelo menos em nossa casa) os cães e gatos tendem a implementar comportamentos de animais domésticos de maneira MUITO diferente.

Ins.ira todos os cédigos dos métodos de Pet aqui para que sej a.m bs~dados .

®

insira todos o smétodos de Pe t ~ ~aqui . . mas sem ~~~"I"'!I"'!!~"P''"'!!!~~. . implementações. To rn e todos os . Vantagens: mé t odos de Pe t Isso nos p roporcionar i a todos os benef í cios da Opção Um, mas sem a desvantagem de termos animais se l vagens com comportamentos de animais domésticos (como serAmigável( )). Todas as classes de Animal teriam o método (por ter sido i nserido nessa classe), mas já que ele é abstrato as classes de animais selvagens não herdariam nenhuma funcionalidade. Todas as classes DEVEM sobrepor os métodos, mas podem torná-los "inúteis".

Opção dois Começaremos com a Opção Um, inserindo os métodos de Pet na classe Animal, mas os tornaremos abs t ratos, forçando as subclasses d e Animal a sobrepô-los.

Desvantagens : Já que os métodos de Pet são abstratos na classe Animal, as subclasses concretas de Animal serão forçadas a implementar todos eles. (Lembre-se de que os métodos abstratos DEVEM ser implementados pela primeira subclasse concreta da árvore de herança.) Que perda de tempo! Você terá que sentar e digitar cada método de Pet em cada classe concreta que não for de Pet e em todas as subclasses futuras. E embora isso resolva o problema de animais selvagens TEREM um comportamento de animais domésticos (o que aconteceria se eles herdassem a funcionalidade de Pet da c l asse Animal), o contrato não é satisfatório. Todas as classes de Animal anu n c i ar iam para todo mundo que também têm os comportamentos de Pet, ainda que na verdade eles não FAÇAM nada quando são chamados. Essa abordagem não parece nem um pouco adequada. Parece errado ins e rir tudo que mais de um tipo de animal pode p reci s a r na classe Animal, A MENOS que se aplique a TODAS as subclasses de Animal.

160 capítu lo 8.

interfaces e classes abstratas

® Opção i rtrês Inser os

rr:, ,~j :-'3: os métodos , de Pet SOMENTE Das classes de

métodos de Pet SOMENTE nas classes a que pertencem .

Vantagens: Não precisamos mais nos preocupar com hipopótamos nos recebendo na porta ou lambendo nosso rosto . Os métodos estão onde é o seu lugar e SOMENTE aí. Os obj etos Dog podem implementar os métodos e os objetos Cat também , mas ninguém mais pre c isa saber sobre eles. Desvantagens: Há dois grandes problemas nessa abordagem. Em primeiro lugar, você ter i a que concordar com um protocolo e todos os programadores d as classes Pet exist en tes em Animal a gora e no futuro teriam que CONHECER ess e protocolo . Por pro toco l o, queremos dizer os métodos e xatos que decidimos que todos os objetos Pet devem ter. O contrato de Pet sem nada que o registre. Mas e se um dos programadores o entendesse u m pouco mal? Como, um méto d o re c eper Str i ng quando p re c i sar de um in t? Ou se o nomearem doFr iendly( ) em vez de beFriendly( )? Já que não temos i sso em um cont r ato, o c ompi lador não ter á como ve r ific a r o que você fe z para s aber se os métodos foram implementados corretamente. Alguém poderia facilmente usar as classes Pet de Anima l e d escobr ir que nem toda s funcionam muito bem . E em segundo lugar, voc ê não poderá usar polimorfismo nos métodos de Pet . Toda classe que precisar usar os comportamen tos de Pet terá que sabe r da existência de cada classe diferente! Em outras palavras , você não poderá usar Animal como o tipo polimórfico agora, porque o compilador não permitirá que chame um método de Pet em uma referência de An ima l (mesmo s e e la for realmen te um objeto Dog) já que a c lass e Animal não tem o método.

MimaI que pud$rem ser animais domésticos, em vez de em PJlimal.

:

~- -

... ;

: ~'.".;:" .-.~

~E
~

'l ""

~~ --

criamos uma nova s uperclasse abstrata chamada Pat a forne cemos para eia todos o métodos de Pet. ~

Parece que precisamos de DUAS superclasses no topo da árvore

I'

Dog estende
tanto Pet quanto AnÍlnal. .

~-, - tenham os mesmos métodos definidos (mesmo nome,

~
.--

"

. ..

-

Então NA VERDADE precisamos de:
__ o

-<

~,

- Uma maneira de termos comportamentos de animal doméstico apenas em classes Pet - Uma maneira de garantir que todas as classes Pet

V"""-

- Uma maneira de nos beneficiarmos do polimorfismo ·~'I , pa:a que todos os objetos Pet possam ter seus ~_ _ .JJletodos chamados,- se,m-que_tenbamos q ue us.~____~ ~_ argumentos, tipos de retorno e matrizes específicos ...~ ~_; de cada classe Pet.

~~

~"I

'"

·A I .h

mesmos argumentos , mesmos tipos de retorno, nenhum método faltando, etc.), sem ser preciso cruzar os dedos e rezar para que todos os programadores pensem igual.
Cat

estende tanto

portanto usa os métodos das duas classes.

Os animais que não são domésticos não herdam
ndda de F",i;.

você esta aqui

to-

161

.,

herança múltipla?

Há apenas um problema na abordagem de '~~~as

~up~rclasses'~.~ . ___

. _ _ __ _

Chama-se "herança múltipla" e pode ser Algo Realmente Perigoso.
Isto é, se fosse possível ocorrer em Java. Mas não é, porque a herança múltipla apresenta um problema conhecido como O Losango Mortal.

Losango Mortal
DigitalRecorder
int i

Tanto CDBurner quanto DVDBurner h e rdam de DigitalRecorder e as duas classes sobrepõem o método burn( ). Ambas herdam a
variável de instância ni rT ..

Imagine se a var iável de i nstância Ui" for usada por CDBurner e DVDBurner, com valores diferentes. O que aconteceria se ComboDrive precisasse usar os dois valores
de "í# ?

,;~(::­

~-

CornboDrive

Problema da herança múltipla. Que método burn () será executado quando você chamar burn() em ComboDrive?

Uma linguagem que permita o Losango Mortal pode levar a algumas complexidades desagradáveis, porque você precisará de regras especiais para lidar com as possíveis ambigüidades. E regras adicionais significarão mais trabalho para você tanto no aprendizado dessas regras quanto na precaução contra esses "casso especiais". O Java foi projetada para ser simples, com regras consistentes que não travem em alguns cenários. Portanto, (diferente da C++) ela o protegerá de ter que pensar no Losango Mortal. Mas isso nos traz de volta ao problema original! Como manipularemos a questão AnimallPet?

A interface vem nos socorrer!
O Java lhe fornecerá uma solução. Uma inte/face. Não a interface de uma GUI, nem o uso genérico da palavra interface como em "essa é a interface pública para o APl da classe Button", mas a palavra-chave Java interface. Uma interface Java resolverá seu problema de herança múltipla fornecendo muitos dos benejlcios polimórficos desse tipo de herança sem a ameaça do Losango Mortal (DDD, Deadly Diamond of Death). A maneira como as interfaces se livram do DDD é surpreendentemente simples: elas tornam todos os métodos abstratos! Dessa forma, a subclasse terá que implementar os métodos (lembre-se de que os métodos abstratos devem ser implementados pela primeira subclasse concreta), portanto, no tempo de execução, a JVM não ficará confusa com relação a qual das duas versões herdadas deve chamar.
Pet
abstract void beFriendly( ); abstract v o id play( ) ;

~

!

!

Uma interface Java é como uma classe 100% abstrata.
Todos os métodos de uma interface são abstratos, portanto, qualquer classe que FOR-UM animal doméstico DEVE implementar (i.sto é, sobreporj os métodos de Fet.

Para definir uma interface:
public interface Pet { ... }
~--------

Use a palavra-chave l\interface~' em

'1're.z

de "clas s n

162 caRjtulo 8

interfaces e classes abstratas

~?"<.i-

Para implementar uma interface:
public class Dog extends Canine implements Pet

&~

Use a pa~avra-chave "implement s" seguida do nome da interface. Observe que, { ... } ( - - - - quando você implementar uma inter face, ainda poderá estender uma c~asse

Criando e implementando a interface de Pet
você
e scre~erá

public interface Pet { _____________ Todos os métodos da interfac e são abstratos, portant o, DEVEM t erminar c~n p o nto- e - vírgula . publ i c abstract void play (); ( _ _ _ _ _ _ _ _ _ _ _ _ Lembre-s e de que eles não t êm corpo!
~(

t

'interface' em vaz de

lclass' aqui

Os métodos da interrace são implicitamente públ icos e abstratos, portanto, digitar 'pub~ic' e 'abstract' é opc ional (na verdade, não é considerado um 'estilo adequado' digitar as pa~avras, mas fizemos isso aqui apenas para rerorçar e porque nunca fomos escravos de modismos •.. )

public abstract void beFriendly();

Cão É - UM anima~ e Cão É-UM animal doméstico

public class Dog extends Canine implements Pet public void beFriendly( ) { ... } publ ic v oid play () { .. }
,

{ ~(~----

Insira 'implements' seguido do nome da interface
DE'~

~4_____________________ _

4~___________________________

ser um objeto petr portanto implementar os métodos de Pet. É seu contr a t o. Observe as cbaves em vez do ponto e - vírgula. Você

dec ~arou

public v oid roam () { ... } ( ---------------------------- Esses são apenas métodos de publ ic void eat() ( ... ) ( sobreposição comuns.

- - - Não existem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Perguntas Idiotas
Espere um momento, as interfaces não fornecem realmente a herança múltipla, porque você não pode inserir qualquer código de implementação nelas. Se todos os métodos são abstratos, o que uma interface vai proporcionar realmente?
Polimorfismo, polimorfismo, polimorfismo. As interfaces são a última palavra em flexibilidade , porque, se você usá-Ias em vez das subclasses concretas (ou até mesmo tipos da superclasse abstrata) como argumentos e tipos de retorno, poderá passar qualquer coisa que implemente essa interface. E pense bem - com uma interface, a classe não tem que ser proveniente de apenas uma árvore de herança. Uma classe pode estender uma classe e implementar uma interface. Mas outra classe pode implementar a mesma interface, mesmo vindo de uma árvore de herança completamente diferente! Portanto, você poderá tratar um objeto pelo tipo de classe da qual foi instanciado. Na verdade, se você escrever um código que use interfaces, não terá nem mesmo que fornecer uma Superclasse a ser estendida . Poderá apenas fornecer a interface e dizer "veja, não me importo com o tipo de estrutura de herança de classes que lhe deu origem, apenas implemente essa interface e poderá continuar". O fato de você não poder inserir código de implementação deixa de ser um problema para a maioria dos bons projetistas, porque grande parte dos métodos da interface não faria sentido se implementada de uma maneira :·" genérica. Em outras palavras, a maioria dos métodos da interface teria que ser sobreposta mesmo se os métodos ~ ,iI-4,~. não fossem forçados a ser abstratos. você está aqui li" 163

R:

o polimorfismo da interface
Classe~

de árvo!.e~ ~e l!~rança diferentes podem implementar a mesma interface. _

A classe RoboDog não é proveni ent e da árvore de herança de Animal, ma.s mesmo assim pode fazer par te de Pet!

l

,

Quando você usar uma classe como um tipo polimórfico (como em uma matriz de tipo Animal ou um método que use um argumento de tipo Canine), os objetôs que poderá inserir nesse tipo devem ser provenientes da mesma árvore de herança. Mas não de qualquer local da árvore de herança; os objetos devem ser provenientes de uma classe que seja uma subclasse do tipo polimórfico. Um argumento de tipo Canine pode aceitar um objeto Wolf e um objeto Dog, mas não Cat ou Hippo. Mas quando você usar uma interface como um tipo polimórfico (como em uma matriz de objetos Pet), os objetos poderão ser provenientes de qualquer local da árvore de herança. O único requisito é que os objetos sejam provenientes de uma classe que implemente a interface. Permitir que classes de árvores de herança diferentes implementem uma interface comum é crucial no APl Java. Você quer que um objeto possa salvar seu estado em um arquivo? Implemente a interface Serializable. Precisa que os objetos executem seus métodos em um segmento separado? Implemente Runnable. Você deve ter entendido. Aprenderemos mais sobre Serializable e Runnable em capítulos posteriores, mas , por enquanto, lembre-se de que classes de qualquer local da árvore de herança podem ter que implementar essas interfaces. Quase qualquer classe pode ter que ser salva ou executada.

o melhor é que uma classe pode implementar
várias interfaces!
Um objeto Dog É-UM tipo Canine, É-UM tipo Animal e É-UM tipo Object, tudo através da herança. Mas Dog É-UM tipo Pet através da implementação da interface e esse objeto também pode implementar outras interfaces. Você poderia escrever:
public cla ss Dog extends Animal implements Pet, Sav eabl e, paintable { ... }
lrt

o Java

orne fácil lemb~ar

Wash

segmentosl Cat ~ wait() notify( )

Rosas são vermelh . """,' . as, VIoletas .sa-o azUIS . Estenda apenas ' uma, mas l/llplemente duas. O Java valoriza os valores familiares' ., A penas um progenitor' Un . ter apenas um pai ( . . la classe Java pode pai definirá quem vsu~e:classe) e essa classe . 1 oce e Mas v llTIp ementar VárI'as I·nt .; . oce .pode . . <. . " defInJrao as fUI . - . e1laces e essas.. ll1terfaces .
A

.

.

lfoe.\ que poderá d " . o

é.lar/penhar.

. 164 capitulo 8

interfaces e classes abstratas

}~ l~,

Como saber se você deve criar uma classe, uma subclasse, uma classe abstrata ou uma interface?
_ Crie uma classe que não estenda nada (a não ser Object) quando sua nova classe não passar no teste É-UM com nenhum outro tipo. _ Crie uma subclasse (em outras palavras, estenda uma classe) somente quando tiver que criar uma versão mais específica de uma classe e precisar sobrepor ou adicionar novos comportamentos. _ Use uma classe abstrata quando quiser definir um modelo para um grupo de subclasses e tiver pelo menos
algum código de implementação que todas as subclasses possam usar. Torne a classe abstrata quando quiser

garantir que ninguém possa criar objetos desse tipo. _ Use uma interface quando quiser definir umafunção que outras classes possam desempenhar, independentémente de onde essas classes estejam na árvore de herança.

Chamando um método na versão da superclasse
E se você criar uma subclasse . concreta e tiver que sobrepor um método, mas quiser o comportamento da versão do método existente na superclasse? Em -outras palavras, e se você não precisar substituir o método através de uma sobreposição e quiser apenas acrescentar a ele algum código específico adicional.

P:

a versão da superclasse abstract class Report ( para o méto do void runReport() ( ~----------------- executa tarera II configura relatório importante que as subclasses void printReport() ( poderiam usar II impressão genérica

c~ R: Vejamos ... Pense no significado da
palavra 'estender'. Há uma área para o desenvolvimento de um projeto adequado de 00 que cuida de como deve ser projetado um ~código concreto que tenha que ser sobreposto. Em outras palavras, você escreveu o código do .~ . método em, digamos, uma classe abstrata, que executa uma tarefa genérica o suficiente para dar suporte às implementações concretas comuns. Mas, o código concreto não é suficiente para manipular todas as tarefas - específicas da subclasse. Portanto, a subclasse sobreporá o método e o estenderá adicionando o resto do código. A palavra-chave super permitirá que você chame a versão da superclasse de um método sobreposto, de dentro da subclasse.
Se o código de um método existente d en t ro de uma sa.belasse BuzzwordRep ort ti ~7er;

class BuzzwordsReport extends Report (
~

chama versão da

superclasse e,
em seguida",

printReport() ;

______________ volta a executar a.1frv.:m.a. ); tarefa

<:

especifica da

subclasse void buzzwordCompliance() { ... }

método d a subclasse (sobrepõe a versão da
superclasse)

métodos da superclasse (inclusive o método runReport( ) sobreposto)

super.runReport(
o método runReport( ) da

)i

sUpercl asse Report será <executado

A .valavra-chave super é na . verdade uma xcafe::.... ê ncie a parte de um objeto relacionada à superclasBe~ Quando o código da subclasse
;;:;;,~IJJ:.I,J;.t:;::-=---­

Isso é

supe;,ç" .cunReport (

)

l'

a

da s1.1pe:z:classe pa.ra, o lntát o do

sezd executada .

você est<3.

165

('

discriminação dos pontos

DISCRIMINAÇÃO DOS PONTOS
- Quando você não quiser que uma classe seja instanciada (em outras palavras, não quiser que ninguém crie um novo objeto desse tipo de classe) marque-a com a palavra-chave abstracto - Uma classe abstrata pode ter tanto métodos abst:ratos quanto não-abstratos. - Se uma classe tiver ao menos um método abstrato, ela deve ser marcada como abstrata. - O método abstrato não tem corpo e a declaração termina com ponto-evírgula (não há chaves). - Todos os métodos abstratos devem ser implementados na primeira subclasse concreta da árvore de herança. - Toda classe em Java é uma subclasse direta ou indireta da classe Object (java.lang.Object). - Os métodos podem ser declarados com argumentos e/ou tipos de retomo de Object. - Você só poderá chamar métodos em um objeto se eles existirem na classe (ou intelface) usada como o tipo da variável de referência, independentemente do tipo real do objeto. Portanto, uma variável de referência de tipo Object só poderá ser usada para chamar métodos definidos na classe Object, a despeito do tipo do objeto para o qual a referência apontar. - Uma variável de referência de- tipo Object não pode ser atlibuída a qualquer outro tipo de referência sem uma conversão. A conversão pode ser usada para atribuir uma variável de referência de um tipo a uma variável de referência de um subtipo, mas no tempo de execução a conversão falhará se o objeto da pilha NÃO for de um tipo compatível com ela. Exemplo: Dog d = (Dog) x.getObject(aDog); - Todos os objetos capturados em ArrayList<Object> terão o tipo Object (o que significa que só poderão ser referenciados por uma variável de referência Object, a menos que você use uma conversão). - A herança múltipla não é permitida em Java, por causa dos problemas associados ao "Losango Mortal". Isso significa que você só poderá estender uma classe (isto é, só poderá ter uma superclasse imediata). - Uma interface é como uma classe abstrata 100% pura. Ela só define métodos abstratos. - Crie uma interface usando a palavra-chave interface em vez da palavra class. - Implemente uma interface usando a palavra-chave implements Exemplo: Dog implements Pet - Sua classe poderá implementar várias interfaces. - Uma classe que implementar uma interface deve implementar todos os métodos dessa interface, já que eles serão implicitamente públicos e abstratos. - Para chamar um método com a versão da superclasse a partir de uma subclasse que o tenha sobreposto, use a palavra-chave super. Exemplo: super.runReport( );

Ainda há algo estranho aqui. .. Você não explicou por que ArrayList<Oog> retorna referências de Oog que não precisam ser convertidas, ainda que a classe ArrayList use Object em seus métodos e não Oog (ou OotCom ou qualquer outra coisa). Que truque especial usamos quando escrevemos ArrayList<Oog>?
Você está certo em chamar isso de truque especial. É realmente um truque especial ArrayList<Oog> retornar objetos Oog sem que nenhuma conversão seja necessária, já que os métodos de ArrayList parecem não saber nada sobre Oog ou qualquer tipo que não seja Object. Uma resposta rápida seria que o compilador gerará a conversão para você! Quando você usar ArrayList<Oog>, não haverá uma classe especial com métodos que usem e retornem objetos Oog , mas em vez disso; <Oog> sinalizará para o compilador que você deseja que ele lhe permita inserir SOMENTE objetos Dog e que o impeça se tentar adicionar qualquer outro tipo à lista. E já que o compilador o impedirá de adicionar algo que não seja um objeto Oog a ArrayList, ele também saberá que é seguro converter qualquer coisa proveniente dessa ArrayList em uma referência Oog. Em outras palavras, usar ArrayList<Oog> o poupará de ter que converter o objeto Oog que você capturar. Mas é muito mais importante que isso ... Porque lembre-se de que uma conversão pode falhar no tempo de execução, de modo que não seria melhor que seus erros ocorressem no tempo de compilação do que, digamos, quando seu cliente estiver usando o código para algo crítico? Mas há muito mais detalhes nessa estória e examinaremos todos no capítulo sobre objetos Collection.

't": "'"' -

R:

166 capítu lo 8

interfaces e classes abstratas

Aqui está uma chance de demonstrar suas habilidades artísticas? À esquerda você encontrará conjuntos de declarações de classe e interface. Sua tarefa é desenhar os diagramas de classe associados à direita. Fizemos o prime iro para você. Use uma linha tracejada para representar "implements" e uma sólida para "'extends".

Dado:
1)

Qual é o cenário?
1)
2)

public interface Foo { } public class Bar implements Foo { }

2)

public interface Vinn { } public abstract class Vout implements vinn { }

3)

public abstract class Muffie implements Whuff ie { } public class Fluffie ext ends Muffie { } public interface Whuffie { }

3)

4)

4) public class Zoop { } public class Boop extends Zoop public class Goop extends Boop

5)

~~.:,.-­

,h
#~

public public public public public

class Gamma extends Delta implements Epsilon { } interface Epsilon { } interface Beta { } c l ass Alpha extends Gamma implements Beta { } class De l ta { }

5)

"k h-~­
,~h
"

À esquerda você encontrará conjuntos de diagramas de classes. Sua tarefa é convertê-los em declarações Java válidas. Fizemos o número 1 para você Ce foi difícil) .

Convenções

.~~

Dado:
3)


>

extends

I I I I ICl'ack I
Clack
Clack

classe interface classe abstrata

4)

5)

Click

Fee

Al

I~

9
Bai!:"

I

I
Alpha

Clack

Fi

,,
A~

,

I

'

....

Baz

Delta

2)

eL.:;':

.~\_._ __

_ __ __ _ _ _ _

4)

5)

'/Oce está aqu: ..

167

~uebra-cabeças
~

na Piscina ~.
-- - - - - - (.
. '-'

--

Sua tareIa. é pegar os trechos de código da piscina e in seri- los nas linhas em branco do cód igo e da saída. v Você pode usar o mesmo tTecho mais de uma vez e não . precisa empregar todos os trechos. Seu objetivo é criar ) uma classe que seja compi lada e executada produzindo a saída listada.

Nose {

abstract c1ass Picasso imp1ements ______ i return 7;

c1ass c1ass return 5;

pub1ic

extends C10wns ( (

pub1ic static void main(String [] args)

i [O] new i [1] new ________ new ________ i [2] for(int x = O; x < 3; x++) System . out . print1n (_ __ __ _ _ _ __

+

"

\\

+ ____ . getC1ass(

) );

Sa í da

Nota: cada trecho de código da piscina pode ser usado mais de uma vez!

) ;

Nose(
0f76 (

) ;
) ;

c1ass extends interface imp1ements
) ;

C1owns( Picasso(

) ;

3

i = new Nose[3]; i; ] i new Nose( ) ; ] i = new Nose[3] ;

c1ass i 5 c1ass Acts i ( ) 7 c1ass Nose i(x) 7 pub1ic class 0f76 i [x] C10wns pub1ic int iMethod( ) Picasso pub1ic i.nt iMethod ( ) i . iMethod(x) ) publi.c int i (x) . iMethod [ )

168 capitu!ü 8

interfaces e

cl~sses

abstratas

Qual é o cenário?
2

Qual é a declaração?
3

(interface) vinn

(interface) W1luffie

2) public abstract class Top { } public class Tip extends Top (

~

3) public abstract class Fee { }

public abstract class Fi extends Fee { }

I
Muffie
4)
' {. "

I ':"

public interface Foo { } public class Bar implements Foo { public class Baz extends Bar { }

II'
5)


)..., .

O
' 4

public interface Zeta { } public class Alpha implements Zeta ( ) public interface Beta ( ) public class Delta extends Alpha implements Beta { }

)--<
\L~

Zoop

5

JI'

O

(interface)
Epsilon

Boop

,1:.;, ~k-:
\.
'

"

/
(interface)
Beta

Gamma

lI'

~ .Solução do Quebra-cabeças
interface Nose { public int iMethod( abstract class Picasso implements Nose { public int iMethod( return 7; public C lass Of76 extends Clowns ( public static void main(String [) args) Nose [ ] i = new Nose [3] ; irO) new Acts ( ); i [1) = new Clowns ( ) ; i[2) = new Of76 ( ) ; for(int x = O; x < 3; x++) { System , out,print ln(i [ x] iMethod( + " " + i [x] ,getClass( ) );

class Clowns extends Picasso ( ) class Acts extends Picasso } pu-ol.i.C-iJ::l.-LiMe.thod ( .- --------------------. )------return 5;

você està aqui

~

169

:"~.'"'~
. ".

.. _ r

':r..d [: .. ~ ~

9 construtores e coiets de líxo

Vida e Morte de um Objeto

... então ele disse, "Não consigo sentir minhas pernas!" e eu disse "Joe! Fique comigo Joe!" Mas era ... Tarde demais. O coletor de lixo veio e ... Ele se foi. O melhor

Objetos nascem e objetos morrem. Você é quem manda no
ciclo de vida de um objeto. Decide quando e como construí-los. Também decide quando destruí-los. Exceto pelo fato de não ser você próprio que destruirá realmente o objeto, apenas o abandonará. Mas quando ele for abandonado, o desalmado Coletor de Lixo (ge,
garbage eolleetor) poderá eliminá-lo, solicitando a memória que o

objeto estava usando. Quando você empregar a Java, criará objetos. / Cedo ou tarde, terá que permitir que alguns deles sejam eliminados ou estará se arriscando a ficar com pouca RAM. Neste capítulo examinaremos como os objetos são criados, onde residem enquanto estão ativos e como manter ou abandoná-los eficientemente. Isso significa que falaremos sobre o heap, a pilha , o escopo, construtores, superconstrutores, referências nulas e muito mais. Aviso: o capítulo contém material sobre a morte de objetos que algumas pessoas podem achar perturbador. Melhor não se deixar impressionar muito.

este é um novo capítulo

171

a pilha e o heap

A pilha e o heap: onde as

coisfu,~esideiT,---com isso. E com uma programação adequada, provavelmente você não terá problemas (veremos mais sobre esse assunto um pouco mais à frente). Sabemos que todos os objetos residem na pilha de lixo coletável, mas ainda não examinamos onde as variáveis residem. E o local onde uma variável irá residir vai depender da espécie dessa variável. Por "espécie", não queremos dizer tipo (isto é, primitivo ou referência de objeto). A duas espécies de variável com as quais nos preocuparemos agora são as variáveis de instância e as variáveis locais. As variáveis locais também são conhecidas como variáveis de pilha, o que é uma boa pista de onde elas residem.

Antes de conseguirmos compreender o que ocorre realmente quando criamos um objeto, temos que retroceder um pouco. Precisamos aprender mais sobre onde tudo reside (e por quanto tempo) em Java. Isso significa que precisamos aprender mais sobre a Pilha e o Heap. Em Java, nós (os programadores) nos preocupamos com duas áreas da memória - aquela em que os objetos residem (o heap) e aquela em que as chamadas de método e as variáveis locais residem (a pilha). Quando uma JVM é iniciada, ela captura um bloco de memória do sistema operacional subjacente e o usa para executar o prog.rama Java. A quantidade de memória, e se é possível ou não ajustá-la, vai depender de que versão da JVM (e em que plataforma) você estiver executando. Mas geralmente não é preciso se preocupar

A Pilha
Onde as chamadas de método e as va riáveis locais residem

o Heap
Onde todos os objetos residem
tamL-'ém conheciào como "Pilh a / ' de Lixo Coletá'vel fi

Variáveis de instância
As variáveis de instância são declaradas dentro de uma classe, mas não dentro de um método. Elas representam os "campos" que cada objeto individual tem (que podem ser preenchidos com valores diferentes para cada instância da classe). As variáveis de instância residem dentro do objeto a que pertencem.

Variáveis locais
As variáveis locais são declaradas dentro de um método, inclusive como parâmetros do método. Elas são temporárias e só existem enquanto o método está na pilha (em outras palavras, enquanto o método não alcançar a chave de fechamento).

public class Duck { int size;

Toclo ob:feto Duck tem

uma 'v ariável de

public void foo(int x) int i = x + 3; boolean b = true;

o parâmetro x e as variáveis i e
b são todos

Os métodos são empilhados
Quando você chamar um método, ele será inserido no topo de uma pilha de chamadas. Esse novo item que na verdade é empurrado para a pilha é o ponteiro da pilha e ele contém o estado do método inclusive que linha de código está executando e os valores de todas as variáveis locais.

Uma pilha de chamadas com dois métodos
ponce.ires das pilhas

topo da pilha

o método no topo da pilha é sempre o que está sendo executado atualmente para essa pilha (por enquanto, presumiremos que há apenas uma pilha, mas no Capítulo 14 adicionaremos mais). Um método permanece na pilha até atingir sua chave de fechamento (o que significa que ele foi concluído). Se o método foo( ) chamar o método bar(), esse será empi lhado acima defoo() .
172·-· tapítulo 9

Fim ôa p.:í. . Lh . ::l .

v'a:r:i ;:flve.i

~:;!

o método no topo da pilha é sempre aquele que está sendo executado atualmente.

construtores e coleta el e lixo

c k=

k
,k

publi c void doStuff() boolean b = true ; go(4) ;

o cenário de uma pilha
o código à esquerda é um bloco (não nos preocupamos com a aparência do resto da classe) com três métodos. O primeiro método (doStufj()) chama o segundo (go()) e o seg undo chama o terceiro (crazy()) . Cada método declara uma variáve l local dentro do corpo do método e o método go() também decl ara lima variável de parâmetro (o que significa que go() tem duas variáveis locais).

k
. .k.
,~

L :')...,.
.1......

public void go(int x) ( int z = x + 24; crazy () ; II imagine mais código aqui

public void crazy () char c = 'a';

.J-~..
.,;~

'h:

h

:1

(!) um código de outra classe chama o método doStuff( ) e esse é inserido em um pontei ro no topo da pilha . A variável booleana chamada ' b ' é inserida no ponteiro de pilha de
doStuff ( ).

®dOStuff( ) chama go( ) . go( ) é empurrado

®gO(

para o topo da pilha . As variáveis 'x' e ' z ' estão no ponteiro de pilha de go( ) .

) chama crazy( ) . Ago ra crazy( ) está no topo da pilha, com a variável \ c ' no ponteiro .

~crazy( ) é conc:uído
e seu ponte~ro e retirado da pilha. A execução retorna pra o método go( ) e prossegue na linha seguinte à chamada de crazy( ) .

-I

~~

IA

f

:-aÕSt uff () .
-~

.s,;:

':m'
-

J"

[~
P:

~.

t ~:

l~

E quanto às variáveis locais que forem objetos?
Lembre-se, uma variável não-primitiva armazena a referência a um objeto e não o próprio objeto. Você já sabe onde os objetos residem - no heap. Não importa onde eles forem declarados ou criados. Se a variável local for uma referência a um objeto, só a variável (a referência!controle remoto) entrará na pilha.
O objeto propriamente dito continuará
/1.0

heap.

barf (} declara e cria uma nova variável de referência ' d' do objeto Duck (já que ela é declarada dentro do método, é ~~ variável local e será inserida na pilha).

public class StackRef public void foof( ) barf();

public void barf() { Duck d new Duck(24);

Não existem

Perguntas Idiotas

a variável de Não referência do objeto ror declarada (dentro de um método ou como a variável de instância de uma classe) o objeto sempre será inserido no heap.

Mais uma vez, POR QUE estamos examinando o assunto da pilha/heap? Em que ele me ajudará? Preciso realmente aprender isso?
Conhecer os aspectos básicos da Pilha e do Heap em Java será crucial se você quiser compreender o escopo das variáveis, questões relacionadas à criação de objetos, o gerenciamento da memória, segmentos e a manipulação de exceções . Abordaremos os segmentos e a manipulação de exceções em capítulos posteriores, mas o~ o~tros assuntos você aprenderá neste capítulo. Não é preciso saber cada detalhe sobre como a Pilha e o Heap ~~o IrtlpLementados_eJILqlLalq uer JVM _ e/ou plataforma específica. Tudo que você precisa saber sobre a Pilh?_e o ~I Heap está nesta página e na anterior. Se memorizar estas páginas , todos os outros tópicos que dependerem do ri(~' conhecimento do assunto ficarão muito mais fáceis. Novamente, algum dia você nos agradecerá MUITO por lhe iD-- termos forçado a estudá-lo.

R:

.J-

você está aqui 1>

173

referências de objeto n2 pona

. - DISCRIMINAÇÃO DOS PONTOS
- O Java tem duas áreas de memória com as quais nos preocuparemos: a Pilha e o Heap. - As variáveis de instância são variáveis declaradas dentro de uma classe, porém fora de qu alquer método. - As variáve is locais são variáveis declaradas dentro de um método ou como seu parâmetro. - Todas as variáveis locais residem na pilha, no ponteiro correspondente ao método onde foram decl aradas. - As variáveis de referência de objeto funcionam·exatamente como as variáveis primitivas uma variável local, ela será in serida na pilha. se a referência for declarada como

- Todos os objetos residem no heap, independententente de a referência ser uma variáve1local ou de instância.

Se as variáveis locais residem na pilha, onde residem as variáveis de instância?
Se você escrever new CellPhoneO, o Java terá que fazer espaço no Heap para esse objeto CellPhone. Mas qual o tamanho do espaço? Suficiente para o objeto, o que significa o bastante para armazenar todas as ·suas variáveis de instância. É isso que ocorre, as variáveis de instância residem no Heap, dentro do objeto a que pertencem. Lembre-se de que os valores das variáveis de instância de um objeto residem dentro do objeto. Se as variáveis de instância forem todas primitivas, o Java criará espaço para elas com base no tipo primitivo. Um int precjsará de 32 bits, um longo de 64 bits, etc. O Java não se importa com o valor existente dentro das variáveis primitivas; a quantidade de bits de uma variável de tipo int será o mesmo (32 bits) se o valor do inteiro for 32.000.000 ou 32. Mas e se as variáveis de instância forem objetos? E se CellPhone FOR_UM objeto Antenna? Em outras palavras, se CellPhone tiver uma valiável de referência de tipo Antenna. Se o novo objeto tiver variáveis de instância que forem referências de objeto em vez de tipos primitivos, a dúvida real será: ele precisa de espaço para todos os objetos cujas referências armazena? A resposta é não exatamente. De qualquer forma, o Java terá que destinar espaço para os valores das valiáveis de instância. Mas lembre-se de que o valor de uma variável de referência não é o próprio objeto, mas apenas seu controle remoto . Portanto, se CellPhone ti ver uma variável de instância declarada como um tipo não-primitivo Antenna, o Java fará espaço dentro do objeto CellPhone somente para o controle remoto (i sto é, a variável de referência) de Antenna e não para o objeto Antenna. Bem, então quando o objeto Antenna terá espaço no Heap? Primeiro temos que descobrir quando o próplio objeto Antenn a foi criado. Isso vai depender da declaração da variável de in stância. Se a variável de in stância for declarada, mas nenhum .. objeto for atribuído a ela, então, só o espaço para a variável de referência (o controle remoto) será criado.
private Antenna ant;

objeto CellPhone

- ;

Objeto com duas variáveis de instância primitivas. o espz:.çc pElrz. ;:;:; 't."l:riávei::; resida ü'::' objeto ..

objeto CellPhone

Objeto com uma 'trsríável de i.nstância n§opri miti"{ra, -- uma re.:f"erência. a um objeto ..,l intenna, mas nenhum avjeto A.~tgnna real. Isso é o que você obtérá se declarar a varíáve~1 mas não inicializá-la com um objeto Antenna real. pub l ic class Cel l Phone ( privat e Antenna ant;

objeto CellPhone

objeto Antenna

Objetc com urna varíável de instância náoprimitiva e a variavel Antenna sendo
p.t:rih!Jide a. um
nc~"~

Nenhum objeto Antenna real será criado no Heap, a menos ou até qu e a variável de referência receba um novo objeto Antenna.
private Antenna ant = new Antenna();

objeto

}~;ter_'l2.

public c la ss Ce ll Phone private Antenna ant

=

l"lew Antenna() ;

174 capitula 9

construtores e coieta de Ii;:<o

o milagre da criação de objetos
Agora que você sabe onde as variáveis e objetos residem, podemos entrar no misterioso mundo da criação de objetos. Você deve se lembrar das três etapas de declaração e atrib uição de objetos: declarar uma variável de referência, criar um objeto e atribuir o objeto à referência. Mas até agora, a etapa dois -- onde um milagre ocorre e o novo objeto " nasce" -- permanece sendo um Grande Mistério. Prepare-se para aprender os fatos referentes à vida dos objetos. Espero que você não seja

i

~~

muito sensível.

I
I

Recapitule as 3 etapas de declaração, criação e atribuição de objetos:
cria uma nova variável de re ferência com o tipo de uma classe ou interface .

!~
~ Declare uma variável de referência
Duck rnyDuck = new Duck ( ) ;

f

ir'Y
f~
Um

t~

~ mvJ
referência de Duck

.1~:tL-

milagre ocorre aqui.....-) G

Crie um objeto
Duck myDuck =

new Duck ( ) ;

objeto Duck

Atribui o novo objeto à r eferência.

~ Vincule o objeto e a referência
Duck myDuck ® new Duck ( ) ;

referência de Duck

~-_ . -

,

..

· j!'Wh"·~ -_ ·

~.

t,-~_-- Estamos chamando um método de nome Duck( )?
~:~-

Porque parece realmente que estamos.
Duck myDuck

new Duc k ();

<:___________________

Parece que estamos chamando lli~ método de nome Duck( ), por causa dos parênteses.

Não. Estamos chamando o construtor de Duck.
Um construtor realmente se parece muito com um método, mas não é um método. Ele contém o código que será executado quando você escrever new no código. Em outras palavras, o código que será executado

quando você instanciar um objeto.
Um CONSTRUTOR contém o código que será executado quando você instanciar um objeto. Em outras palavras, o código que será executado quando você escrever new em um tipo de classe. TOda classe que for criada terá um construtor, mesmo se não for você que o escrever. A única maneira de chamar um construtor é com a palavra-chave new seguida do nome da classe. A JVM encontrará essa classe e chamará seu construtor. (Certo, tecnicamente essa não é a única maneira de chamar ='I"'\-um Construtor. Mas é o únkõ-úi.õdo de fazê-io de.Tora de um construtor. Você/Jo(te chamar um constru tor de .. ~k . dentro de outro construtor, com restrições, mas abordaremos isso posteriormente no capítulo.)

'lif'r;--voce está aqui ~ 175
_. ...........

--

\

construindo um novo

Ob)8tO

UL,ck

Mas onde está o construtor? Se não o escrevemos, quem o fez?
Você pode criar um construtor para sua classe (estamos perto de fazer isso), mas se não o fizer, o compilador criará um! Veja a aparência do construtor padrão do compilador:
public Duck() (

Notou algo faltando? Em que isso é diferente de um método?
Onde es tá o tipo de retorno? Se isso fosse um método" 'r'ocê preci saria d e um t ipo de retorno

en're

"p~r e ~
Duck() {

S e u nome é igual ao nome d a cla sse . Is so é obr iga tório.

~.

public

//0 código do construtor en tra aqui

Construa um objeto Duck o recurso-chave do construtor é que ele é executado antes de o objeto
poder ser atribuído a uma referência. Isso significa que você poderá interferir e fazer o que for preciso para deixar o objeto pronto para uso. Em outras palavras, antes de alguém poder usar o controle remoto de um objeto, este terá uma chance de ajudar na sua própria construção. No construtor de nosso objeto Duck, não estamos fazendo nada de útil, mas ele demonstra a seqüência de eventos.
public class Duck ( public Duck() ( System. out .println ("Qu ack" );

'E-----------

código do

o construtor lhe dará a
chance de entrar no meio da execução de new.

con strutor ..

public c lass Us eADuck public static void main (String[) args) Duck d = new Duck(); (
Is s o chamará o construtor de ~uck.

~ .......

~'",:Aponte
,< ,,~

seu lápis..._ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _- ,

Um construtor lhe permitirá entrar no meio da etapa de criação do objeto - dentro da execução de nev.'. Consegue identificar condições em que isso seria úti l? Quais dessas opções poderiam ser útei s no construtor de uma classe Car, se ela fizer parte de um Jogo de Corrida? Marque aquelas para as quais penso u em um cenário .

- Incrementar um contador para registrar quantos objetos desse tipo de classe foram criados. - Atribuir um estado específico do te mpo de execução (dados sobre o que está ocorrendo AGORA). - Atribuir valores às variáveis de ill sLâm:ia importantes do objeto. - Capturar e sal var uma referência do objeto que está criando o novo objelo. - Adicionar o objeto a uma ArrayList. - Criar obietos que passem no lesle TEM-UM. _ _ _ __ _ _ _~ (sua idéia ent ra aqui)
~.
.1

!~';'

. 176

C3pituío~

-9 .

construtores e coleIa

lixo

~f~

·K

Inicializando o estado de um novo objeto Duck
A maioria das pessoas usa construtores para inicializar o estado de um objeto. Em outras palavras, para criar e atribuir valores às variáveis de instância do objeto.
publ i c Duck ( ) size = 34;

Não existem

~~~-

Perguntas Idiotas
Por que é preciso criar um construtor se o compilador criará um para você? Se você precisar de um código que ajude a inicializar seu objeto e torná-lo pronto para uso, terá que criar seu próprio construtor. Você pode, por exemplo, depender de entradas do usuário antes de poder concluir a preparação do objeto. Há outra razão para ter que criar um construtor, mesmo se você mesmo não precisar de nenhum código de construtor. Está relacionada ao construtor de sua superclasse e falaremos sobre isso em breve. Como distinguir um construtor de um método? Você também pode ter um método com o mesmo nome da classe? A Java permite que você declare um método com o mesmo nome de sua classe. No entanto, isso não o tornará um construtor. O que diferencia um método de um construtor é o tipo de retorno. Os métodos devem ter um tipo de retorno, mas os construtores não podem ter um tipo de retorno. OS construtores são herdados? Se não fornecermos um construtor, mas nossa superclasse o fizer, usaremos o construtor da superclasse em vez do padrão? Não. Os construtores não são herdados. Examinaremos isso algumas páginas à frente.

P: R:

~.

~t
~~l4::~~
'+..f~. ('~/

Isso não será problema quando o desenvolvedor da classe Duck souber o tamanho que o objeto Duck deve ter. Mas e se quisermos que o programador que está usando Duck decida o tamanho que um objeto Duck específico deve ter? Suponhamos que o objeto Duck tivesse uma variável de instância para o tamanho (size) e você quisesse que o programador usasse sua classe Duck para configurar o tamanho do novo objeto Duck. Como faria isso? Bem, você poderia adicionar um método de configuração setSizeO à classe. Mas isso deixaria o objeto Duck temporariamente sem um tamanho* e forçaria o usuário de Duck a escrever duas instruções uma para criar o objeto Duck e outra para chamar o método setSizeO. O código abaixo usa um método de configuração para definir o tamanho inicial do novo objeto Duck.
public class Duck ( int size; public Duck () System . out.println("Quack");

~"
)~ J. ~~
~.~

P:

',;;.[,,=-'.:'."''' " :.'' :\' :
~

.,

~..•:•.
':l..~

,I 'C~

'n ~~ ~
...,1
~~-o-

!
'ij

variável de instância
~L-_ _ _

R:

construtor método de

.; ~ '_.

frt. ,. :l!':,

~h~

public void setSize(int newSize) size = newSize;

(~---- configuração

P:

}.~f· ~.

public class UseADuck public static void main (String [l Duck d = new Duck(); d . setSize(42) ; args) (

;~\\'"~' .:
'\
1.~

,;"

<r~'

R:

~~~
"I.c'"-i
n.

~

~=-~~~

.~~

Há a'go arrado ali. O objeco Duok j ' foi ori,do aoa •• poneo do código, aa. c_anho!' Portaneo, est á confiando no fato do usuário de Duck SABER que a c riação do objeto Duck é lli~ processe de duas partes: uma para chamar o construtor e outra para cha:nar o mé todo de conf.iguração.

~a ~

=0'

.~-

,~
){
~f
~

::JIJ~

"L.

'Na verdade, as variáveis de instância têm um valor padrão. as booleanas e nulo para referências.

°

ou 0,0 para variáveis primitivas numéricas, falso para

~~" •...

:~ ~
~

Usando o construtor para inicializar um estado .importante de Duck*
Já que um objeto não deve ser usado até uma ou mais partes de seu estado (variáveis de instância) terem sido inicializadas, não deixe ninguém criar um objeto Duck até que você tenha concluído sua inicialização! Pode ser arriscado demais permitir que alguém crie - e use uma referência de -- um novo objeto Duck que ainda não esteja totalmente pronto para uso até essa pessoa resolver chamar o método setSize() . Como o usuário ele Duck vai saber que precisa chamar o método ~- de configüração depois de-CITai o novo obj-eto-Bnek-?- - - -"-O melhor local para inserir o código de inicialização é 110 construtor. E tudo que
"Não quer dizer que nem todo estado de Duck não seja irrelevante.

.

i:,

r-='"
10
~ .'

-1-

-h··::'...· .. você terá que fazer será criar um construtor com argumentos.

você eshJ

177

/

inici alizando o estEic!C

'JD

~

public class Duck {
..LnL s.i z e;

':{--

publ i c Duck(int duckSize) ( '7---System.out . println("Quack") ; siz e
=

----------

;::ii~.io::;: o"r, ";-a.::;ó;...··",;it::C

':'nt zc

Çr.;·"'::l:·.;tC::; d~ I..;:;:.:;]:.

;:{

21'

duck Si ze ;

System . out.println("O tamanho é igual a " + size);

pub l ic c lass UseADuck p ublic sta tic v o i d main (Str ing [l a r g,,) ( Pa.ssa um va1.or Duck d = new Du ck( 4 2) ; ~------------------

~

par~

o

consc~tor.

Dessa vez há apenas uma instruçi:o. Criaremos o nC1--O objer:o
configuraremos seu taman.ho em u..-na i:Istn.:ção.

Duck e

r.=.-:

Torne fácil a criação de um objeto Duck
Certifique-se de ter um construtor sem argumentos

o que aconteceria se o construtor de Duck usasse um argumento? Pense nisso. Na página anterior, há apenas um construtor de Duck - e ele usa um argumento int para o tamanho do objeto Duck. Talvez isso não seja um grande problema, mas com certeza ficará mais difícil para um programador criar um novo objeto Duck, principalmente se ele não souber qual deve ser o tamanho de um objeto Duck. Não seria útil termos um tamanho padrão para o objeto Duck, para que quando o usuário não souber qual o tamanho apropriado, ainda possa criar um objeto Duck que funcione?
Suponhamos que você quisesse que os usuários de Duck tivessem DUA S opções para a criação de um objeto Duck - uma em que eles fornecessem o tamanho de Duck (como o argumento do construtor) e outra em que não especificassem um tamanho e portanto usassem o tamanho padrão que você definiu para Duck.
Você não pode fazer isso corretamente com apenas um construtor. Lembre-se de que , se um método (ou construtor - as regras são iguais) tiver um parâmetro, você deve passar um argumento apropriado quando chamar esse método ou construtor. Não pode apenas dizer "se algu ém não passar nada para o con strutor. use o tamanho padrão", porque eles não conseguirão nem mesmo compilar sem enviar um argumento int para a chamada do construtor. Você poderia fazer algo complicado como o descrito a seguir:
pub l ic cl ass Duck ( int s iz e ; publ i c Duck(int newSize) if (newS i ze = = O) { ~( ~-----------­ s ize = 2 7 ; el se { size = newSize ;
Se o ;ralor do parâmetro

Você quer ter DUAS maneiras de criar um novo objetoDuck:
public class Duck2 { i nt size; p ublic Duck2 ( ) II fo rn ece o tamanho p adr ão size = 2 7;

public Duck2 (int duckSize) ( II usa o parâmetro duckSize size = duckSize;

Para criar um objeto Duck quando você souber o tamanho:
Duck2 d
=

for zero, forneça ao novo cbjeto Duck um ~ama~~o padrâo 4 caso contrário use c va2cr do parâ~etro como [) tamanho " Esse!. NÃ.O é uma so~uçâo muito boa.

new Duck2(15);

Para criar um objeto Duck quando você não souber o tamanho:
Duck2 42
=

new Du c k2();

Mas isso signifi ca que o program ador que cri ar um novo obj eto Duck terá que saher que passar um " O" é o protocolo para o uso elo tamanho padrão ele Duck. Muito ruim. E se o outro programador não souber di sso? Ou se ele quiser realrnenle urn objeto D uck de tamanho zero? (Supondo que um objeto Duck de tamanh o zero seja permitido . Se você não quiser objetos Duck de tamanho zero, in sira um códi go de validação no construtor para impedir isso.) O probl ema é que talvez nem sempre seja possível distinguir entre um argumento genuín o do tipo "quero zero para o tamanho" e um argumento "estou enviando zero, portan to você me fo rnecerá o ta manh o padrão, qualquer que seja" .

Portanto , essa idéia de ter du as opções para se cri ar um obj etc Duck precisa de dois con strutores. Un·. , Iue use um int e () outro não. Se J'(,cé f,, '[,(" mais de um construtor em uma Ch>:,e, isso .; significa que tem construtores

sobrecarregados.

H8;-. capítuí o 9

construtores c:; coleia rie lixo

o compilador não criará sempre um construtor
sem argumentos para mim?
Você pode ac har que se criar sOJllente um construtor com argume ntos , o compilador ve rá que não ex iste um constru tor sem arg umentos e in serirá um. Mas não é ass im que funciona. O compilador se en vo lverá na criação de con strutores somente se você nüo informar absolutamente nada sobre eles .

Se você criar um construtor que use argumentos e ainda quiser um construtor sem argumentos, terá que construí-lo por sua própria conta!
Assim que você fornecer um construtor, QUALQUER tipo de construtor, o compilador recuará di zendo: "Certo meu chapa, parece que agora é você que se encarregará dos construtores."

Se você tiver mais de um construtor em uma classe, eles precisarão de listas de argumentos diferentes.
A lista de argumentos incluirá a ordem e os tipos dos argumentos . Se elas forem diferentes, você poderá ter mais de um construtor. Também poderá fazer o mesmo com os métodos, mas veremos isso em outro capítulo.

t1.~ Para ~ue seja compilado, c~da construtor deve ter
(""'_ - uma lista de argumentos dIferente!

ra=
. ;-

O termo construtores sobrecarregados significa que há mais de um construtor em sua classe.

somente um tipo int, por exemplo, a classe não seria compilada. Como você nomeará a variável de parâmetro não importa. É o tipo (int, Dog, à~~"';7": etc.,) e a ordem da variável que importam. Você também pode ter dois );1':.._=;':'. _ construtores que tenham tipos idênticos, contanto que a ordem seja diferente . Um construtor que use uma String seguida de um int não é o ' ·· . . -"=-- mesmo que um que use um int seguido ele uma String. ......

l~ i
,
,

t

-A~­

- de argumentos diferentes. Se você tivesse dois construtores que usassem

A classe abaixo é válida, porque todos os quatro construtores têm listas

- /"

I.

, .1.~t"" .'

,

1
·3

..

publ ic c l a s s Mushroom .( public Mushr oom{int size) publ ic Mus hroom ( ) { }
quando voce souber o tamanho, ~(~-------mas não souber se ele é mágico

~--------- quando v-ocê não souber nada

public M ushroom (boolean isMagic)

cr...tando você souber se sle é ou não { } (-;ágico, Rias não ~'cuber o tamanho int size)
quando se ele mágico Gcuber você souber é ou não E também o tamanho

esses ~ois aons=rutczes têm
os mesmos a~~~entos, mas em ord:m uifa=~nter portan=o, es ta~ corretos

{

PUbliC M ushr oom {boolean isMagic,
ub lic

P

Mushroom{int size,

boolean isMagic)

locê está aqui

~

179

construtores sobrecarregados

r----

DISCRIMINAÇÃO DOS PONTOS
- Se você inserir um construtor - qualquer construtor em sua classe, o compilador não criará o construtor padrão. - Se você quiser um construtor sem argumentos e já tiver inserido um com argumentos, terá que criá-lo por sua própria conta. - Forneça sempre um construtor sem argumentos se puder, para tornar fác il para os programadores criarem um objeto funcional. Forneça valores padrão. - Os construtores sobrecarregados devem ter li stas de argumentos diferentes. - Você não pode ter dois construtores com a mesma lista de argumentos. Uma lista de argumentos inclui a ordem elou o tipo dos argumentos. - As variáveis de instância receberão um valor padrão, mesmo quando você não atribuir um explicitamente. Os valores padrão são OIO,Olfalso para tipos primitivos e nulo para referências.

- As variáveis de in stância residem dentro do objeto ao qual pertencem, no Heap. - Se a variável de instância for a referência de um objeto, tanto a referência quanto o objeto que ela referenciar ficarão no Heap. - Um construtor é o código que é executado quando escrevemos new em um tipo de classe. - Um construtor deve ter o mesmo nome da classe e' não deve ter um tipo de retorno. - Você pode usar um construtor para inicializar o estado (isto é, as variáveis de instância) do objeto que está sendo construído. - Se você não inselir um construtor em sua classe, o compilador inserirá um construtor padrão. - O construtor padrão é sempre um construtor sem argumentos.

Aponte seu lápis

Ligue a chamada a new DuckO ao construtor que será executado quando esse objeto Duck for instanciado. Fizemos o mais fácil para ajudá-lo a começar.

class Duck { int pounds = 6; float floatability = 2 .1F; String narne = "Generic"; longe] f eathers = {1,2,3,4,5,6,7} ; boolean canFl y = true; int rnaxSpeed = 25; public Duck(} { Systern.out.println("type 1 duck");

public class TestDuck publi c static void rnain(String[] args) { int we i ght = 8; float density = 2.3F ; String narne = "Donald"; longe] feathers = (l,2,3,4,S,6l; boolean canFly = true; int airspeed = 22; Duck[] d = new Duck[7]; d[O] d[l] d[2] new Duck(); new Duck(density, we i ght) ; new Duck(narne, feathers);

public Duck(boolean fly) { canFly = fly ; Systern.out.println("type 2 duck");

public Duck(String n, longe] f) { n ame = n; f eathers = f; System . out . println("type 3 duck"};

d[3] d[4] d[5] d[6]

new Duck(canFly); new Duck(3.3F, airspeed } ; new Duck (false) ; new Duck(airspeed, d ensity};

public Duck(int w, float f} { pounds = w; fl oatability = f ; System . out.println( " type 4 du c k");

public Duck(float density, int rnax) { fl oa tability = den sity ; rnaxSpeed = max; System. ou t.println("type 5 duck"};

180 capítulo 9

Q~.J...-

construtores e coleia de lixo

h

;..

~

Anteriormente você disse que é bom ter um construtor sem argumentos para que, se as pessoas o chamarem, possamos fornecer valores padrão para os argumentos "ausentes". Mas não há situações em que é impossível ter padrões? Há casos em que não seria recomendável ter um construtor sem argumentos em nossa classe? Você está certo. Há situações em que um construtor sem argumentos não faz sentido. É possível ver isso no APl Java - algumas classes não têm um construtor sem argumentos. A classe Color, por exemplo, representa uma ... Cor. Os objetos Color podem ser usados na configuração ou alteração da cor de uma fonte da tela ou de um botão de GUI. Quando você criar uma instância de Color, ela será referente a uma cor específica (você sabe, Marrom-Chocolate, Azul-Cadavérico, Vermelho-Escândalo, etc.). Quando criar um objeto Color, terá que especificar a cor de alguma maneira.
Colar c
=

P:

J.-.

h
,h.
~
.J..... :

R:

(Estamos usando três inteiros para os valores RGB aqui. Trataremos do uso de Color depois, nos capítu los sobre o Swing.) Caso contrário, o que você teria? Os programadores do APl Java poderiam ter definido que, se chamássemos um construtor de Color sem argumentos, obteríamos uma iinda sombra violeta . Mas o bom gosto prevaleceu. Se você tentar criar um objeto Color sem fornecer um argumento:
Calor c
=

new Color();

O compilador ficará confuso, porque não conseguirá achar um construtor sem argumentos correspondentes na classe Color.

J..-.,
~.

h
~ .

)~

new Color(3 ,45, 200) ;

h ~
~

Mini-revisão: quatro coisas a memorizar sobre os construtores
Um construto r é o código que s e rá executado quando a lguém escrever new em um ti po de class e

..

J!.-; -,I...;. .. L;

~.

Duck d = new Du ck(); Um construtor deve ter o mesmo nome da classe e nenhum t i po de retorno p ubli c Duck (int size) · { } Se você não inserir um construtor em sua classe, o compilador inserirá um construtor padr ão. O construtor padrão é sempre um construtor sem argumentos. public Duck () { }

o

poder do cérebro

E quanto às superclasses? Quando você criar umobjeto D09, o construtor de Canine também deve ser executado?

-~

~-

Se a superclasse for abstrata, 'éla
deve ter um construtor?

i ;

Você pode ter mais de um construtor em sua c l asse, contanto que as listas de argumentos sejam diferentes. Te r mais de um construtor e m uma classe significa que v oc ê tem construtores sobrecarregados . public Duck () ( { }

Examinaremos isso nas próximà~ páginas, portanto, faça uma pausa agora e pense nas implicações éxistentes entre os construtores' eas superclasses.

public Duck (int s i ze)

~--------~~------~~~--~
Está comprovado que fazer todos os exercícios de halterofilismo cerebral produz um aumento de 42% no tamanho dos neurónios. E você sabe o que dizem por aí, "Grandes neurónios ..."

public Duck(String name ) public Duck(String name, int s i ze) { }

Não existem

Perguntas Idiotas

Não. Os construtores podem ser public, private ou padrão (que significa nenhum modificador de acesso) . Examinaremos com mais detalhes o acesso padrão no Capítulo 16 e no Apêndice B.
você está aqui!';>

R

P.- oS construtores têm que ser public? _
181

espaço para as partes da s,-Ipei"dssse de um objeto

_ -= Em que um construtor privado seria possível criar um novo objeto!

P

·p0dej"~a-sei

útii? ·Ningttém- põderia nem mesmo chamá-lo, portanto, não

.-tr .

Mas isso não é exatamente assim . Marcar algo com private não significa que ninguém poderá acessá-Io, significa apenas que ninguém de fora da classe poderá acessá-Io. Aposto que você está pensando "ch egamos a uma situação sem saída". Só um código da mesma classe que a do construtor privado pode criar um novo objeto dessa classe, mas sem criar primeiro um objeto, como você conseguirá executar um código dela? Como conseguirá acessar algo dessa classe? Paciência, gafanhoto. Chegaremos lá no próximo capítulo.

R

_

Espere um momento ... Ainda não falamos sobre as superclasses e a herança, e o que tudo isso tem a ver com os construtores.
É aqui que começar a ficar divertido. Lembra-se do último capítulo, da parte em que examinamos o objeto Snowboard que envolvia um núcleo interno representando a parte Object da classe Snowboard? A grande descoberta foi que todo objeto contém não só suas próprias variáveis de instância, mas também todos os elementos de sua superclasse (o que significa, no mínimo, a classe Object, já que toda classe estende Object). Portanto, quando um objeto é criado (porque alguém escreveu new; não há outra maneira de criar um objeto que não seja alguém, em algum local, escrever new no tipo da classe), ele ganha espaço para todas as variáveis de instância, no trajeto até o topo da árvore de herança. Pense nisso por um momento ... Uma superclasse pode ter métodos de configuração encapsulando uma variável privada. Mas essa variável tem que residir em algum local. Quando um objeto é criado, é quase como se vários objetos se materializassem - o objeto que está sendo criado e um objeto para cada superclasse. Conceitualmente, no entanto, é muito melhor considerar isso como no cenário a seguir, onde o objeto que está sendo criado tem camadas que representam cada superclasse.

Object
Foo a; int b; int c; equals () getClass () hashCode ( )

Object tem variáveis de instân,cía encapsuladas por métodos de acesso. Essas variáveis de instância são criadas quando qualquer subclasse é instanciada. (Essas não são as 'treriávsis PJiA::S de Object, mas não se preocupe com sua

Um unl.CO objeto do heap

natureza; conta.cto .qUG estej~~ encapsuladas.)

Snowboard
Foo x Foo y int z t u rn() shred( ) getAir () loseC o ntro l ( )

SnowDoard também tem ,rariáveis de instância próprias, portanto, para criar ~~ objeto Snowboarà$ precisamos de espaço para as variáveis de instáncia das duas classes.

Há apenas UJ'·f obj&to no heap aq>,Ji.

Um objeto SnoW'Doard.

Mas ele contém tanto partes de Snowboard quanto de Objec to Todas as variáveis de instância das duas classes tém que estar aq>Ji.

A função dos construtores da superclasse é dar vida a um objeto
Todos os construtores da árvore de herança de um objeto devem ser executados quando você criar um novo objeto.
Pense nisso. Isso significa que toda supercl asse tem um construtor (porque toda classe tem um) e cada construtor superior na hierarquia é executado na hora em que um ohjeto de uma subclasse é criado.
E.~crever new é uma Grande Ocorrência. Isso inicia toda a reação em cadeia dos construtores. E sim, até as classes abstratas têm construtores. Embora talvez você nunca escreva new em uma cla<;se abstrata, ela

182

capitu!o 9

construtores e coiet2

rjs ,:;.;(

continuará sendo uma superclasse, portanto, seu construtor será exec utado quando alguém cri ar uma in stância de uma subclasse concreta. Os superconstrutores são executados para construir as partes do objeto referentes à supercl asse. Lembre-se de que uma subcl asse pode herdar métodos que dependam do estado da superclasse (em outras palavras, do valor das variáveis de instância da superclasse). Pam um objeto ser totalmente formado, todas as suas partes referentes à superclasse devem ser plenamente criadas e é por isso que o superconstrutor deve ser executado. Todas as variáveis de instância de qualquer classe da árvore de herança têm que ser declaradas e inicializadas. Mesmo se Animal tiver variá veis de instância que Hippo não herdar (se as variáveis forem privadas, por exemplo), o objeto Hippo ainda dependerá dos métodos de Animal que usam essas variáveis. Quando um construtor é executado, ele chama imediatamente o construtor de sua superclasse, subindo a cadeia até chegar ao construtor da classe Object. Nas próximas páginas, você aprenderá como os construtores da superclasse são chamados e como podemos chamá-los. Também aprenderá o que fazer se o construtor de sua superclasse tiver argumentos!

"r~ ri·

4
rl" f ,........

,~_

..

Um único objeto Hippo do heap
Um novo objeto Hippo também É-UM objeto Animal e É-UM tipo Object. Se você quiser criar um objeto Hippo, também deve criar suas partes referentes a Animal e Object. Tudo isso acontece em um processo chamado Encadeamento de Construtores.

Criar um objeto Hippo também significa criar as partes referentes a Animal e Object. ..
public class Animal public Animal() ( System.out.println("Criando um obje to Animal"); A

Qual será a saída? Dado o código à esquerda, o que será exibido quando você executar TestHippo? A ou B?
(a resposta está no final da página)

L
public class Hippo extends Animal ( public Hippo () ( System . out .println("Criando um objeto Hippo");

I

r---

A

B
~

public class Tes t Hippo { public static void main (String[] args) Hippo h = new Hippo();
'o~1am1~d ~ ~u,lliaa~ ano T~m,uv ap ~o~n~~suo~ op og6n~axa ~ ~ s~m 'sa~u~ op~~~~ ()odd,H ~04n~4SUO~ O 'V '~~,am,~d V

r <;

você está aqu i i;>

183

construção

- ~~ ~:~

*'i~

,;p..,.

(:})o códiao de outra '-../ classe usa new Hippo{ ) e o construtor Hippo{ ) é inserido em um ponteiro no topo da pilha.
~

(2)Hippo( -)- --chama - - -- -- - - "'-'" - - -- . - -- - o construtor da superclasse que força a entrada do construtor Animal { no topo da pilha.

-_. _

._ ~ --- ~ _ . -

(3) Animal {

) chama o construtor da superclasse que força a entrada do construtor Object{ ) no topo da pilha, já que Object é a superclasse de Animal.

® A concluída de e)(ecus:~o é e

Obj ect (_L _-">L-.___.,,~. seu ~_ ponteiro é eliminado da pilha. O processamento volta ao construtor Animal { ), prosseguindo na linha posterior àquela em que Animal chama o construtor de sua superclasse.

):: .

Como chamar o construtor de uma superclasse?
Você pode achar que em algum local, digamos, do construtor de um objeto Duck, se Duck estender Animal será necessário chamar Animal(). Mas não é assim que funciona:
public class Duck extends Animal int size i public Duck(int newSize) (

E

O

que ocorrerá se não fizermos isso?

Você já deve ter adivinhado.

Nosso bom amigo, o compilador, insenra uma chamada a supere ) se você não o fizer.
Portanto, o compilar interferirá na criação do construtor em duas situações:
C!)se você não fornecer um construtor O compilador inserirá um que terá esta aparência: public ClassName() super() ;

In"J7álido!'

Animal ( );

1'--- - - - - ' Não! :Isso não é vá.lido!

size = newSizei

A única maneira de chamar um superconstrutor é chamando super( ). É isso que ocorre - super( ) chama o superconstrutor. Quais são as chances de dar certo?
public class Duck extends Animal

int size;
public Duck(int newSize)

super();
size = newSize;

C3Jse você fornecer um construtor mas não inserir a chamada a super { ) O compilador inserirá urna chamada a super() em cada um de seus construtores sobrecarregados. * A chamada fornecida pelo compilador terá esta aparência: super() ;

Uma chamada a supere ) em seu construtor inserirá o construtor da superclasse no topo da Pilha. E o que você acha que o construtor da superclasse fará? Chamará o construtor de sua superclasse. E assim por diante até o construtor de Object estar no topo da Pilha. Quando a execução de Objecte ) for concluída, ele será eliminado da Pilha e a operação seguinte (o construtor da subclasse que chamou O~ject( )) agora estará no topo. A execução desse construtor será concluída e o processamento continuará até o construtor original estar no topo da Pilha, onde agora sua execução poderá ser concluída.

Ela sempre terá essa aparência. A chamada a super( ) inserida pelo compilador sempre será uma chamada sem argumentos. Se a superclasse tiver construtores sobrecarregados, só o construtor sem argumentos será chamado.

o filho pode existir antes dos pais?
Se você está considerando a superclasse como o pai da subclasse, já sabe quem deve existir primeiro. As partes de um objeto referentes à superclasse têm que estar totalmente formadas (completamente desenvolvidas) antes que as partes referentes à subclasse possam ser construídas. Lembre-se de que o objeto da subclasse pode depender de coisas que ela herdar da superclasse. portanto, é importante que esses elementos herdados estejam formados. Não há outra saída. O construtor da superclassc deve tcr sua execução concluída antes do construtor de sua subclasse.
::,;.,·184

9

construtores e Col8t3 oe ilxo
~~

).."
!

À

A x·· ,
):.. .1

Examine a seqüência da Pilha da pág ina 248 no vamente e verá que, embora o construtor de Hippo seja o pril1leiro a ser chamado (é o primeiro item da Pilha), ele é o último a ser co ncluído I O construtor de cada subclasse chamará imediatamente o construtor de sua própria superclasse, até o construtor de Object estar no topo da Pilha. Em seguida, a execução do construtor de Obj ect será concluída e voltaremos a descer a Pilha até o construtor de Animal. Só depois que a execução do construtor de Animal for concluída é que finalmente voltaremos a descer e terminar a execução do construtor de Hippo. Portanto:

A chamada a super( ) deve ser a primeira instrução de cada construtor!*
Construtores possíveis para a classe Boop

V public
..; publ ic Boop () super ( );
}

Boop ()

{

por~Je

I'

.../ public Boop ( int i ) super () ; size = i;

{

Esses são válidos porque o programador codificou explicitamente a cbamada a super ( ) , como a primeira inscruçáo ..

, / public Boop (int i) size ;:: i i

{

Esses são válidos o compilador inserirá uma chamada super () como a primeira instrução.

iii

o

public .Boop ( int i ) size = i; super();

~

Inválido!! Não será ( compilado! Você não pode inserir e~licitamente a chamada a super{) abaixo do que quer que seja.

)..{
,~~-

*Há uma exceção a essa regra; você a conhecerá na página XXX.

Animal

.PI
j

Construtores de superclasse com argumentos
~~ -'1 , ;-., E se o construtor da superclasse tiver argumentos? Você pode passar algo para a chamada de supere )? É claro. Se não pudesse, nunca conseguiria estender uma classe que não tivesse um construtor sem argumentos. Imagine esse cenário: todos os animais têm um nome. Há um método getName( ) na classe Animal que retorna o valor da variável de instância name. A variável de instância foi marcada como ptivada, mas a subclasse (nesse caso, Hippo) herda o método getName( ). Portanto, aqui está o problema: Hippo tem um método getName( ) (através da herança) mas não tem a variável de instância name. Depende de sua parte referente a Animal para ter a variável de instância name e retorná-la quando alguém chamar getName( ) em um objeto Hippo. Mas ... Como a parte referente a Animal capturará o nome? A única referência que Hippo tem de sua parte referente a Animal é fornecida através de supere ), logo, esse é o local onde Hippo enviará seu nome para a parte referente a Animal, para que ela possa armazená-lo na variável de instância privada name.
public abst r act class Animal Todos os animais (inclusive as private String name; ~(~_______________ subclasses) têm um nome
!:1-..

-::1 !

private String name Animal (String n) String getName ()

I
I
I

I

.p;
~-

.4 ~
Hippo
Hippo(Str ing n)
(ou tro s métodos específicos
de HippoJ

~

1 "
I~
I

j

h
. I

public Str ing getName () retu rn name ;

{ (---------- Um método de ca tura que

Híppo herda

.,.,~.­
~~.

public An imal (String theName) { O construtoz' que 'Usa o nome e name = theName; (~_____________ o atri.bui à variável àe instãzlcia name

public class Hippo extends Animal public Hippo (String name) --supéi rname~ { (---- - - O construtcr de IIippo usa um nome . .envia o .nome para. cima. na Pilha atá c constra.tox c!{-0 ..~J1.ima1.

-

você ::stá aqui ii>

185

r

chamando construtores :3;,:'

~(ê:

-.:::~

.... '

-

publ i r.

rl-3~S

~1 a keHipP0

{

__ _________ " _

publi c static void mainlString[] args) ( Hippo h = new Hippol"Buffy"); ~------­ System . ou t . printlnlh . getNamel)) ;
segui~~, cba~a

c

:nétodo gec!\a...rne (

Chamando um construtor sobrecarregado a partir de outro
E se você tiver construtores sobrecarregados que, exceto pela manipulação de diferentes tipos de argumentos, façam todos a mesma coisa? Você não quer código duplicado em cada um dos construtores (a manutenção é difícil, etc.), portanto, gostaria de inserir grande parte do código do construtor [inclusive a chamada a superO] em apenas U111 dos construtores sobrecarregados. Você quer que o construtor que for chamado primeiro chame O Construtor Real e deixe que ele termine a tarefa de construção. É simples: apenas insira this( ). Ou this( aString). Ou this(27, x). Em outras palavras, basta usar a palavra-chave this como uma referência ao objeto atual. Você só pode inserir this( ) dentro de um construtor e essa deve ser a primeira in strução do construtor! Mas isso é um problema, não é? Anteriormente dissemos que superO deve ser a primeira instrução do construtor. Bem, quer dizer que você terá que optar.

."

-.\~ ­
~ ; ~,~

Todo construtor pode ter uma chamada a superO ou thisO, mas nunca as duas!
class Mini extends Car ( Color color; public Mini I) thisIColor . Red); ( _______ _ _ _ _ _ _ _ _ _ ________

o construtor sem ar~~"entos fornece um objeco Color padrão e ch~~ o Const~utor Real sobrecarregado [aquele que chama super()].

Esse é o Construtor Real que executa realmente public MinilColor c) super I "Mini"); ~(~--------------------­ o trabalho de inícíalizar o objeto [incluindo a :::bamada a super ( ) ] • color = c; II mais códigos de inicialização
Não :f7.LYJCiona:L"ét 1! l\Tão e

public Minilint sizel possíve~ ter super', e thisIColor.Red); <~------------------ tbis() no mesmo super(size); ~ construtor, porque
a,moa:s d e ""l:''''srn s er
f:j.

)

primeira ínst:ruçãc!

186 capitu!o _ q:.c:·

construtores e Gole1a ele

!i/{O

. <~-. -"':.-., Aponte seu lápis
~

r~

li...

~.
~
'~,;

o Java

Algun s dos construtores da c lasse SonOfB oo não serão comp ilados. Vej a se consegue reconhecer que con strutores não são válidos. Ligue as mensagens ele erro do compilador aos construtores de S0110fBoo que as causaram , desenhando uma linha da mensage m de erro ao construtor "in vá lido" .
As rosas vi oletas são azuis . Seus pai ' s V~rao primeiro, A você virá bem depois s par t es de um b' superclasse d o ]et o referentes à f evem ser t ormadas antes de o otalmente Subclasse pod . novo objeto da er eXlsti rorma, que você _ r . Da mesma antes de seus pa~: o Poderia ter nascido int i) ( ) sa o vermelhas , as

~
- ~
~.

public class Boo ( public Boo (int i) ( )

public BoolString s) public Boo(String s,

~.

~

t ~.

.~
-~
.Ii..•... ,.

h

~-

class SonOfBoo extends Boo ( pub l ic SonOfBoo() super ( "boo" ) ;

public SonOfBoo I int i) super I "Fred") ;

(

· r
i

~
public SonOfBoo(String s) super(42) ; (

p ublic SonOfBoo ( int i,
}

S tring s ) {

public SonOfBoo (String a, String b, String c) super(a,b) ;

(

publ ic SonOfBoo(int i, super ("man", j);

int j)

{

public SonOfBoo(int i, super(i, "star");

int x,

int y)

(

Agora sabemos como um objeto nasce, mas quanto tempo ele vive?
A vida de um objeto depende in teiramen te da vi da das referências que apontam para ele. Se a referência for con siderada "ativa", o objeto co ntinuará ,uivo no Heap. Se ela for eliminada Ce exam inaremos o que isso significa em breve) , o obj eto também o será.

Bem, se a vida de um objeto depende da vida da variável de referência, quanto tempo uma variável vive?
ISliü vai depender ·se~kw.J.ma.v"2ri;i"e! l(Jc(.!L~U-.fi.e..j11 \·tân('ia.-O~digQ.a.s..e.g.llÜ:.mo~r'l_a .v id a ele uma variáve l local. No exemplo, a variável é de um tipo primitivo, m as seu tempo de vi da se rá o mes mo se ela for primitiva ou uma variável ele referência.

a

I

i

~

187

-

ciclo de vida

~

os

Gt'j':: O~

_____ 1Uma variável jQçill só existe dentro do méto~o que a declarou.
public c las s TestLifeOne
Si
~o public void read() int s = 42; rF--------- portanto nâo pode ser usada em ne.n.i:I.um sleep () ; '_")utro local ..
T

cern seu eE:~Opo met.o(l~) ....ea_d() ,

pub lic vo id read( ) int s = 42 ; II ' s ' só pode ser usada II dentro desse método. II quando sua execução for concluída, II 's ' desaparecerá completamente .

publi c void sleep () :::lIíVÁLIDO! i Nâo e s = 7; ( - - - - - - - - - - -,.álião usar 's' aqui!

A variável ' s ' só pode ser usada dentro do método read( ). Em outras palavras, a variável só faz parte do escopo de seu próprio método. Nenhum outro código da classe (ou de qualquer ou tra cla ss e) conseguirá ver ' s ' .

sleep() não consegue ver a 'ST. Com? ela não está no ponteiro de sleep( na Pilha, o método não sabe nada sobre esse variável ..
varíáve~

Uma variável de instância vive o mesmo tempo que o objeto. Se o objeto ainda estiver ativo, suas variáveis de instân cia também estarão .
public cla ss Life { int size; public void setSize(int s) size = s; /1 's' desapar ec erá no II fim da execução desse método. II mas 'size' pode ser usada II em qualquer local da classe

.'

'r
'.

A var~avel 's' está ativa~ mas somente no escopo do método read ( ) . Quando a execução de sl e ep () f:"or concluída e read() estiver no topo da Pílha sando executado novamente, ele ainda conseguirá ver '5'. Quando a execução âe ~eaà{ ) for concluída e e~e for eliminado da Pilha, 's' deixará de existir. Estará digi talmen t e morta e enterrada .

A v ari ável ' s ' (dessa v ez um parâmetro do método) exi ste somente no escopo do método setSize(), mas a variável de instância size tem como es copo a vida do objeto e não do método .

A diferença entre vida e escopo para as variáveis locais:
Vida
Uma variável local estará ativa enquanto seu ponteiro estiver na Pilha. Em outras palavras, até a execução do método ser concluída.

public void doStuff () boolean b = true; go (4) ;

Escopo
Uma variável local só existirá no escopo do método em que foi declarada. Quando seu método chamar outro método, a variável continuará ativa, mas estará fora do escopo até o seu método voltar a ser executado. Você só poderá usar uma variável quando ela fizer parte do escopo.
~ dOStuff( ) entra na
Pilha. A variável está at i va e faz parte do escopo . 'b'
• ) pas sa para o topo da Pilha . 'x' e ' z ' es tão ativas e no escopo e 'b' está ativa, porém fora do es copo. go (

public void go(int x) in t z = x + 2 4; cra zy () ; II suponhamos que haja mais código aqui

public void crazy() char c = ' a' ;

8

crazy( ) é forçada para a pilha e agora 'c' está ati v a e no escopo . As outras tr ês v ariáv eis estão ativas, porém for a do escopo .

o

execução de crazy( ) foi conc luída e o método foi removido da Pi lha, portanto, 'c' está fora do escopo e foi eliminada . Quando go( )voltar a ser executado onde parou, 'x' e 'z' estarão ativas e de volta ao escopo . A variável 'b' ainda estará ativa, porém fora
A

do escopo [a té a
crazy()

execução de go( ) ser c onc lu ída] . go()

1

doStuff ()

l

I

doStuff ()

_......

construtores e coleléi de lixo

Enquanto uma variáve l local esti ver ativa, se u estado persistirá. Enquanto o método doStuffO esti ver na Pilh a, por exempl o, a variável ' b' manterá se u valor. Mas só poderá ser usada enquanto o ponteiro de doStuff() estiver no topo da Pilha. Em outras palavras, você só poderá usar uma variável local enqu anto seu método estiver sendo executado (e não aguardando a eliminação de ponteiros superiores da Pilha) .

E quanto às variáveis de referência?
As regras são as mesmas para tipos primiti vos e referências. Uma variável de referênc ia só poderá ser usada quando fizer parte do escopo, o que significa que você não poderá usar o controle remoto de um objeto a menos que tenha uma variável de referência no escopo. A dúvida é:

('Como a vida da variável afeta a vida do objeto?"
Um objeto estará ativo enqmmto houver referências ativas apontando para ele. Se uma variável de referência sair do escopo, mas ainda estiver ativa, o objeto que ela referenciar continuará ativo no Heap. Portanto é preciso perguntar: " O que acontecerá quando o ponteiro da Pilha que contém a referência for eliminado ao fim da execução do método?"

A vida de um objeto não terá valor, nenhum significado ou objetivo, a menos que alguém tenha uma referência que aponte para ele. Se você não conseguir acessá-Io, não poderá pedir que faça algo, e ele constituirá apenas um grande desperdício de bits . Mas , se um objeto não puder ser alcançado, o Coletor de Lixo descobrirá isso. Cedo ou tarde, esse objeto será elim inado .

k
.~

Se essa for a única referência ati va do objeto, ele estará fora do Heap. A variável ele referência desapareceu com o ponteiro da Pilha, portanto, agora o objeto abandonado foi , oficialmente, eliminado. O truque é saber o ponto em que um objeto se toma qualificável para a cole/a de lixo. Quando um objeto for qualificável para a coleta de lixo (GC, garbage collection), você não precisará se preocupar em reclamar a memória que ele estava usando. Se seu programa ficar com pouca memória, a GC destruirá alguns ou todos os objetos qualificáveis, para impedir que você fique sem espaço em RAM. Você ainda poderá ficar sem espaço na memória, mas não antes de todos os objetos qualificáveis terem sido enviados para a lixeira. É sua responsabilidade se certificar de abandonar os objetos (isto é, torná-los qualificáveis para a GC) quando não precisar mais deles, a fim de que o coletor de lixo tenha algo para reclamar. Se mantiver os objetos, a GC não poderá ajudá-lo e você correrá o risco de seu programa passar por uma indesejada falta de memória.

j~;.-

h.
K h
~ ~
r"""\. .

I "

~
j

~

Há três maneiras de eliminar a referência de um objeto:
referência sair do escopo permanentemente .

Um objeto se torna qualificável para a GC quando sua última referência ativa desaparece.

void go () Life z

a referência 'z ' será eliminaãa new Life(); ( ------------ ao fim da execução do método.

referência é atribuída a outro objeto . Life z = new Life(); o primeiro objeto é abandonado z = new Life() ; ~------------------. quando z é ' repr ogr&~aá2 ' para um novo objeto.

® A referência
_

é configurada explicitamente com nula.

Life z = new Life(); o primeiro objeto é abandonado z_ _ _ _--'-_ - - -__ - - - -- _ __ - _ _ Ç[flando z é ldesprogra..q}.ada' .. = null; ( _ _ - - ._ _ __ - - - - -

\focê está aqui

~

189

ciclo de vida

r~~

,"-tos

Exteíminador de objatas número i
A referência sai do escopo permanentemente.

public class StackRef ( public void foof{) ( barf () ;

public void barf () Duck d = new Duck();

~ foof( ) é forçado para a Pilha, nenhuma variável é declarada .

barf( ) é for çado para a Pi l ha, o n de declara uma var i áve l de referência e cria um novo obje to atribuído a essa referência . O ob j eto é c r iado no Heap e a referência está ativa e f az parte do escopo .

o

Re ap e enquanto b e rf ()

novo objeto Duck será in s erido no es ti ver sendo
td~

executado, a referência

estará

ativa e no escopo, portanto o ob]eto Duck ser á c ons iderado a t ivo.

~ A execução de barf( ) é concluída e o método é el i minado
da Pilha . Seu ponteiro desaparece, portanto , agora 'd' foi eliminada . A execução r e to rnará para foof( ) , mas esse método não poderá usar 'd' .

I
\ >i':;'

o<>~~' Cfr '
:.7E!to ~"

l ~~
Opa. A variável 'dr sumiu ~Jando O ponceiro de barf () foi elímÍ1Jado da pí111a, portanto , o objsto Duck será ebandonado~ virou isca do coletor de lixo.
I

/

Exterminador de objetos número 2
Atribua a referência a outro objeto

public class ReRef Duck d

(

=

new Duck() ;

novo obje t;o Duc ]: entra no Heap, r€d'erenciado por Já que td~ é uma variáve2 de inst~~cíaT o objeto Duck estará ativo enquanto o obieto ReRef que. o in.stanciou também estiver~ A menos que .. ""
~d ~.

o

public void go () d = new Duck ( ) ;

o
·H~ap

190 C8pitu!("; 9

construtores

f':

coieta ce

11;<0

Cara , tudo que você tinh a que fazer e ra reconfigurar a referê ncia . Acho que el es não tin ham gerenciamento de memória na é poca.

o

O

Quando alguém

cbw~ar

o método go(),

esse objeco

Duck será abandonado. Sua única referBncia foi reprogramada para um objeto Duck diferente.

Heap
'd' recebeu um novo objeto Duck" dei:r;an d o o objeto Duck original (o primeiro) abandonado. Agora esse primeiro objeto pode ser consiàerado elíminaão ~

Exterminador de objetos número 3
Configurar explicitamente a referência com nula
pub l ic clas s ReRef ( Duck d = new Duck () ; public vo i d g o () d = null;

o

significado de null
o

Heap
novo objeto Duck entra no Eeap, refe.renciado por 'd" ~ Já que \d:J' é uma varíável de i nstância~ o objeto Duck 8stará ativo enquanto o objeto ReRer ~~e o instanciou também estiver. A menos que ...

Quando você configurar um referência com nuIl, estará desprogramando o controle remoto. Em outras palavras, terá um controle remoto, mas nenhuma TV na outra extremidade. Uma referência nula contém bits que representam 'nulo' (não sabemos ou não estamos interessados em quai s são esses bits, contanto que a JVM saiba). Se você tiver um controle remoto desprogramado, no dia-a-dia, os botões não farão nada quando você os pressionar. Mas, em Java, você não poderá pressionar os botões (isto é, usar o operador ponto) de uma referência nula, porque a JVM saberá (esse é um problema do tempo de execução e não um erro do compilador) que estamos esperando um latido, mas não há um objeto Dog para executá-lo'

Esse objeto ~Jck será abandonado. Sua única referência foi configuraãa com nula.

J
Heap

h !

h

",.h
l:f

'. h

~.-..---------------------------

r'Y

Se você usar o operador ponto em uma referência nula, verá uma exceção Nu!!Point8r.Exgeption no tem po-de execu~""a·9n~~.--!-Aprenderemos tudo sobre Exceções no capítulo sobre Comportamento Arri scado.

ld' foi configurada com .nU~d, o qu-e é {) mesmo que termos um control.S! r.emoto que .n30

poderá nem mesmo usar o operador ponta ~m td f até que essa. va.riá"ve.L sej.~l :.Y'~prog,:c:;;.rfí(·uJa

voce está aqui I>

191

"
ciclo de vida dos objetos

Bate-papo na fogueira

-----

- - - -- - -- --

- - --

Debate de hoje: uma variável de instância e uma variável local discutem vida e morte (com uma educação notável)

Variável de instância
Gostaria de começar, porque devo ser mais importante para um programa do que uma variável local. Eu me faço presente para dar suporte a um objeto, geralmente durante toda a sua vida. Afinal, o que é um objeto sem estado? Os valores mantidos nas variáveis de instância.

Variável local

Respeito o seu ponto de vista e certamente aprecio o valor do estado de um objeto, mas não quero que as pessoas se enganem. As variáveis locais são realmente importantes. Usando sua frase, "Afinal , o que é um objeto sem comportamento?" E o que é comportamento? Algoritmos de métodos. Pode apostar seus bits que haverá algumas variáveis locais presentes para fazer esses algoritmos funcionarem.

Não me entenda mal. Compreendo realmente seu papel em um método , só que a sua vida é tão curta. Tão temporária. É por isso que vocês são chamadas de "variáveis temporárias". Dentro da comunidade de variáveis locais, o termo "variáveis temporárias" é considerado depreciador. Preferimos "locais", de pilha", "automáticas" ou "dependentes do escopo". Desculpe, compreendo perfeitamente. De qualquer forma, é verdade que não temos uma vida longa e ela também não é particularmente boa. Primeiro, somos empurradas para um ponteiro da Pilha com todas as outras variáveis locais. Em seguida, se o método do qual fizermos parte chamar outro método, outro ponteiro será empun'ado para a posição acima da que nos encontramos. E se esse método chamar outro método ... E assim por diante. Às vezes temos que esperar uma eternidade até que todos os outros métodos do topo da Pilha terminem sua execução para que o nosso possa ser processado novamente. Nunca pensei nisso de tal forma. O que você faz enquanto os outros métodos estão sendo executados e é preciso aguardar seu ponteiro estar no topo da Pilha novamente? Nada. Absolutamente nada. É como ficar em estado de suspensão - essas coisas pelas quais as pessoas passam nos filmes de ficção científica quando têm que viajar longas distâncias. Animação suspensa, na verdade. Apenas ficamos sentadas esperando. Enquanto nosso ponteiro existe, estamos seguras e o nosso valor também, mas é uma faca de dois gumes quando ele volta a ser executado. Por um lado, ficamo s ativas de novo. Mas por outro, as horas começam a passar mais uma vez em nossas curtas vidas. Quanto mais tempo nosso método permanecer sendo executado, mai s perto chegaremos do fim de sua execução. Todo,\' nós sabemos o que acontecerá depois. Vimos um vídeo educativo sobre isso uma vez. Parece um fim muito brutal. Quero dizer, quando esse método atingir sua chave final, o ponteiro será literalmente removido da Pilha! Isso deve doer.

192 capltp lQ -9

construtores e coieta de lixo

Variável de instância

Variável local
Nem me diga. Na ciê ncia da computação usa-se o termo eliminado como em "o ponteiro foi eliminado da pilha". Isso faz tudo soar di vertido ou talvez como um esporte radical. Mas, bem, você vi u o filme. Portanto, por que não falamos sobre você? Sei qual é a aparência de meu pequeno ponteiro na Pilha, mas onde você reside?

Vivo no Heap, com os objetos. Bem, não com os objetos, na verdade em um objeto. O objeto cujo estado eu armazeno . Tenho que admitir que a vida pode ser bem luxuosa no Heap. Muitos de nós se sentem culpados, principalmente nos feriados. Mas nem sempre você vive tanto quanto o objeto que o declarou, certo ? Suponhamos que existisse um objeto Dog com uma variável de instância Collar. Imaginemos que você fosse uma variável de instância do objeto Collar, talvez uma referência a um objeto Buckle ou algo desse tipo, toda feliz sentada dentro do objeto Collar que por sua vez estaria todo satisfeito dentro do objeto Dog. Mas ... O que aconteceria se o objeto Dog quisesse um novo objeto Collar ou anulasse sua variável de instância Collar? Isso tornaria o objeto Collar qualificável para a Gc. Portanto ... Se você fosse uma variável de instância de Collar e o objeto inteiro fosse abandonado, qual seria o seu destino? Certo, hipoteticamente, sim, se eu for uma variável de instância do objeto Collar e ele for qualificável para a GC, suas variáveis de instância serão realmente descartadas como o são tantas embalagens de pizza. Mas fui informado de que isso quase nunca acontece.

E você acreditou? Isso é o que dizem para nos manter motivados e produtivos. Mas você não está esquecendo algo? E se você fosse a variável de instância de um objeto e ele fosse referenciado somente por uma variável loca!? Se eu for a única referência do objeto em que você estiver, quando me eliminarem, você virá comigo. Goste ou não, nossos destinos podem estar conectados. Portanto, proponho que esqueçamos isso tudo e tomemos um porre enquanto podemos. Carpe RAM e etc.

Eles nos deixam beber?

você está aqui

I>

193

exercício: Seja

ü

CO'etor ds ;"';xo

Seja o Coletor de Lixo
Quais da s linhas de código à direita, se inseridas na classe à esquerda no ponto A, fariam com que exatamente um objeto adicional se tornasse qualificável para o Coletor de Lixo? [Suponhamos que o ponto A (I/chama mais métodos) seja executado por um período longo, dando tempo para que o Coletor de Lixo realize sua tarefa. ]
1. 2. 3. publie statie void main(String [] args) GC gel; GC ge2 new GC() ; GC ge3 = new GC( ) ; GC ge4 = ge3; gel = doStuf f (); 4. 5.
6.
7.

public class GC ( public static GC doStuff() GC newGC = new GC(); doStu ff 2(newGC); return newGC;

eopyGC = null; ge2 = null; newGC = ge3; g e l = n ull; newGC = null; ge4 gc3 gel ge3 null; ge2; ge4; null;

II chama mais métodos

publie statie void doStu ff 2(GC eopyGC) GC loealGC = eopyGC;

"

8.

{

9.

Objetos populares
Nesse exemplo de código, vários objetos novos são criados. Seu desafio é encontrar o objeto ' mais popular' , isto é, o que tem mais variáveis de referência apontando para ele. Em seguida, liste qual é o total de referências que existem para esse objeto e quais são elas! Daremos o pontapé inicial apontando um dos novos objetos e sua variável de referência.
elass Bees { Honey [] beeHA;

elass Raeeoon Kit k; Honey rh;

elass Kit { Honey kh;

elass Bear { Honey hunny;

publie elass Honey ( publie statie void main(String [] args) ( Honey honeypot = new Honey(); Honey [] ha = {honeyPot, h oneypot, honeyPot , Bees b1 = new Bees(); bl . beeHA = ha; Bear [] ba = n ew Bear[5]; for (int x=O; x < 5 ; x++) ba[x] = new Bear(); ba[x] .hunny = honeyPot ;

'honeypot} ;

Kit k = new Kit(); _ __------------------ Aqui est á um novo objeto Raccoon! k . kh = honeyPot; Raecoon r~w Raeeoon(); ~ r . rh = hOneypot~;----------------------________________
r.k = k;

~

Aqui está sua variável

de refErência

' r(~

k = null; // fim de main

1.94 capitulo 9

construtores

coieta de lixo

Um pequeno mistério
"Executamos a simulação quatro vezes e a temperatura do módulo principal sempre se desvia do padrão em direção ao frio", disse Sarah, exasperada. "Instalamos os novos robôs de temperatura na semana passada. As leituras nos robôs do radiador, projetados para resfriar os aposentos, parecem estar dentro das especificações, portanto, enfocamos nossa análise nos robôs de retenção de calor, aqueles que ajudam a aquecer o local." Tom suspirou, no início parecia que a nanotecnologia os colocaria realmente à frente do prazo. Agora, com apenas cinco semanas para o lançamento, alguns dos sistemas-chave de manutenção de vida da nave ainda não tinham passado no teste da simulação. "Que proporções você está usando na simulação?", Tom perguntou. "Bem se entendi onde você quer chegar, já pensamos nisso", Sarah respondeu. "O controle da missão não aprovará os sistemas críticos se eles estiverem fora das especificações . Fomos solicitados a executar as Unidades Sim do robô do radiador v3 em uma proporção 2: 1 com relação às Unidades Sim do radiador v2", Sarah continuou. "No sistema como um todo, a proporção entre os robôs de retenção e os do radiador deve ser de 4:3." "Como está o consumo de energia Sarah?", Tom perguntou. Sarah hesitou, "Bem isso é outra coisa, o consumo de energia está mais alto do que o planejado. Temos uma equipe analisando essa questão também, mas já que os componentes da nanotecnologia não têm fio tem sido difícil isolar o consumo de energia dos radiadores dos robôs de retenção". "A proporção geral do consumo de energia", Sarah continuou, "foi projetada para ser de 3:2 com os radiadores extraindo mais energia do acumulador sem fio". "Certo, Sarah", disse Tom. "Examinemos o código de iniciação da simulação. Temos que identificar esse problema, e rápido!"
import java.util.*; class V2Radiator ( V2Radiator(ArrayList list) ( for(int x=O; x<5; x ++) ( list.add(new SimUnit("V2Radiator"));

Um pequeno mist é r io .JIIII:.1lI'IIII~

class V3Radiator extends V2Radiator V3Radiator(ArrayList 19list) super (lglist) ; for(int g=O; g<10; g++) ( 19list.add(new SimUnit("V3Radiator"));

class RetentionBot { RetentionBot (ArrayList rlist) ( rlist.add(new SimUnit("Retention"));

public class TestLifeSupportSim { public static void main (String [I args) ( ArrayL ist aList = new ArrayList(); V2Radiator v2 = new V2Radiator(aList) ; V3Radiator v3 = new V3Radiator(aList) ; for(int z=O; z<20; z++) ( RetentionBot ret = new RetentionBot(aList);

class SimUnit ( String botType; SimUnit(String type) botType = type; int powerUse () { if ("Retention". equals (botType) ) return 2 · } else { return 4;

Tom examinou o código rapidamente e um pequeno sorriso desenhou-se em seus lábios. "Acho que encontrei o problema, Sarah, e aposto que também sei qual o percentual de desvio em suas leituras da utilização de energia!" De que Tom suspeita? Como ele conseguiu identificar -- os erros na leitura do consumo de energia e que linhas de código você poderia adicionar para ajudar a depurar esse programa?
195

solu ções ces

exsl C,CIOS

._~~~"

.~

Soluções dos

Exercício~_

-.~
~ ~

....

1 copyGC = nulI; 2 gc2 = nulI; 3 newGC - gc3; 4 gc1 = nulI;

Não -- essa linha tenta acessar uma variável que está fora do escopo. OK -- gc2 é a única variável de referência que aponta para esse objeto. Não -- outra variável fora do escopo. OK -- gel tem a única referência porque newGC está fora do escopo. Não -.-:. newGC está fora do escopo. Não -- gc3 ainda está referenciando esse objeto. Não -- gc4 ainda está referenciando esse objeto. OK -- nova atribuição à única referência desse objeto. Não -- gc4 ainda está referenciando esse objeto.

.~
-~ -,

G.C.

5 newGC =null;
6 gc4

= nuU ;

7. gc3 = gc2;

8. gel = gc4;

9 gc3 = null;

Objetos populares
Não deve ter sido tão difícil descobrir que o objeto Honey inicialmente referenciado pela variável honeyPot é sem dúvida o objeto mais 'popular' dessa classe. Mas pode ter sido um pouco mais complicado perceber que todas as variáveis que apontam no código para o objeto Honey referenciam o mesmo objeto! Há um total de 12 referências ativas apontando para esse objeto imediatamente antes de main( ) ser concluído. A variável k.kh é válida durante algum tempo, mas k é anulada no final. Já que d continua a referenciar o objeto Kit, I: k. kh (embora nunca declarado explicitamente) também referencia o objeto!
public class Honey ( public static void main(String [] args) ~---------------------------------------------------- Honey honeyPot = new Honey(); Honey [] ha = {honeypot, honeypot, honeypot, honeypot}; Bees bl = new Bees(); bl.beeH.lI. = ha ; Bear [ ] ba = new Bear[5]; for (int x=O; x < 5; x++) ba[x] = new Bear(); ba[x] .hunny = honeyPot; Aca ba sendo

t

r
I

anulada

-- -- -- --

~______________________________________

II
}

Ki t k = new Ki t ( ) ; k. kh = honeypot; Raccoon r = new Raccoon(); r.rh = honeyPot; r.k = k; k = nul l; // fim de main

Solução do pequeno mistéio
Tom notou que o construtor da classe V2Radiator usava uma AlTayList. Isso significa que sempre que o construtor de V3Radiator era chamado, ele passava uma ArrayList ao construtor de V2Radiator em sua chamada a super(). Portanto, cinco objetos SimUnit adicionais de V2Radiator eram criados. Se Tom estivesse certo, o uso total de energia teria sido igual a 120 e não aos lOO que as taxas projetadas por Sarah previam. Já que todas as classes Bot geram objetos SimUnit, criar um construtor para a classe SimUnit, que exibisse uma linh a sempre CJue um objeto SimUn it fosse gerado, teria realçado rapidamente o problema'

196 capitu lo 9 .

números

t;

elementos estáticos

Os Números são Importantes

,):;
jf,~:,.

"J,.<;C"

h
- P""\~ L;~:~

Faça as contas. Porém há mais coisas a se fazer com os números
do que apenas primitivos cálculos aritméticos. Você pode querer obter o valor absoluto de um número, arredondar um número ou saber qual é o maior entre dois números. Pode querer que seus números sejam

'>~,. -:~.

·~.'t·'.
-,.

:

'"
--

.

'h

.J,,'

exibidos com exatamente duas casas decimais ou inserir pontos em seus números altos para torná-los mais fáceis de ler. E quanto ao uso de datas? Você pode querer exibir as datas de várias maneiras ou até
manipulá-Ias para dizer algo como "some três semanas à data de

hoje". E quanto à conversão çle uma String em um número? Ou à conversão de um número em uma String? Você está com sorte. O APl Java está cheio de métodos úteis de manipulação de números prontos e fáceis de usar. Mas a maioria deles é estática, portanto começaremos aprendendo o que significa para uma variável ou método ser estático, inclusive as constantes em Java finais estáticas.

variáveis

":r-\
:, -("
~.

_0_-

este é um novo capítulo

197

métodos oe

Os métodos de Math: o de um método global

m a iS R(óximQº~lte~Jloçê ch~gará
usam vaiores de nenhuma variável de instânci~L E que sã.o (estáUcos' ~ você não de i\!1ath.
",-,-"~",,Math.

)f
)t
';{
fi

Já que nada é global em Java. Mas pen se nisto: e se você tiver um método cujo comportamento não depender do valor de uma variável de instância. Veja o método roundO da classe Math, por exemplo. Ele faz sempre a mesma coisa - arredonda um número ele ponto flutuante (o argumento elo método) para o inteiro mais próximo. Sempre. Se você tivesse 10.000 instâncias da classe Math e executasse o método round(42,2), obteria um valor inteiro igual a 42. Sempre. Em outras palavras , o método atua sobre o argumento, mas nunca é afetado pelo estado ele uma variável de instância. O único valor que altera a maneira como o métoelo roundO é executado é o argumento passado para ele! Não parece um desperdício de espaço útil do heap criar uma instância da classe Math simplesmente para executar o método roundO? E quanto aos outros métodos ele Math como minO, que usa dois tipos primitivos numéricos e retorna o menor entre eles. Ou MaxO. Ou absO, que retorna o valor absoluto de um número.

?1
;tl
pt,

int x int y int z

Math.round(42.2); Math.min(56,12); Math.abs(-343);

)if
~ ~
~

Esses

Esses métodos nunca usam os valores da variável de instância. Na verdade a classe Math não tem nenhuma variável ele instância. Portanto, não ganharíamos nada com a criação de uma instância da classe Math. Logo, adivinhe. Você não precisa fazer isso. Ou melhor, não poelerá fazê -lo.

métodos .t:1UZ1Ca usem ,rariáveís de instância/, portanto seu comporta.msnto não depende da existênci a de
um objeto esp ecifi,co.

>:I,
,~1I '
.r-<,
.. -::;-. ---=

Se você tentar criar uma instância da classe Math:
Math mathObject

' ;=-'

=

new Math();

,~

'-')1t
Verá essa mensagem de erro:
Essa mensagem de erro mostra
~-------- J)riv"ado!
~Je

.'~ :..
~'.
c
..~ .
.:~:--: ? "<:{.; .

con.strutor de 1tJ(:1tll e s tá marcado como
1:sso signifi ca
qt10

't!l"ocê rraMCA

poderá escrever \nel:V" V na cla,sse JYlatl:; criar um novo objeto bJatb~

A diferença entre métodos comuns (não-estáticos) e estáticos
O Java é orientada a objetos , mas em algumas situações você pode ver um caso especial, normalmente um método utilitário (como os métodos ele Math), onde não é necessária a existência de uma instância ela classe. A palavra-chave static permite que um método seja executado sem qualquer instância da classe. Um método ser estático significa "que o comportamento não depende de uma variável de instância, portanto não são necessárias instâncias/objetos. Apenas a classe".

método comum (não-estático)
public class Song String title; public Song( title = t;

t)

(

public void play() SoundPlayer player = new SoundPlayer(); player.playSound(title) ;

198

números e elementos estáticos
duas instâncias da c1.asse SOn.§1

Song

Song
s2 .play();

Song
s3 .play();

Cbamar play() nessa referência fará com que "Polítik" seja reproduzida.

Cnamar play ( ) nessa referência fará com que fl1'1y Way" seja reproduzida.

/i

método estático
public
.~J:_ati;;;

int min(int a,

int b) {

l/ retorna o menor entre a e b

Math
min I) max()
abs ()

Nenhuma variável de instância. O comportamento do método não é altsraâo cem o estado da variável àe instância ..

NÃO HÁ OBJETOS! 1

Não há

absoluta~ente NENH~l

OBJETO em qualquer local

desse cenário!

Math.min(42, 36}i

Oe

. ~t···'·
"'I~

-

j
Usa o nome da Classe, em vez do nome de uma variável de referência .

~~~~'""
~j~

Chame um método estático usando o ~A ~-=~ nome de uma CLASSE
7-- --

r

Math
minI ) max( )
abs ()

1

Chame um método não estático usando o nome de uma VARIÁVFL de REFERÊNCIA

Song t2 = new Song()i t2.play() ;

\

Math.min(88, 86};

o que significa termos uma classe com métodos estáticos
Geralmente (mas nem sempre), uma classe com métodos estáticos não deve ser instanciada. No Capítulo 8 falamos sobre classes abstratas e sobre como criar uma classe com o modificador abstract torna impossível alg uém inserir ' new ' nesse tipo de classe. Em outras palavras, é impossível instanciar uma classe abstrata. Mas você pode impedir que outros códigos de instanciel11 uma classe não-abstrata, marcando o construtor com private. Lembrese de que um método marcado como privado significa que só os códigos de dentro da classe podem chamá-lo. Um construtor marcado como privado signifi ca essencia1rnente a mesma cOIsa -- só CÕOlgOS ue ueIlLLU Üa classe podem chamá-lo. Ninguém pede executar 'new' defora da classe. É isso que OCOITe com a classe Math, por exemplo. O construtor é privado, você não pode criar .uma nova instância de Math. O compilador saberá que seu código não tem acesso a esse construtor pri vado.
você está é'.lG u i
/I>-

199

métodos estáticos
Isso não significa que uma classe com um ou mai s métodos estáticos nunca deva ser instanciada. Na verdade, toda classe em que 'Você inserir LHli ülétodo Inain() será urna ehr::-.~-e-coTlTU1Tl métodu--estáti-co+- - -! Normalmente, criamos um método mainO para podermos iniciar ou testar outra classe, quase sempre in stanci ando uma classe em main e, em seguida, chamando um método nessa nova instância. Portanto, fique à vontade para combinar métodos estáticos e não-estáticos em uma classe, embora, mesmo com apenas um método não-estático, isso signifique que deve haver alguma maneira de criar uma instância da classe. As únicas maneiras de se criar um novo objeto são através de 'new' ou da desserialização (ou algo chamado de Java Reflection APl que não examinaremos). Não há outra maneira. Mas quem exatamente pode usar 'new ' é uma pergunta interessante que discutiremos um pouco adiante neste capítulo.

Métodos estáticos não podem usar variáveis não estáticas (de instância)!
Os métodos estáticos são executados sem usar qualquer instância específica de sua classe. E como você viu nas páginas anteriores, pode nem mesmo haver qualquer instância dessa classe. Já que um método estático é chamado com o uso da classe (Math.random()) e não de uma referência de instância (t2.play()), ele não pode referenciar nenhuma variável de instância da classe. O método estático não sabe que valor de variável da instância usar.

Se você tentar usa r uma variável de instância de dentro de um método estático, o compilador pensará: "Não sei de que vari ável de instância do objeto você está fa!ando!" Se você tiver dez objatos Duck no heap, um método estático não saberá da existência de nenhum deles.

Se você tentar compilar esse código:
p ubl ic c l a ss Duck { pr ivate in t si ze ;

public static v o i d main ( String [] args ) { Que objetc Duol:? System.out.println("Siz e of duck is " + si z e ) ; fl( - - - - - - - - - " O tamanho de qpem ? public vo id setSize (int s ) {
size = s;

Não sabemos se há-um objeto
Duck em
a~gum

20cal do

h eap ~

public int getSize() r eturn siz e;

Verá essa mensagem de erro:

Métodos estáticos também não podem usar métodos não-estáticos!
O que os métodos não-estáticos fazem? Geralmente usam o estado da variável de instância para afetar o comportamento do método. Um método getNameO retornará o valor da variável de nome. O nome de quem? Do objeto usado para chamar o método getNameO.

200

capitulo 1q ~.

números e elementos estáticos

Isso não será compilado:
p ublic class Duck { private int size ; publ i c stati c vo id mai n (Str ing[] a rgs ) { Syst e m. out . println("S i ze is " + getSize());
Cherna:r: getSíze ( ) apenas adia rá o inevi tável getS:!. ze ( ) usa a variiZh.rel de instància. size ~

public void setSi z e ( i n t s i ze = S i public int get S ize() retur n siz e ;

5)

(

De vol ta ao .me smo problema. -

o

td.l7!anhoª.~ . . . <;F:'!"J:!l ?

wasb

. brar " wait() Torne fácil lem notif;: o

;:j segmento s t

cat

..

Não existem

sas s ã o vermelha s tardiamen t e AS ro fl o rescem , E sabe - se que ' a vel de instância ' ' O estad o da varl. tático s nao e para OS métodOS eS transparente

Perguntas Idiotas
E se você tentar chamar um método não-estático em um método estático, mas o método não-estático não usar variáveis de instância? O compilador permitirá isso?

P:

~

Não. O compilador saberá. que, independentemente de você usar ou não variáveis de instância em um método não-estático, é possível fazê-Io. E pense nas implicações ... Se você pudesse compilar um cenário como esse, o que aconteceria se no futuro quisesse alterar a implementação desse método não-estático para que um dia ele realmente usasse uma variável de instância? Ou pior, o que aconteceria se uma subclasse sobrepusesse o método e usasse uma variável de instância na versão de sobreposição?

R:

Eu poderia jurar que vi um código que chama um método em vez do nome da classe.

P:

~stático usando uma variável de referência

,......."
~

Você pode fazer isso, mas como sua mãe sempre lhe disse: "Só porque pode ser feito não significa que é bom." Embora funcione chamar um método estático usando qualquer instância da classe, isso leva a um código confuso (menos legível). Você pode escrever,
Duck d = n e w Duck(); Stri ng[] 5 = {} ; d . main (5) ;

R:

[

I I)

I

L _

r'--

___ Esse código é válido, mas o compilador apenas o converterá novamente na classe real ["Certo, d é de tipo Duck e mainO é estático, portanto chamarei o método estatlco mamO na ciasse uuciCrEm outras pal8ví8s, usai d paía chamar mainO não implica que mainO terá algum conhecimento especial do objeto que d está referenciando . Trata-se apenas de uma maneira alternativa de chamar um método estático, mas o método continuará a ser estático! você está aqui... 201

variáveis está\icas

Variável e_~tática: o valor é o mesmo para TODAS as instâncias da classe
Suponhamos que você qui sesse con tar qu antas in stânci as de Duck estão se ndo cri adas enquanto seu programa está sendo executado. Como faria isso? Talvez com um a vari ável de in stânci a que você incrementasse no con strutor?
cl as s Du ck ( i nt d uc kCount pub lic Duck() d u ckCount++; O;
isso sempze ~onfiguraria duckCo~t co~ 1 a ~--------------------------------------- vez que um objet0 Duck fosse criado

Não, isso não funcionaria porque duckCount é uma variável de instância e começará em O para cada objeto Duck. Poderíamos tentar chamar um método de alguma outra classe, mas seria confuso. Você precisa de uma classe que tenha apenas uma cópia da variável para que todas as in stâncias compartilhem essa cópia única.

É isso que uma variável estática lhe dará: um valor compartilhado por todas as instâncias de uma classe. Em outras palavras, um valor por classe, em vez de um valor por instância.
public cl a ss Duck ( pri v a te i nt s i z e ; p r i v at e stat i c int duckCount p ubli c Duck () du ckC ount++;
A variável e státi ca ducltCount SÓ é inicializada na primeira vez que a classe é
carregaãa e rJÃO sempre q'..le uma no'to""a

O;

( - - - --

- - - instância é criada.

publ i c vo id se tSi ze ( i n t s ) siz e = s ; p ub lic i n t g etSi ze () r e t urn s iz e ;

Agora ela c ontinuará a s e r incr ement a da sempre que o construtor de Duck for executado, porque duckCount é estática e n ã o será reconfigurada com o~

tJ"iTI objeto Duck nã.o tem su a própr ia cóp:i a de áuckCou!1c .. Já que ducJrCount é estática, todos os objetos Duc.k compartilham a mesma cópia da variávelw Você pode consíde~ar uma -variável estática como uma variá.vel que resiãe em uma CLASSE em vez de em um objeto.
~R"'~

~

size:

d uclcC ounc :

Ca d a obj e to Du c Je texn sua

, size: 8

~ ~uçkcount ;

4.

própria variável size; mas há apenas uma cópía da variáveL ãuckCount - a da cLasse •

. 202 . capítulo 10

números ", elementos estáticos

;).Ç'

As variáveis estáticas são compartilhadas.
primeir~

k"'
instancia
variável
segurlda i.nstància

de Jr/d

IcrÍ..:nça)
es~áci=a:

Todas as instâncias da mesma classe compartilham a mesma cópia das variáveis estáticas.
variávei s de in stância: 1 por instância variávei s estáticas: I por classe

K.
).<, ...~
'~;.'

~ ~
.

O :· -~

~)

. Halterofilismo cerebral

Anteriormente neste capitulo. vimos que um construtor ser privado significa que a classe não pode ser instanci ada a partir de um código que esteja sendo executado fora dela. Em outras palavras, só códigos de dentro da classe podem criar uma nova instância de uma classe com um construtor privado. (Há um problema do tipo 'a galinha ou ovo' aqui.) E se você qui ser criar uma classe de maneira que somente UMA instância dela possa ser gerada e qualquer pessoa que queira usar uma instância da classe tenha que usar sempre essa?

Inicializando uma variável estática
As variáveis estáticas são iniciali zadas quando uma classe é carregada. Uma classe será carregada quando a JVM decidir que é hora de carregá-Ia. NOlmalmente, a JVM carrega uma classe porque alguém está tentando criar uma nova instância dela, pela primeira vez, ou usar uma variável ou método estático da classe. Como programador, você também poderá solicitar à JVM que canegue uma classe, mas é provável que não precise fazer isso. Em quase todos os casos, é melhor deixar a JVM decidir quando carregar a classe. E há duas coisas garantidas na inicialização estática: As variáveis estáticas de uma classe são inicializadas antes de qualquer objeto dessa classe poder ser criado. As vmiáveis estáticas de uma classe são inicializadas antes de qualquer método estático da classe ser executado.

Todas as variáveis estáticas de uma -classe

sãQ
in.icializadas

i'j.!Z":"~F~~.~.
L:..
~

antes dê
qualquer objeto dessa classe poder ser criado.

~-:.

:. J ,"""

~.~ ~~:

c l a ss Play e r

{

h_
--~ -"

static int playerCoun t = O; p ri vate St ri ng name; public Player (Str i ng n ) { name = n; playerCount ++ ;

playerCount é inicializada quando a classe é car.regaàa ~ Inicializamos eJ~li c itamente e ssa variável com O, mas não precisa.ríamos fazer ( -- - - -- ---:-- - -- - - 'isso, já que O é o valor padrao para tipos int. As variáveis estáticas recebem valores padrão da mesma forma que as variáveis de instância.

J~,

p;

t~-tiL

I. r

h

publ i c c l ass Playe rTe s tDri v e ( public static v o id main ( String[) a r gs) { System. out . pr i n t ln(Playe r . playerCoun t ) ; -Player one - n e w Player (" 'l' ~ger w;;;;o"'o"'a't;s"'~",~- - -------A-c-e-ssa uma variável estática dã lneSlna roX"!na ; Sys t e m.ou t . p rintln( P l a yer. playerCount); que um método estático - com o nome da c lasse.

Os valores padrão para variáveis estátic:2$ e de instância decla r adas mas não inicia.lizadas são os .m esmos ;: tipos primitivos intei:t'os: (longo, cux·t:o, etc.): O tipos primitivos de ponto flutuante (flcat, double): 0,0 booleanos: falso referências de objeto: nulo

você astá aqL:!

II>

203

constantes estáticas finais

As variáveis estáticas são ini c iali zadas quando a classe é carregada. Se você não ini cializar expli cita mente um a Yeuiávei estática (atribuindo um valor qu-ando a declarar), era rece5eráuI 1 val ol:- pádrão. portanto variáve is in l 1são inicializadas com 0, o que significa qu e não precisamos dizer explicitamente "pl ayerCount = O . Declarar. " mas não inicializar, uma variável estática significa que ela receberá o valor padrão desse tipo de variáv el, da mesma forma que as variáveis de in stância recebem valores padrão quando declaradas.
r .
.

. .....

~
I

antes de qualquer instância ser criaãa

depois que um objeto é criado

As variáveis estáticas finais são constantes
Uma variável ser marcada com final significa que - quando inicializada - ela nunca poderá ser alterada. Em outras palavras, o valor da variável estática final permanecerá o mesmo enquanto a classe estiver carregada. Procure Math.PI no APl e você verá:
publ i c sta t i c final double PI = 3 .1 41592653589793 ;

A variável está marcada com public para que qualquer código possa acessá-la. A variável está marcada com static para que você não precise de uma instância da classe Math (que, lembre-se, não pode ser criada). A variável está marcada com final porque PI não se altera (no contexto Java). Não há outra maneira de designar uma variável como uma constante, mas há uma convenção de nomeação que o ajudará a reconhecê-la:

Os nomes das variáveis constantes devem ter somente letras maiúsculas!

Inicialize uma variável estática final:

(!) Na

hora em que a declarar:

public class Foo publi c static f ina l int F OO_X

25 ;

observe a convenção de nomeação as variáveis estáticas finais são constantes, portanto o noma deve estar todo em mai ú scula s, com um sublinhado separando as palavras.

1

Se você não fornecer um val or para uma variável final em um desses doi s locais:
publ ic cla ss Bar public static final double BAR_ SIGN; não há inicialização!

o compilador perceberá:

ou
~
Em um inicializador estático: public class Bar public static f inal double BAR_S I GN ; ' s ta ti c (.

I'\,BAR S I GN
} \
\ ,.

=

(double) Math . random( ) ;

esse código será executado assim que
êi.

cla sse fox.

;;,;õ.:r:xega,àd r

a nt es de

qualquer método estático ser chama.do e a~ ces mesmo fte ~~?-l~Jer varijvel estética poder ser usada.

204 _ capítulo ,1.Q..

números

elementos estáticos

A palavra-chave final não é usada apenas para variáveis estáticas ...
Você também pode usar a palavra-chave final para modificar variáveis não-estáticas, inclusive variáveis de instância, variáveis locais e até mesmo parâmetros de métodos. Em todos esses casos, ela teria o mesmo significado: o valor não pode ser alterado. Mas você também pode usar final para impedir que alguém sobreponha um método ou crie urna subclasse.

Variáveis não-estáticas finais
class Foof ( final int size = 3; final int whuffie; Foof () { whuffie
vocé .!lão pode altera.r s.ize

42;

~

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ agora v'oeê não pode alterar whuffi e

void doStuff (final int x) { II você não pode alterar x

void doMore ( ) final int z = 7 · II você não pode alterar z
}

Método final
class Poof ( final void calcWhuffie () { II coisas importantes II que nunca devem ser sobrepostas

Classe final
final class MyMostPerfectClass II não pode ser estendida

-

Não existem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Perguntas Idiotas
Um método estático não pode acessar uma variável não-estática. Mas um método não-estático pOde acessar uma variável estática?

P:

esperados. Se você precisar contar com uma implementação específica dos métodos de uma classe, marque-a como final.

sempre poderá chamar um método estático dela ou acessar uma variável estática da classe.

R:

É claro. O método não-estático de uma classe

Não é redundante ter que marcar os métodos como finais se a classe for final?
Se a classe for final, você não precisará marcar os métodos como finais. Pense bem - se uma classe for final ela nunca poderá ter subclasses, portanto nenhum dos métodos poderá ser sobreposto. Por outro lado, se você quiser realmente permitir que outras pessoas estendam sua classe e que possam sobrepor alguns, porém não todos os métodos, então, não marque a classe como final, mas marque -o-finais. Uni .. seletivamente métodos especrfícos com método ser final significa que uma subclasse não poderá sobrepor esse método específico.
VOCÔ

P:

Por que eu poderia querer criar uma casse final? Isso não invalida a finalidade da OO?
Sim e não. Uma razão típica para a criação de uma classe final é por segurança. Você não pode, por exemplo, criar uma subclasse da classe String. Imagine --'--=C--7 pro ema se alguém estendesse a classe String e substituísse pelos objetos de sua própria subclasse String, polimorficamente, onde objetos de String fossem

P:

R:

R:

"";;-""""'-

está

205

estático e finaí

DISCRIMI NAÇÃ-U-DOS PONTOS
..
~.

- Um método estático deve ser chamado com o uso do nome da classe em vez de uma variável de referência de objeto:
Math.random()
V S.

myFoo.go()

- Um método estático pode ser chamado sem que haja qualquer instância de sua classe no heap. - Um método ser estático pode ser adequado para um método utilitário que não dependa (e que nunca dependerá) do valor de uma variável de instância específica. - Um método estático não estará associado a um instância específica - somente à classe - portanto não poderá acessar valores de nenhuma variável de instância de sua classe. Ele não saberia os valores de que instância usar. - Um método estático não pode acessar um método não-estático, já que geralmente os métodos não-estáticos estão associados ao estado da variável de instância. - Se você tiver uma classe que sé tenha métodos estáticos e não quiser que ela seja instanciada, poderá marcar o construtor como privado. - Uma variável estática é aquela compartilhada por todos os membros de uma determinada classe. Há somente uma cópia da variável estática em uma classe, em vez de uma cópia por cada instância individual para as variáveis de instância. - Um método estático pode acessar uma variável estática. - Para criar uma constante em Java, marque uma variável como estática e final. - Uma variável estática final deve receber um valor na hora em que for declarada ou em um inicializador estático.
st a t i c {

DOG_CODE

420 ;

- A convenção de nomeação das constantes (variáveis estáticas finai s) define que o nome use somente maiúsculas.
- O valor de uma variável final não poderá ser alterado depois que for atribuído.

- A atribuição de um valor a uma variável de instância final deve OCOlTer na hora em que ela for declarada ou no construtor. - Um método final não pode ser sobreposto. - Uma classe final não pode ser estendida (ter subclasses).
"t

- " Apont e seu lá pis
~

O que é válido?
Dado tudo que vócê acabou de aprender sobre elementos estáticos e finais , quai s desses códigos seriam compi lados?

Mantenha-se

à direita

C!) public class Foo { static int x ; public void go() ( System. out . println(x) ;

o

public c l ass Foo3 { fin al i n t x; public void go() ( System . out . pri n tln(x) ;

~ publiC cl a ss Foo5 ( s t a ti c fi n a l i nt x

=

12 ;

public vo i d gO(final int x) Sy s t em . ou t . prin t l n (x) ;

~ public class Foo2 {
i nt x ' public static void go() ( System . out . p rintln( x ) ;

® public

c l ass Foo4 { static final int x

@ 12;

publiC class Foo6 ( int x = 12 ; public sta tic void go(final int x) Sys t em . out . printl n (x) ; (

public void go () System . out . print l n( x ) ;

206 capítulo 10

números e elementos e'státicos

Métodos de Math
Agora que sabemos como os métodos estáticos funcionam, examinemos algun s métodos estáticos da classe Math. Não veremos todos, apenas os mais importantes. Verifique seu APl para ver o restante inclusive sqrtO, tanO, ce i1 0, tloorO e asinO· , .

Math.random( )
Retorna um double entre 0,0 e (mas não inclusive) 1,0.
double rI = Maeh . random(); ine r2 = (ine) (Math .random( ) * 5);

Math.abs( )
Retorna o double que for o valor absoluto do argumento. O método é sobrecarregado, portanto, se você passar um int ele retornará um int. Passe um double e ele retornará um double.
int x = Math.abs(-240); II retornará 240 double d = Math.abs(240.45); II retornar á 24 0.4 5

Math.round( )
Retorna um inteiro ou um longo (dependendo se o argumento for um fIoat ou um double) arredondado para o valor inteiro mais próximo.
in t x ine y Math.r ound(-24 . 8f) ; Math.round(24 . 45f) ;

II re tornará -2 5 II retornará 24

+~~.~
'~"

:O~F

.~

Lembre-se de que números literais de ponto flutuante serão interpretados como tipos double a menos que você adicione o 'ff.

t

Math.min()
Retorna o valor que for menor entre dois argumentos. O método é sobrecarregado para usar tipos int, longo, float ou double.
i nt x = Math . min(24,240); II ret ornará 24 double y = Math.min(90876.5, 90 876 . 49); II r etornar á 90876.49

,«;
.".,.

:~
-~:~

Math.max()
Retorna o valor que for maior entre dois argumentos. O método é sobrecarregado para usar tipos int, longo, float ou double.
int x = Math .max(24,240); II retornará 240 doub le y = Math . max(90876 . 5, 90876.49); II retornará 90876.5

Empacotando um tipo primitivo
Em algumas situações você pode querer tratar um tipo primitivo como um objeto. Por exemplo, em todas as versões do Java anteriores à S.O, não é possível inserir um tipo primitivo diretamente em um conjunto como ArrayLi st ou HashMap:
int x = 32; Isso não funcionará a menos que você esteja usando a Java ArrayList Iist new ArrayList () ; 5.0 ou superior!1 Não há um método aãd(int) em ArrayList que list . add(x); (------------------------------ use um inteiro! IArrayList só tem métodos aãd ( ) que usam referências de objeto e não tipos primitivos.]

'" ..1 ' R·
,h;;~

,t4. ,

~--

Há uma classe empacotadora para cada tipo primitivo e já que as classes empacotadoras se encontram no pacote java.lang, você não precisará importá-las. Você conseguirá reconhecer as classes empacotadoras porque elas foram nomeadas de acordo com o tipo primitivo que empacotam, mas com a primeira letra em maiúsculo para obedecer a convençãode nomeação de cl asses.

~ , .
~

;, L~?l2à,

------------ -------------

você está aqui..

207

~------------------------------------------------

métodos estí:Íticos

Ah sim, pú razões que absolutamente ninguém no planeta sabe ao certo, os projetistas do APl decidiram não mapear os nomes exatamente do tipo primi'(ivo-para o t1.po da clãsse.\iõCê entenaei'"á o que quererrios dizer:

~ ,'

 ,

-,

Boolean Character Byte Short Integer Long Float Double Empacotando um valor
int i = 288; Integer i Wrap = new Integer(i);
(~-----------------------primitivos~

~

Cuidado! Os nomes não roram mapeados exatamente conforme os tipos Os nomes das classes foram escritos por extenso~

Fornece o tipo primitivo para o construtor do empacotador. Apenas isso

Desempacotando um valor
int unWrapped = iWrap .intValue();

Todos os empacotadores funcionam assim. (----------------------- Boolean tem um construtor booleanValue()r Character tem charValue()r etc.

~ objeto

'-

Quando você precisar tratar um tipo primitivo como um objeto, empacote-o. Se estiver usando qualquer versão do Java anterior à 5.0, você fará isso quando precisar armazenar um valor primitivo em um conjunto como ArrayList ou HashMap.
tipo primitivo

tipo primitivo
o.bjeto Integer

Nota: a figura anterior é um chocolate em um pacote de papel laminado. Captou? Um pacote? Algumas pessoas acham que parece uma batata assada, mas isso também funcionaria.

,jit .,,~

...-I..

Antes do Java 5.0, nós é que tínhamos que fazer tudo ..
Ela está certa, Em todas as versões do'Íava anteriores à 5.0, os tipos primitivos eram tipos primitivos e as referências de objeto eram referências de objeto, sem NUNCA serem tratados de maneira intercambiável. Sempre cabia a nós, os programadores, criar o empacotamento e o desempacotamento. Não havia como passar um tipo primitivo para um método que usasse uma referência de objeto e como atribuir o resultado de um método que retornasse uma referência de objeto diretamente a uma variável primitiva -- mesmo quando a referência retornada era atribuída a um objeto Integer e a variável primitiva era um inteiro. Simplesmente não havia relacionamento entre um objeto lnteger e UIll tipo int, exceto pelo fato de Integer ter uma variável de instância de tipo int (para armazenar o tipo primitivo que esse objeto empacotava), Tudo tinha que ser feito por nossa própria conta.

'~.'.

208 capítulo 19

números e elementos estáticos

Uma ArrayList de tipos primitivos inteiros
Sem o auto-empacotamento (versões da Java anteriores à 5 .0)
public void doNumsOldWay() Ar r a y List l i stOfNumbers
Cria lime ArrayList", que antes da. v0rsão 5~ Q não podiamos f?,specif:.ic.:ar o TIPO, portanto tedas as ,2!.rrayLists era.m new Array Li st(); ~---------- listas de tipos Object.)

listOfNumbers . add(new Integer(3» ;

t!-- - - -- - - -- -

Você não pode adic _ ionar o tipo primit,l'íTo t3'" â lista, portanto terá ('re,e empacotá-lo em um
objeto Integer
ant&s~

Intege r one

(Integer) listOfNumber s . g e t(O) ; t!-- - - - Será capturado COl!! o tipo Object, mas '1'ooê pode convertê-lo para .Integer • one . intValue() ;
.( __ _ _ _ _ __ _ _ _ _ Fina.lmente você pode exc,raí.1._ primiti'vo de :rnt$geX'~
o

i nt i n t One

tipo

Auto-empacotamento : tornando obscura a linha divisória entre tipos primitivos e objetos

o recurso de auto-empacotamento adicionado ao Java 5.0 faz a conversão de tipo primitivo para obj eto empacotador auto maticamente!
Vejamos o que acontecerá quando quisermos cri ar uma ArrayList que armazene inteiros .

Uma ArrayList de tipos primitivos inteiros
Com o auto-empacotamento (versão 5 .0 da Java ou posteriores)
Cria. uma ArrayList 6.e típo Intege- ::" J Embora lVÃO haja um método

public void doNumsNewWay()

(

~
new ArrayList <Integer> ();
Basta adicionar!

ArrayList <Int e g e r > listOfNumbers listOfNumbers .add(3); i n t num

=

li s tOfNumbers . get(O) ;

E o cO.!flpila.do:r:· oese;lllp,~c{)t; (converterá) automaticamente o objato Integer para que você possa atribuir o valor int d í r etamente a um tipo primitivo sem ter ~le cbamar o método intValue{ ) no objstc Int$gor~

addtint) na classe ArrajrList", o compilador fará todo o trabalbo de empacotamento (encapsula.mento) para você" Em outras pa~aYr{is", na ve,r ãE!de " ~~€ está armazenado na Arra,yJ4ist É tOO abjeto Integer; mas você terá que "t;"azeX" de conta""" que ela. usa i:n:teiro.s.., (Você poda adiciona.J:' t3121:0 inteiros qua.uto objetos Integer a ArrayList<Integer>.)

Por que não declara r uma ArrayList< int> se qu isermos armazenar inteiros?

;~

;~=­

'K'

~~-'
~..

Porque ... Não é possível. Lembre-se de que a regra dos tipos genéricos diz que você pode especificar somente tipos de classe ou interface e não tipos primitivos. Portantq, ArrayList<int> não seria compilada. Mas, como você pode ver no código anterior, isso não importa , já que o compilador permite que você insira inteiros em ArrayList<lnteger> . Na verdade, não há uma maneira de impedir que você insira tipos primitivos em uma ArrayList onde o tipo da lista fo r o mesmo que o do empacotador do tipo primitivo, se estiver sendo usado um compilador ,compatível com o Java 5.0 , já que o auto-empacotamento ocorrerá automaticamente. Portanto, você pode inserir tipos primitivos booleanos em ArrayList<Boolean> e chars em ArrayList<Character>.

h
j

O auto-empacotamento funciona em quase todos os locais
comuns para usar tipos primitivos em um conjun to .. . Ele tam bém deixará que use um tipo primiti vo ou seu tipo empacotador em qualquer local onde um ou outro for esperado. Pense nisso ! você está 209

_Jr""i~- ---ü .auto-empaGotame!ltg-pe.rmitirá quevoº€-faç.a-!=illli.-s-C.lo...q.U.f~--ap~'ls-o. e-m.p~ame.DjO e desempacotamento

'--F\-'-

I

l~

métodos estáticos

Diversão com o auto-emRc:l~ot~JTIen~
3

Argumentos do método
Se um método usar um tipo empacotador, você poderá passar a referência de um empacotador ou um valor primitivo do tipo correspondente. E é claro que o invers o também é verdadeiro - se um método usar um tipo primitivo, você poderá passar um tipo primitivo compatível ou a referência de um empacotador desse tipo primitivo . void takeNumbe r (Int eger i )

Valores de retorno
Se um método usar um tipo de ret orno primitivo, você poderá retornar um tipo primitivo compatível ou a referência de um empacotador desse tipo primiti v o. E se um método declarar um tipo de re to rno empacotador, você poderá retornar uma referência do tipo empacotador ou um valor primitivo do tipo correspondente.

int gi veNumber ()
return x;

verdadeiro v 4irdadei Jb
~ e~

Expressões booleanas
Em qualquer local onde um valor booleano for esperado, vo cê poderá usar uma expressão que resulte em um booleano (4)2), um booleano primitivo ou a referência de um empacotador boo l eano .

~

f\\ ~ªL.
.~ ~

boo~ ~booleano
if (bool ) System . out.println("true");

Operações e números
Talvez esse seja o local mais estranho - sim, agora você pode usa r um tipo empacotador como operando em operações onde o tipo primitivo for esperado. Isso significa que se pode aplicar, digamos, o operador de incremento à referência de . um objet o In teger! Mas não se preocupe - isso é apenas um truque do compilador. A linguagem não foi modificada para fazer os operadores funcionarem em objetos ; o compilador simplesmente converterá o objeto em seu tipo primitivo ant e s da operação . No entanto, parece me s mo estranho . Integer i
i++;

3

=

new Integer(42);

i++ ;

E isso signif ica que você também poderá fazer coisas como : Integer j Integer k new Integer(S);
j
+ 3; 3

Atri bu i ções
Você pode atribuir um empaco tado r ou um tipo primitivo a uma variável declarada com o tipo empaco tador ou primitivo correspondente. Por exemplo, uma var i ável primitiva int pode ser atribuída a uma variável de referência Integer e vice - versa - a referência de um obje t o Integer pode ser atribuída a uma variável dec larada com um tipo pr imitivo int .

Double d = x ;

210

capítulo 10

números e elementos estáticos
.~ .

~10~,
{-...;
,

~; ,
~_

.

_. ,Aponte seu lapls

..

_

public clas s TestBox In teger i; in t j;

Esse código será compilado? E executado? Se for, o que fará ? Faça uma pausa e analise esse código; ele demonstra uma implicação do auto-e mpacotamento sobre a qual não falamos . Você terá que acessar se u compilador para encontrar as respostas. (Sim, estamos forçando você a fazer testes, para seu próprio bem.)

public static void main (String[] args) TestBox t = new TestBox(); t . go ();

(

public void go () ( j=i ; System. out . pr int ln(j) ; System. out . pri ntln(i ) ;

Mas espere! Há mais! Os empacotadores também têm métodos utilitários estáticos!
Além de agir como uma classe comum, os empacotadores têm vários métodos estáticos realmente úteis. Já usamos um neste li vro - Integer.parselntO. Os métodos de conversão usam um objeto String e retornam um valor primitivo.

Converter um objeto String em um valor primitivo é fácil:
Str ing s = "2"; i nt x = I nteger . parse In t (s) ; ~ 1--------------- Não há problemas em convert e r "2' em 2 . double d = Double . par s eDouble("420 . 24"); bool ean b

=

new Boolean("t r ue"). 'booleanValue();

Mas se você tentar fazer isto:
String t = "two"; int y = I nteger . pars e Int(t);

Você está pensando que deveria haver um ( - - - - método Boolea.'lparseBoolen(); não está? Nas nãe há. Felizmente há mn construtor de Bollean que usa (e converte) um objeto String e você SÓ terá que desempacotar o v alor pr i mit ivo para c apturá-l o.

Opa. Isso será c~~pilado cerretamente, mas no tempe de execução travará. Qualquer coisa ~(~-------------- ~Je não possa ser convertida em um número causará uma exceção ~hunberFormatException

Verá uma exceção de tempo de execução:
Todo método ou construtor que converta um objeto String pode lançar uma exceção NumberFormatException. Trata-se de uma exceção de tempo de execução, portanto você não terá que manipular ou declará-Ia. Mas talvez queira.
(Falaremos sobre exceções no próximo capítulo.)

E agora o inverso ... Convertendo um número primitivo em um objeto String

t
l!

~

Há várias maneiras de converter um número em um objeto String. A mais fácil é simplesmente concatenar o número a um objeto String existente.

__

~~.

double d

Lembre-se de que o operador '+' é s obrecarregado em Java (o único operador sobrecarregado) para a conc atenação d e String doubleString = "" + d; ( - - - - - - - Strings. QU<ilquer coisa que for adi ci on ada a um objato _. - -

=

42 .5;

-

~ - --~ -- - -

double d = 42 .5 ; String doubleString

Double.toString(d); ~------- estático da class e Dcubl$.

Outra maneira de. fazer isso é u sar

UJrt

mé todo

você está aqui

\It-

211

formatação de illime,03

l
.. -

" f

~

~

Formatação de números
Em Java, formatar números e datas não tem que estar associado à EIS. Pense nisso. Uma das maneiras mais comuns de exibir números para um usuário é através de uma GUI. Você inserirá as Strings em uma área de texto de rol agem ou talvez em uma tabela. Se a formatação fosse construída somente em instruções de impressão, você nunca poderia formatar um número em uma String adequada à exibição em uma GUI. Antes do Java S.O , grande parte da formatação era manipulada através de classes do pacote java.text que não examinaremos nesta versão do livro, já que houve alterações. Em Java S.O, a equipe Java adicionou uma formatação mais poderosa e flexível através da classe Formatter de java.util. Mas você não terá que criar e chamar métodos da classe Fonnatter, porque o Java S.O adicionou métodos convenientes a algumas das classes de EIS (inclusive printf()) e à classe String. Portanto, é uma simples questão de chamar um método String.fonnatO e passar para ele o que você quiser que seja formatado junto com as instruções de formatação.
É claro que você terá que saber como fornecer as instruções de formatação , e isso demandará algum esforço, a menos que esteja familiarizado com a função printf( ) da CIC++ . Felizmente, mesmo se você não conhecer prinfO, poderá simplesmente seguir as etapas da maioria das operações básicas (que mostraremos neste capítulo). Mas talvez queira aprender como formatar para usar todos os recursos e fazer o que quiser.

.Y.

- '~_

..

·1

I

Formatando um número para que use pontos
public clas s Te s t Forma t s {
/

~. '
~~'-

o número a formatar (queremos
que

ele tenh a pontos).

~.~'

public stat ic vo i d mai n (S tring [ ] 'args) Str ing s = String. format ("%. Sy s tem. ou t. println(s) ;

'{

d" I

1000000000);

As instruções de fonna.taçã o que ÍJ,dicam como fonnatar o segundo argumento (que nesse caso é um valor ínt). Lembre-se de que a~~i há somente dois argumentos no método - a primeira vírgula faz parte da String literal, portanto não está separan.do argumen,tos do método Le,rmat:.

1"

1.000.000.000
• ..> •• ,

~4,gora

temos

pontos inseridos no nU,l!!ero ..

212 capítulo 10

números e elementos estáticos

Detalhando a formatação .. .
No nível mai s básico, a formatação é composta de duas partes principai s (há mais , porém começaremos dessa forma para manter o ass unto mais simples):

(I) Instruções

de formataçã o Você usará especificadores especiais de formato que descreverão como o argumento deve ser formatado .

~ O argumento a ser formatado
Embora pos s a have r mais de um argument o , começaremo s com ap e nas um . O t i po do a rgumen t o nã o p ode s er simple smen te qualquer coisa . .. Te m que se r algo que possa s er format ado com o uso d os espec i ficadores de fo r mato nas instruções de formatação. Por exemplo, se suas instruçõe s de formatação especificarem um número de ponto flutuante , você não poderá passar um objeto Dog ou mesmo uma Str i ng que se pareça com um número de ponto flutuante .
Faça i s to ••. Com isto.

Nota: se você já conhece o método printf(} da CIC++, talvez só precise examinar super ficial men te as p ;!'óx;Ímas pági n a s. Ca s o c ontrári o, leia cuidadosamente!

@

®

format("%. d", 1000000000);

?

,

rIse essas :i.I/.Struções ••• Nesse arg-.mIellto.

Qual o significado real dessas instruções?

,

j~--_

.I ,.=-;

"Pegue o segundo argumento desse método, formate-o como um inteiro decimal e insira pontos ."

Como isso é informado?

. ~ Na próxima página examinaremos com mais detalhes o que a sintaxe "%. d" realmente significa, mas , para .:' começar, sempre que você se depar ar com o sinal de percentual (%) em uma String de formato [que é sempre "h o primeiro argumento de um método formatO] , considere-o como a representação de uma variável, que será o ". ';.,.,,: _- outro arg~mento do método. O restante dos caracteres após o sinal de percentual descrevem as instruções de :~ .~- formataçao do argumento.

~
'~';

o percentual (%) representa "insira o argumento aqui" (e formate-o
usando essas instruções)
O primeiro argumento de um método formatO é chamado de String de formato e pode incluir caracteres que você queira simplesmente que sejam impressos no formato original, sem formatação adicional. No entanto, quando você se deparar com o sinal %, considere-o como uma variável que representa o outro argumento do método.
Carac t e res a

inclu ídos na String fi nal ret o r nada p or
ser€17l

Especificadores de fo:rmato para o segundo argumento do método (o nÚ.l nero) •

F
(r\

"

__ ,_o"

\

Mais caracteres a serem i n cluído s na String após o segundo, argumento ser formatado e inserido.

Argumento a ser for ma t ado.

,r-,, __ .\_/- ",.,.-. __ ... _ -._.

'_""'_~" " ' _._ . ______ .... .

-'-'-"-",

format("Tenho %,2f erros a corrigir.", 476578,09876);
Saída

J

E1,......
1~ "
~,,.-.,.

Tenho 476578,10 erros a corrigir.
0 0 '· 0

Observe que perdemos alguns dos números após a vírgula d e cimal. Entendeu o que U12r" significa?

Q -3'l......... l '-'('jf-',.....:---C\..Jl Jl1aJ.(.l. c.lV ... .Q.~Lr~_rl Clo-L""".,,.......,.f.lot--O 'O.;.;o ; u a 1 lU IIU . . . .-.--.,.-~...,.._U .•, ...... Ul.:') V U\,.; .l VÜUUl.Ll~ U\.J

.tJl..U LA

.1 .... v

i n cp'''';

r

......... o.

0
\.J

°1
.......

• .,. dtfe-Rfg-H+p.g.H-te-9--9---ffi@..tod g [o segund o

argumento de formatO, o número] aqui E formatá-lo usando os caracteres ",2f' existentes após o sinal. Em

!0

L _. seguIda, o resto da String de formato, "enos a corrigir", será adicionado à saída final. _
.. ,

i= -

você está aqui

~

213

o método forrratO

Adicionando um ponto

-------------format("Tenho %.,2f erros a corrigir.", 476578,09876);

.
~enho

.

.

Ao alterar as instruções de
formato de 1l%" 2f u para n%.. r 2fR', 'teremos um ponto no

476.578,10 erros a corrigir.

número formatado.

A String de formato usa a sintaxe de sua própria linguagem
É claro que você não pode inserir qualquer coisa depois do sinal "%". A sintaxe para o que pode entrar após o sinal de percentual segue regras muito específicas e descreve como formatar o argumento que será inserido naquele ponto da String (formatada) do resu ltado.

Você já viu dois exemplos:

%.d significa "insira pontos e formate o número como um inteiro decimaL",
% ,2f significa "formate como um número de ponto flutuante com precisão de duas casas decimais."
e

%.,2f significa "insira pontos e fOlmate como um número de ponto flutuante com precisão de duas casas decimais .".
A pergunta certa seria: "Como saberei o que inserir após o sinal de percentual para que ele faça o que desejo?" E isso inclui conhecer os símbolos (como "d" para decimal e " f' para número de ponto flutuante) assim como a ordem em que as instruções dever:n ser inseridas após o sinal de percentual. Por exemplo, se você inserir o ponto depois do "d" desta forma: "%d." em vez de "%.d" não funcionará! Ou funcionará? O que você acha que conseguirá com isso:
String . format("Tenho %,2f . erros a corrigir.", 476578.09876 ) ;

(Responderemos a seguir.)

o especificador de formato
Tudo o que vier após o sinal de percentual até e incluindo o indicador do tipo (como "d" ou "f') fará parte das instruções de formatação. Depois do indicador do tipo, o método de formatação presumirá que o próximo conjunto de caracteres deve fazer parte da String de saída, até ele atingir outro sinal de percentual (%) . Hmmmm ... Isso é possível? Você pode ter mais de uma variável como argumento a ser formatado? Deixe essa questão em suspenso por enquanto; retornaremos a ela em breve. Até lá, examinaremos a sintaxe dos especificadores de formato - os elementos que entram após o sinal de percentual (%) e descrevem como o argumento deve ser formatado.
Um especificador de formato pode ter até cinco partes diferentes (sem contar o U%"). Tudo que estiver entre [ ] abaixo é opcional, portanto só o percentual (%) e o tipo são obrigatórios. Mas a ordem também é obrigatória, logo, qualquer parte que você usar deve seguir essa ordem.

214 capítuig 10

números e elementos estáticos

Fal aremos s obre isso depois ... Essa parte permi t irá que você informe QUl'o.L é o argumen to se houver mais de Ulll . (Não se preocupe com essa questão por enquanto.)

~

%[número do argumen~agSJ [t ~nhOJ [,precisão] tipo ,,\

Esses e.l emen t: os seQ as

opções especiais de formatação como a inserção de pontos. colocar os números
n e gati v os eJU parên tese s
ou fazer com que os números sejam alinhados

lrJIr.;xr~1A

De.f.i ne a qua.ntida.de dos caraccarC:3 que serão usados.

á esquerda.

Infor&a o minimo e não o TOTAL. Se o número fo r mai o r do que o trunanho especificado J ela ainda será usado por completo, mas, se for menoz' , será completado com zeros.

Você já conhec e czca parte#4' Z~a define a precisão. Em outras pala.vras, configure a quantidade de casas ãecímais .. Não se esqueça de inc~uir a UrN ai.

o tigo

.fi!

obrigatorio (consulte o próximo item) e geralmente é "d" para um ínteíro decimal
ou nfN para um

número de ponto flutuante.

%[ número do argumento] [flags] [tamanho] [,precisão]tipo

. . . _ /~---::.ro ._
format( " %. 6,lf ", 42.000)
-- -----~~

do argumento l ' não foi

especificado nessa String de

o único especificador obrigatório é o do TI PO

formato r mas todas as outras partes estão a.í.

Embora o tipo seja o único especificador obrigatório, lembre-se de que se você in serir algo mais, o tipo deve vir sempre por último ! Há mais de uma dezena de modificadores de tipo diferentes (sem contar as datas e horas ; elas têm seu próprio conjunto), mas provavelmente você usará mais %d (decimal) ou %f (ponto flutuante). E normalmente combinamos %f com um indicador de precisão para configurar a quantidade de casas decimais que desejamos em nossa saída.

o TIPO é obrigatório,
%d decimal
format ( "%d" , 42);
,

o restante é opcional.
;f.,, - - - - - - - - - - - '
.4 2.25 não :funci.onari a I SeriÇ. o mesmo que tentar a tribuir

diretamente um doubla a uma variável int.

o

argumento deve ser compatíve l com um inteiro, portanto isso significa apenas tipo s byte, curto, int e char (ou seus tipos empacotadores) .

%f

ponto flutuante
Aqui cow namos o "f " com um irldíca.dor de precisão .bi portanto acabaremos usando três z eros.

format( "%,3f" , 42,000000);

42,000
o argumento deve ser um tipo de ponto flutuante, portanto i ss o
significa apenas um float ou um double (primitivo ou empacotador) assim como algo conhecido como BigDecimal (que não examinaremos neste livro) .

%x

hexadecimal
( "~oX" ,

__V\ _.
1"'-""
I

f ormat

42);

f\

r
\.

o argumento deve ser um tipo byte, curto, int, longo (incluindo tanto os tipos primitivos quanto os empacotadores) ou Biglnteger.

.. ~

%c

caractere

Você dever incluir um tipo em suas instruções de formato e. se especificar outras coisas além do ti po, ele terá que vir sempre por último. Na maioria das situações, o mais provável é que você fo rmate números usando "d" para decimais e 'T para número de ponto flutuante.

format ( "%c" , 42);

o número 42 representa o caractere

o argumento deve ser um tipo byte, curto, char ou int (incluindo tanto
os tipos primitivos quanto os empacotadores) .
,.~

você está aqui

ir

215

argumentos de forrnêto

o aue aconteceria se eu tivesse mais de um araumento?
• . - - - ------ ---- - -.- - - --- -- --0 - - - - -

Suponhamos que você tivesse uma String com esta aparência: "A posição é a de número 20.456.654 entre as 100.567.890,24 existentes." Mas os números fossem extraídos de variáveis. O que você faria? Simplesmente adicione dois argumentos depois da String de formato (primeiro argumento), para indicar que sua chamada a formatO terá três argumentos em vez de dois. E, dentro desse primeiro argumento (a String de formato), você terá dois especificadores de formato diferentes (dois elementos que começam com "%"). O primeiro especificador de formato inserirá o segundo argumento do método e o segundo especificador inserirá o terceiro argumento. Em outras palavras, as inserções de variáveis na String de formato usarão a ordem com que os outros argumentos forem passados para o método formatO.

.'int one = 20456654; double t wo = 1 0 056789 0 . 2 48907; String s = String. format (A posição é a de número %.d entre as %.,2f existentes",

one,

twO );

Adicionamos pontos às duas variáveís e limitamos o n úmero de ponto flutuante ( a segunda variável) a duas cas a s d ecimai s .

Quando você tiver mais de um argumento, eles serão inseridos na ordem em que forem pa s sados para o método
fo=mat(,1 .

Como você verá quando chegarmos à formatação de datas, podemos querer aplicar especificadores de formato diferentes ao mesmo argumento. Isso pode ser difícil de imaginar até que você veja como a formatação de datas Ce não a formatação de números com a qual estivemos trabalhando) funciona. Por enquanto você só precisa saber que em breve, verá como ser mais objetivo quanto a que especificadores de formato serão aplicados a que argumentos.

'- ~~ 6
~ .'
.

""

!~.
1~

....

,..

.,
~

Hum, há algo REALMENTE estranho acontecendo aqui. Quantos argumentos posso passar? Quero dizer, quantos métodos formatO sobrecarregados existem NA classe String? E o que acontecerá se eu quiser passar, digamos, dez argumentos diferentes a serem formatados para uma única String de saída?
Boa pergunta. Sim, há algo estranho (ou pelo menos novo e diferente) acontecendo e não há vários métodos formatO sobrecarregados que usem uma quantidade diferente de argumentos possíveis. Para dar suporte a esse novo APl de formatação (semelhante a printf) em Java, a linguagem precisou de outro recurso novo - listas de argumentos de variáveis (chamados de varargs na abreviação). Falaremos sobre os varargs somente no apêndice porque, exceto na formatação, provavelmente você não os usará muito em um sistema bem-projetado.

P:

R:

Tantos detalhes quanto aos números, mas e as datas?
Suponhamos que você quisesse uma String com essa aparência: "Sunday, Nov 282004". Você diria que não há nada de especial aqui? Bem, suponhamos que inicialmente você só precisasse de uma variável de tipo Date - uma classe Java que pudesse representar um carimbo de hora - e agora quisesse pegar esse objeto (e não um número) e enviá-lo para o método de formatação. A principal diferença entre a formatação de números e a de datas é que os formatos de data usam um tipo de doi s caracteres que começa com "t" (e não o caractere exclusivo "f' ou "d" , por exemplo). Os exemplos a seguir devem lhe dar uma boa idéia de como funciona:

. 216 caritu!o 10

números e elementos estáticos

A data e a hora completas
s t ring . format ( "%tc" , new Date () ) ;

%tc

Sun Nov 26 1~:_5Z:41 MST 2004 Apenas a hora
string . forrnat ( "%tr" , new Date () ) ;

%tr

03:01:47 PM Dia da semana, mês e dia do mês %tA %t8 %td
Mas isso significa que

teremos que passar o objeto
Date três
vezes~

Não há um especificador de formato exclusivo que faça exatamente o que queremos, portanto temos que combinar três deles para obter o dia da semana (%tA), o mês (%tB) e o dia do mês (%td) .
Date today = new Date(); String. forrnat ( "%tA, %tB %td" , today, today , today) ;

uma para

cada parte do formato que selecionamos. Em outras palavras, o e s pecificador %tA nos fornecerá apenas o
dia da semana, depois teremos que passar o argumento novamente para

A vírgula não faz parte da formatação .•. É apenas o caractere que queremos

T

obter apenas o mês e mais ~~ vez pare o dia do mês .

. exibir depois do primeiro argumento formatado que for inserido.

Sunday, November 28

. %tA %t8 %td

A mesma situação anterior, porém sem duplicação dos argumentos
o
Date today = new Date(); String . forrnat ("%tA , %< tB %< td", today) ;

sina l menor que " <" é apenas outro flag do especificador que informa ao método de formatação para "usar o argumento anterior novamente U • Portanto, ele evitará a repetição dos argumentos e em vez disso você formatará o mesmo argumento de três maneiras diferentes. '

Você pode considerar isso como se estivéssemos chamando três métodos de captura diferentes n o objeto Date r para obter suas três ~artes distintas referentes à data.

Trabalhando com datas
Você vai ter que fazer mais coisas com as datas do que apenas capturar a data de hoje. Vai precisar que seus programas ajustem datas, calculem intervalos de tempo, priorizem prazos, criem agendamentos. Você precisará de recursos de manipulação de datas de nível industrial. É claro que você poderia criar suas próprias rotinas de data .. . (E não esqueça dos anos bissextos!) E, bem, aqueles irritantes e acidentais segundos a mai s. Nossa, isso pode ficar complicado. A boa notícia é que o APl Java está cheio de classes que poderão lhe ajudar a manipular datas . Às vezes acho até que há classes demais ...

:~
"~

Avançando e voltando no tempo
Digamos que a semana de trabalho de sua empresa vá de segunda à sexta. Você recebeu a tarefa de calcular o último dia de trabalho de cada mês desse ano no calendário ...

. ~.

,r
h

h

Parece que o pacote java.util.Date está realmente ... Desatualizado
Anteriormente usamos java.lltil.Date para saber a data de hoje, portanto o lógico seria que essa classe fosse um bom local para começarmos a procurar alguns recursos práticos de manipulação de datas , mas quando você verificar o APl descobrirá que a maioria dos métodos de Date foi substituída!

~--

, r· -·

j~JA.

ii

você está aqui >-

217

.r--...

manipulando dat&s A classe Date ainda é ótima para a captura de um "carimbo (marca, indicador) de hora" um objeto que represente a data e hora atúai s; põi1anto use-a-quando qui ser dizer "torneça os dados ATUAlS ". A boa notícia é que o APl recomenda a classe java.util.Calendar como substituta, portanto iremos exami ná-la:

Use java.util.Calendar em sua manipulação de datas
Os projetistas do APl Calendar queriam pensar literalmente de maneira global. A idéia básica é que você solicite um objeto Calendar (através de um método estático da classe Calendar que veremos na próxima página) quando quiser trabalhar com datas e que a JVM retorne a instância de uma subclasse concreta de Calendar. (Na verdade Calendar é uma classe abstrata, portanto você estará sempre trabalhahdo com uma subclasse concreta.) No entanto, o mais interessante é que o tipo de calendário que você obterá senl adequado ao local onde estiver. Grande parte do planeta usa o calendário gregoriano, mas, se você estiver em uma área que ele não seja utilizado, poderá fazer com que as bibliotecas Java manipulem outros calendários como o budista, o islâmico ou o japonês. O APl Java padrão vem comjava.utiI.GregorianCalendar, portanto será essa classe que usaremos aqui. Geralmente, entretanto, você não terá nem mesmo que pensar no tipo de subclasse Calendar que estará usando e em vez disso só terá que se preocupar com os métodos da classe Calendar.

Para obter um carimbo de hora do momento "atuar, use Date. Para qualquer outra coisa , use Ca!endar.

Capturando um objeto que estenda Calendar
Como seria possível capturar uma "instância" de uma classe abstrata? Bem, é claro que não é possível, isto não funcionará:

Isto NÃO funcionará:
Ca lendar cal = new Calendar ( ) ; li(
o compilador
não permi tirá isso!

Portanto, use o método estático "getinstance( )":
Calendar cal = Calendar. getlnstance () ;
~d._ _ _ _ _ :Essa si ntaxe j á deve ser fam i l i a r , c namfundo um método e stát ico.

es tamos

Você não pode capturar uma instância de Calendar, mas pode capturar uma instância de uma subclasse conCreta de Calendar.
É claro que você não pode capturar lima instânci a de Calendar, porque Calendar é abstrata. Mas pode chamar métodos estáticos em Calendar, já que os métodos estáticos são chamados na classe, em vez de em uma instância específica. Portanto, você chamará o método estático getinstanceO em Calendar e ele retornará ... Uma instância de uma subclasse concreta. Algo que estenda Calendar (ou seja, que possa ser atribuído polimorficamente a Calendar) e que - por conseguinte - possa responder aos métodos dessa classe.
Em grande parte do planeta, e por padrão na maioria das versões da Java, é retornada uma instância de java.utiI.GregorianCalendar.

Trabalhando com objetos Calendar
Há vários conceitos-chave que você terá que compreender para trabalhar com objetos Calendar: - Os campos armazenam o estado - Um objeto Calendar tem muitos campos que são usados para representar aspectos de seu último estado, sua data e hora. Por exemplo, você pode capturar e configurar o an.o ou o mês de um objeto Calendar. - As datas e horas podem ser incrementadas - A classe Calendar tem métodos que permitirão qu e você ad icione e subtraia valores de vários campos, por exemp lo, "some uma i.lllidade ao mês" ou "subtraia três anos".
218 ..capítulo10

números e elementos estáticos

_ As datas e horas podem ser representadas em milissegundos - A classe Calendar permitirá que você converta e desfaça a conversão de suas datas para uma representação em milissegundos. (Especificamente, quantos mili ssegundos ocorreram desde 10 de janeiro de 1970.) Isso lhe permitirá efetuar cálculos precisos como "o tempo transcorrido entre duas datas" ou "somar 63 horas, 23 minutos e 12 segundos a essa data".

Um exemplo de como trabalhar com um objeto Calendar:
Calendar c = Calendar . getlnstance(); Configura a hora para 7 de janeiro de 2004 às 15;40. c.set(2004,O,7,15,40); ( - - - - - - - - - - - - - - - - - (Observe que o mês começa em zero.) long dayl = c.getTimeInMil1is(); day1 += 1000 * 60 * 60; c.setTimeInMil1is(day1); Converte para o
va~or

em

1tti~i$segundo$

Adiciona o valor de uma hora em milissegundos

(L.-------------------

e, em seguida , atualiza a hora .

System . out . println("new hour " + c.get(c . HOUR_OF_DAY» ); c.add(c.DATE, 35); System . out . println("add 35 days " + c.getTime(» ); c.rol1(c . DATE, 35); ( ----------------------------------Sys t em.out . println("rol135 days" + c.getTime(» ) ;

(Observe o sinal "+= " r ele é o me smo que dayl = dayl + ••• ) Adiciona 35 dias à data, o que deve nos levar para fevereiro.

"Avança" 35 dias a. partir dessa data. "Avança" a data 35 dias, fila s NÃO altera o mês!

Não estamos incrementando aqui, apenas c.set (c.DATE, 1); ~(~----------------------- "configurando" a dat a.
System. out .println("set to 1 " + c.getTime(» );

=~"o-

~

t:Destaques do APl Calenda r

Essa saída confirma como mil1is, add, roll e set funcionam.

Acabamos de examinar o uso de alguns dos campos e métodos da classe Calendar. Trata-se de um APl extenso, portanto só estamos mostrando alguns dos campos e métodos mais comuns que você usará. Após dominar alguns deles, será bem fácil submeter o resto desse APl à sua vontade.

DATE I DAY OF MONTH r.~~~~::~;-~::~=-::e~c~a:l~e~n~d~a~r~~~J ~
Captura/configura o d ' d '

_

-

CampOs-chave d

HOUR I HOUR OF "a a _DAY
Captura/configura o ....alor d

mes.

MILLr SECOND

a hora na notação de 12

Ou 24 horas.

Captura /conf; 0r MINUTE .. g'u a os milissegundos .

MONTH

Captura./con figura os

m~nut o s .

.

YEAR

Captura/çonfigura o

~ C"
me".

Captura /configu ra o ano

ZONE_OFFSET

.
;J

Li'

__ CQPtt:ra/~..!!l.igura

d:

F..:>.____

.

Outros...

-- --' .. '0

Ud VM'f emmilissegunaos.

j I.:

voce esrá aqui

~

219

importações (-:;státicas

Outros recursos estáticos! Importacões estátiça~ ___
Trata-se de uma novidade no Java 5.0 que é uma verdadeira faca de dois gumes. Algumas pessoas amam essa idéia, outras odeiam. As importações estáticas existem so mente para que você não precise digitar tanto. Se você odeia digitar, talvez goste desse recurso. A desvantagem das importações estáticas é que -- se você não for cuidadoso -- usá-las pode tornar seu código muito mais difícil de ler. A idéia básica consiste em sempre que você estiver usando uma classe estática, uma variável estática ou uma enumeração (falaremos mais sobre isso posteriormente), possa importá-las e evitar a digitação.

,~:.. .~
~.

;

Um código escrito da maneira tradicional:
import java.lang.Math; class NoStatic ( public static void main(String [J args)
-

(

System: out.println("sqrt " + , Math.sqrt (2.0));
~"'"

.

, ~y;s~_em.

out .println ("tan " + iMath: tan (60) ) ;

o

mesmo código, com importações estáticas:
""""""~,,_

,?~~-.-~ . =

1<

F mport st,a tic
iLho ,_
;();~.".>< ~.

java.lang '_ System~ol).t;

= ""

--

~4~_________________

A

~

sintaxe a ser usada na decl aração d e importações estáticas.

class WithStatic public static vo id main(String [J args) Oüt--::. println("sqrt " + ' sqrt( 2 . 0)) ; ' 0 i,t;.; println ("tan " +[ tan(60)) ;

Use cuidadosamente: As importações estáticas podem tornar seu código difícil de ler

As importações estáticas em ação.

\

1

Advertências e cuidados - - - - - - - - - - - - - - - - - - . . . . ,
- Se você for usar um membro estático apenas algumas vezes, recomendamos que evite empregar as importações estáticas, para tentar manter o código mais legível. - Se você for usar muito um membro estático (como na execução de vários cálculos com Math), então provavelmente será adequado usar a importação estática.
- É bom ressaltar que você pode usar curingas (.*), em sua declaração de importação estática.

- Um grande problema das importações estáticas é que não é muito difícil o su rgimento de conflitos de nomes. Por exemplo, se houver duas classes diferentes com um método "addO", como você e o compilador saberão qual usar?

220

capítulo 'lO

números e"elementos estáticos

Bate-papo na fogueira
Debate de hoje: Uma variável de instância usa de ironia com uma variável estática
Variável de instância
Não sei por que estamos fazendo issoc Todo mundo sabe que as variáveis estáticas são usadas apenas na criação de constantesc E quantas delas existem por aí? Acho que o APl inteiro deve ter, digamos, quatro? E nem sempre elas são usadasc Você precisa confirmar seus dados . Quando foi a última vez que examinou o APl? Ele está cheio de variáveis estáticas! Tem até mesmo classes inteiras dedicadas ao armazenamento de valores constantes. Há uma classe chamada SwingConstants, por exemplo, que está cheia delas. Cheia delas c Sim, repita isso, por favor. Certo, há algumas na biblioteca do Swing, mas todo mundo sabe que o Swing é apenas um caso especial.

Variável estática

À
~

Pode ser um caso especial, mas é importante! E quanto à classe Color? Não seria incômodo se você tivesse que lembrar os valores RGB para gerar as cores padrão? Mas a classe Color já tem as constantes definidas para o azul, roxo, branco, vermelho, etc. Muito prático.

k'
+~

Certo, mas, além de alguns recursos de GUI, cite um exemplo de apenas uma variável estática que todo mundo use cNo dia-a-dia. Que tal System .out para começar? O termo out de System.out representa uma variável estática da classe System. Você não terá que criar pessoalmente uma nova instância da classe System, apenas solicitar a ela sua variável out. Bem, esse é outro caso especial. E mesmo assim ninguém a usa, exceto em depuração. Ah, e a depuração não é importante? E veja algo que provavelmente nunca passou por sua menteencaremos os fatos, as variáveis estáticas são mais eficientesc U ma por classe em vez de uma por instância. A economia de memória pode ser enorme! Hum, você não está esquecendo de algo? O quê? As variáveis estáticas fazem o que podem para não se adequar à OO! Certo, então por que não voltar no tempo e usar a programação procedimental, já que falamos nisso? O que você quer dizer com não se adequar à OO? Você é como uma variável global, e qualquer programador que faça jus a seu PDA sabe que geralmente isso não é bom. NÃO sou uma variável global. Não é assim. Vivo em uma classe! Isso tem mu ito a ver com a 00, sabe como é, uma CLASSE. Não fico situada em qualquer local DO espaço; sou uma parte natural do estado de um objeto; a única diferença é que sou compartilhada por todas as instâncias de uma classe. Muito eficiente.
uma-t;.~~mas o nnnJe certo oão~é ~_ _ programação Orientada a Classes. Isso é estúpido. Você é uma relíquia. Algo que ajuda os antiquados a migrarem para a Java.

eh

h
c};( L",C

n
I"
'-

J,

~

t

.~

h I"

h

-h-

j"

Sim, voeê reside en1

h -h

você está aqui ii'

221

variáve l de instância vs. vBrí3ve; e:::t3iic2

Variável de instância

Variável estática
Certo, vamos parar por aí. ISSO definitivamente não é verdade. Algumas variáveis estáticas são absolutamente cruciais para um sistema. E mesmo as que não são cruciais com certeza são úteis.

Bem, certo, de vez em quando faz sentido usar uma variável estática, mas lembre-se: o abuso de variáveis Ce métodos) estáticas é a marca de um programador de 00 imaturo. Um projetista deve pensar no estado do objeto e não no estado da classe. Por que você acha isso? E o que há de errado com os métodos estáticos? Não há nada pior que os métodos estáticos , porque 'geralmente seu uso significa que o programador está pensando de maneira procedimental em vez de em objetos fazendo as coisas com base em seu estado exclusivo de objeto. Certo, sei que os objetos devem ser o foco de um projeto de 00, mas só porque há alguns programadores incompetentes por aí. .. Não confunda as coisas. Há uma hora e um lugar para o uso de vaLiáveis estáticas e, quando você precisar de uma, verá que não há nada melhor. Ceeerto. Engane-se o quanto quiser...

Seja o compilador

o arquivo Java dessa página representa um programa completo. Sua tarefa é personificar o compilador e determinar se esse arquivo será compilado. Se não for, como você o corrigiria, e se ele for compilado, qual será sua saída?

Se ele for compilado, qual dessas será a saída?
class StaticSuper{ static ( System.out.println("super static block");

Saída possível

StaticSuper{ System . out .println( "super constructor ");

public class Stat icTests extends StaticSuper ( static int rand; static rand = (int) (Math . random() * 6); System.out.println("static block " + rand);

Saída possível

StaticTests() System.out.println("constructor");

public static void main(String [] args) System.out.println("in main"); StaticTests s t = new StaticTests();

222

capítulo í O

números ", elementos estáticos

~rCíCiO

Este capítulo exp lorou o maravilhoso mundo estático elo Java. Sua tarefa é definir se cada uma elas instruções a seguir é verdadeira ou falsa.

Verdadeiro ou falso

1. Para usar a classe Math, a primeira etapa é criar uma instância dela. 2. Você pode marcar um construtor com a palavra-chave static. 3. Os métodos estáticos não têm acesso ao estado da variáve l de instância do objeto 'thi s' . 4. É boa prática chamar um método estático usando uma variável de referência. 5. As variáveis estáticas poderiam ser usadas na contagem das instâncias de uma classe . 6. Os construtores são chamados antes de as variáveis estáticas serem iniciali zadas. 7. MAX_SIZE seria um bom nome para uma variável estática final. 8. Um bloco inicializador estático é executado antes de o construtor de uma classe. 9. Se uma classe for marcada como final, todos os seus métodos devem ser marcados como finais. 10. Um método final só pode ser sobreposto se sua classe for estendida. 11. Não há classe empacotadora para tipos primitivos booleanos. 12. Um empacotador será usado quando você quiser tratar um tipo primitivo como um objeto. 13. Os métodos parseXxx sempre retomam uma String. 14. As classes de formatação (que não estão associadas à EIS) se encontram no pacote java.format.

Imãs com código lunar
Esse pode ser realmente útil' Além do que aprendeu nas últimas páginas sobre manipulação de datas, você precisará de um pouco mais de informação .. . Primeiro, as luas cheias ocorrem aproximadamente a cada 29,52 dias. Em segundo lugar, a lua estava cheia em 7 de janeiro de 2004. Sua tarefa é reconstruir os trechos de código para criar um programa Java funcional que produza a saída listada mais à frente (mais algumas datas de lua cheia). (Você pode não precisar de todos os imãs, portanto adicione todas as chaves que forem necessárias .) Ah, e a propósito, sua saída será diferente se você não vive no fuso horário da montanhas.
l ong
-" L , Qit ; "

dayl

=

c. getTimeInMillis () _ ;

~-,r ' _~~ ,"-

L." .+_-,i>~J'{f%,

r---~mport
L_ _

static

java.lang.System.out i

::~~==~~~~~~~~~~
static int DAY_ IM
on %tc ",
C»i

=

60 *

60
\

L

~_"....._~~~ ~ew...:.. :,:e:.:n~da~r~(~); C . =_n "," ca::l
public

Calenda r

.

tL------J'.
[] args) {

f

j

~------------~l--======~
static void main (String

I

import

java. util. *; ~~r

~t

-s t- t~ c i- po r-t-j--a 1--- s-s t-e-rn-.o u t; - a--~ rn-' av -.- an g .- y -

b

voce está aqui

I>

223

....---"" ~--~~-

soluções dos exercícius

Soluções dos exerc!cios

Seja o compilador
StaticSuper ( Syst em.out . print l n( 'super constructor");

Verdadeiro ou falso
1. Para usar a classe Malh , a primei ra etapa é criar uma instância dela.

Falso

, 2. Você pode marcar um construtor com a palavra-chave static. Falso 3. Os métodos estáticos não têm acesso aó estado da variável de instânci a do objeto 'thi s' . Verdadeiro

StaticSuper é um construtor e deve ter O em sua assinatura. Observe que, como a saída abaixo demonstra, os blocos estáticos das duas classes são executados antes de qualquer um dos construtores. Saída possível

4. É boa prática chamar um método estát ico usando uma variável de referênci a. Falso 5. As variáveis estáticas poderiam ser usadas na contagem das instâncias de uma classe. 6. Os construtores são chamados antes de as variáveis estáticas serem inicializadas. 7. MAX_SIZE seria um bom nome para uma variável estáti ca final.

Verdadeiro

Falso

Verdadeiro Verdadeiro Falso

8. Um bloco inicializador estático é executado antes de o construtor de uma classe.

9. Se uma classe for marcada como final, todos os seus métodos devem ser marcados como finai s. 10. Um método final só pode ser sobreposto se sua classe for es tendida.
II. Não há classe empacotadora para tipos primitivos booleanos.

Falso

Falso

12. Um empacotador será usado qu ando você qui ser tratar um tipo primitivo como um objeto. Verdadeiro 13. Os métodos parseXxx sempre retorn am uma String.

Falso Falso

14. As classes de formatação (que não estão associadas à EIS) se encontram no pacote java.format.

import java.util.*; import static java.lang.System.out; class FullMoons { static int DAY_IM

Notas sobre o Imã com Código Lunar:

=

1000 * 60 * 60 * 2 4;

public static void main(String [) args) Calendar c
=

Calendar.g et Ins tanc e( ) ;

c . set(2004,0,7,15,40l; long dayl = c.ge tTimeInMi llis () ; for (int x
=

Talvez você perceba que algumas das datas produzidas por esse programa estão atrasadas em um dia. Essa questão astronômica é um pouco complicada, e se usássemos de perfeição, seria muito complexo criar um exercício aqui. Dica: um problema que você pode tentar resolver está relacionado às diferenças de fuso horário. Consegue identificar o problema?

O; x < 60; x++)

dayl += (DAY_IM * 29 . 52) c . setT i meInMillis(dayl) ; out.println(String . format("full moon on %tc", c));

224

capitulo 1O

1 manipulação

Comportamento Arriscado

Problemas acontecem. o arquivo não está no local. O servidor
está travado. Independentemente de quanto você é bom em programação, não é possível controlar tudo. As coisas podem sair errado. Muito errado. Quando criar um método perigoso, você precisará de um código para manipular o que possa ocorrer de errado. Mas como saber quando um método é perigoso? Onde inserir o código que manipulará a situação excepcionaf? Até agora neste livro, não nos arriscamos realmente. Sem dúvida tivemos coisas que deram errado no tempo de el<ecução, mas os problemas eram em sua maioria falhas em nosso próprio código. Erros. E devemos corrigir isso na hora do desenvolvimento. Não, o código de manipulação de problemas sobre o qual estamos falando aqui será direcionado a códigos que você não possa garantir que funcionarão no tempo de execução. Códigos que precisem que o arquivo esteja no diretório correto, que o servidor esteja sendo executado ou que o segmento
permaneça_ ~n:!...~uspensão . ~ temos~ue

fazer isso agora. Porque,

neste capítulo, construiremos algo que usará o perigoso APl JavaSound. Construiremos um MIDI Music Player.
este é um novo capitulo 225 ·

construindo '- '., _

Criemos uma máquina de _ l'Jsica__ . _ m
Nos três capítulos a seguir, construiremos alguns aplicativo s de som diferentes, inclusive uma BeatBox Drum Machine. Na verdade, antes de terminar o livro. teremos uma versão com vários participantes para que você possa enviar seus loops de bateria para outro músico, semelhante ao que ocorre em lima sala de bate-papo. Você vai esc rever o cód igo inteiro, embora possa optar por usar o código predefinido nas partes de GUI. Certo, nem todo departamento de informática vai se interessar por um novo servidor de BeatBox, mas estamos fazendo isso para aprender mais sobre Java. Construir lima BeatBox é apenas uma maneira de nos divertir enquanto aprendemos Java.

A BeatBox concluída ficará semelhante a esta:

a os
Bass Drum
Closed Hf-Har Acoustfc Snare Crasn Cymbal
I '

Cyber BeatBox

CJ :: 2í:::J C (' t- r· ~ t0==~ = ==~0 fi I: : "{.;-, \-t r~it _ ' __ ' - ,--,' "--<-' ..........' r-~
i.,.....--_ .. _""""-"-~ '

(

Sran

'

~

n

ri.

G

f t ll

_.:......,....,.

rr r ! r-! fi
. _, _.

' '--

~-~

I--' , -, '----'
>--<'"'-'

ii

HandClap

"ligh Tom

!-Ii Bqngo
Maracas

~

Vvhi~tle
L.owConga Cov/beJl
Vibraslap

==::::::'===!21 = ~iV1=, ~=, = = -,
...-, '- I r-. r-.
~

loi.v-mld Tom
High Agogo

QC::;:: CJ - ::: c: =
'--

=-

S=-={ =c:=~· =~C=:==: == '
.~ ~.-~ ~;

=

~ =~= Iyj

=

~= 5?:= ~ ':JiY'i::::::'

~_
~

_"

_1!. .mensagem que s~=~ enviad::!

::=

~ para

==C ..

~

2 ! t ~ ~=:~: CJ

- "-' - - ' --'

~;-1

,--ri
~ '--'

= .

Andy: groove #2 Chris: groove2 revised

os outros mUSICOS, jlli,to com o padrão de sua ba~iãa atual, quando você
U.SenõIt " ..

p:::essionar

CCQ· J : ] : :
' -, -.-.-' --.!-~ ~';I

Nigel: dance beat

As luensagens recebidas de
1..1ma palra

Open Hl Conga= ' C'

l~gl~ C

=::: :.: nc t!'JIYi~:.:

Clique em carregar o padrão que veio com ela ta, em
ou tros
músicos~ ~St.a.rt ~

Vocé criará o loop de UW~ beatbcx (um padrão de bateria de 16 betidas) --:'nseriI1do ma.:.-ce:$ de seleção nas cai,u!:s ..

seguidà r cliq"... 6 sm 1 para reproduzi-lo.

Insira marcas de seleção nas caixas para cada uma das 16 'batidas'. Por exemp lo, na plimeira batida (das 16) o bumbo e as maracas serão tocados, na batida 2 não haverá nada e na batida 3 haverá as maracas e o Hi-Chapéu Closed .. . Você deve ter entendido. Quando pressionar 'Start', seu padrão será reproduzido em um loop até que 'Stop' seja pressionado. A qualquer momento , você poderá "captárar" um de seus própri os padrões, enviandoo para o servidor de BeatBox (o que significa que qualquer outro músico poderá escutá-lo). Você também poderá canegar qualquer um dos padrões recebidos clicando na mensage m que veio com ele.

Começaremos com o básico
É claro que temos algumas co isas a aprender antes de o programa completo ser tel111inado, o que inclui como construir uma GUI do Swing, C0l110 se conectar CO I11 outra máquina através da rede e um pouco de EIS para que possamos enviar algo para a outra máquina.
Ah sim, há o APl JavaSound. É por onde começaremos neste capítulo. Por enquanto, você pode esquecer a GUI, a rede e a EIS e se dedicar so mente a fazer com que algum S0111 gerado em formato MIO! seja emitido por seu computador. E não se preocupe se não souber nada sobre MIDI ou sobre ler ou fazer música. Tudo que você precisar aprender será abordado aqui. Já estou quase sentindo o cheiro do contrato fonográfico .

o APl

JavaSound

o APl JavaSound é um conjunto de classes e interfaces adicion ado ao Java a partir da versão 1. 3. Elas não são complementos especiais; fazem parte da bibli oteca padrão de classes da J2SE. Esse APl fo i di vid ido em duas parles: ['v1TDT e Sampled. Usaremos apenas a parte MIDJ neste livro. MIDI signifi ca Mu sica l ln strument Digital
226 capítulo 11

manipulação ele exceróes Interface e é um protocolo padrão para que diferentes tipos de equipamentos el etrônicos possam se comunicar. Mas, para noSSO aplicati vo de BeatBox, você pode con siderar o MID! como um tipo de mlÍsica impressa com a qual alimentaremos algum disposilivo que poderia ser um 'piano mecânico' com tecnologia de ponta. Em outras palavras, na verdade, os dados MIDI não incluem nenhum som e sim as instruções que um instrumento leitor de MIDI poderá reproduzir. Ou, usando outra analogia, você pode considerar um arquivo MIDI corno um documento HTML e o instrumento que o gerar (isto é, reproduzir) como o navegador Web. Os dados MIDI informam o que fazer (reproduza C médio com essa intensidade e durante esse período, etc.), mas não i.nformam absolutamente nada sobre o som real que você ouvirá. O formato MIDI não sabe como fazer o som de uma flauta, piano ou da guitarra de Jimmi Hendrix. Para o som real , precisaremos de um instrumento (um dispositivo MIDI) que possa ler e reproduzir um arquivo MIDI. Mas geralmente o dispositivo se parece mais com uma banda ou orquestra COI/1 todos os instrumentos. E esse instrumento pode ser um dispositivo físico, como os sintetizadores de teclado eletrônico que os músicos de rock usam, ou até mesmo um instrumento construído inteiramente em software, residindo em seu computador. Em nossa BeatBox, usaremos somente o instrumento interno que vem com a Java. Ele se chama sinteti zador (algumas pessoas o chamam de sintetizador de software) porque gera som. Som que pode ser ouvido.

arquivO MIDI

reprOduza c-\
elevado, bastante
CoDl

j

::: 1i...!.J... _1'<.

M'::.Di.'"

t~fl!

~.'lf;;rma9Õ$s
<... ')m~

so}:;ra

uma carlção Gt:?ve

: intensidade e .

)

mantenna a . nota durante
2 batidas
.

se::: :ce.p,::·oduzid.a" ma.s' !:<jo :)0$:;n1.1 nenhum

caco de

S~-n

_rea~.

E

.

....-"'.

como ~nscr~qões ~e música impressa para lli'11 piano me.cânico ..

1
o dispositivo UIDI sabe
como t.ler~ um arqui vo MIDI e reproduzir o som. Pode ser um tec.lddo d.: sintetizador ou algu..ro. out ro tipo de instrumento. Geralmenta r um insc~Jmento MIDI conse~~e reproduzir !nui tos soas dífsrentes (p iano .. };;;la,r;eria J violino, etc.), todos ao mesmo tempo~ Portanto, um arq- vo MIDI não é úi como lnú sica impress~ para apenas um músico da banda - ele pede conter as partes de TODOS os músicos que tocam uma canção especifica.

Al to-falante

a~

Primeiro precisamos de um seqüenciador
Antes de podermos gerar qualquer som, precisamos de um objeto Sequencer. O seqüenciador é o objeto que pega todos os dados MIDI e os envia para os instrumentos certos. É o objeto que reproduz a música. Um seqüenciador pode fazer muiras coisas diferentes, mas, neste livro, o usaremos estritamente como um dispositivo de reprodução. Como o CD-player de seu equipamento de som, mas com alguns recursos adicionais. A classe Sequencer se encontra no pacote javax.sollnd.micli (parte da biblioteca Java padrão a partir da versão 1.3). Portanto, comecemos nos certificando se podemos criar (ou capturar) um objeto Seqllencer.
i mport j avax . sound . midi . *; publi c clas s Mu s icTe st l publi c void play() { Sequencer sequencer = Mi diSys t em . getSequenc e r(); Syst em . out . prin t ln( "We got a sequence r ") ; II fecha pl a y p u b lic static vo i d ma in(S tr ing[] arg s ) MusicTestl mt new Mu s icTestl () ; mt .pl ay() ; /1 fe cha mai n II enc er ra a class e
(~_ _ _ _ _ _ _ _ _ _ _ _ _ _ __

ímporta o pacote javax.sound.midi

~

Precisamos ãe um objeto Sequencer. Ele é a parte pri ncipal do dispositivo /i nstrumento MIDI que esta~os usando. É o objeto que, bem, seqüencia todas as inEozmações MIDI, conve~tenào-as êm ~~ 'canção ~~ Mas não criaremos ~~a marca nova - teremos que solicitar a Mõ'àõ'Syst:.e.m que nos forneça

UJn)

ESS B

cód . igo a Jo $:!$ rcl

compilado! O ~o~pilõdc está inrormandr. que ha urna ;excecão
llão-",:"s:.l~r.:::-!da?

CJ1 ~ 6.-9 ~e Séz"

cap':urada cnt declara;i._L :

loce esta aqui>

227

~~------------------------------------------------------------------------------------

mas

tão simples

OlJA rlr.nntAr.Ar8- OlJrlndo --- - - --- -método Que- você- -auiser --chamar - ,--- - - - - - . - - - -- -.-- - _. ---- um -- - -- -- --- --. --. ---1 - -- - --- - - - - - (provavelmente de uma classe que não criou) for perigoso?
-

o

f""J.

@

que usa métodos da Suponhamos que você quisesse chamar um método de uma classe que não criou. seu
você

classe que você não criou void moo() { if (serv e rDown) explode( ) ;

~Esse método faz algo arriscado, algo que pode não funcionar no tempo de execução.
a classe que você não criou

~você precisa saber se o método que
está chamando é perigoso. a classe que você não criou você

~ Em seguida, você escreverá um código
que consiga manipular a fàlha, se ela realmente ocorrer. É preciso estar preparado, para o caso de acontecer. seu código você

Em Java os métodos usam exceções para informar "Aconteceu algo errado. Falhei" ao código que os chamou.

o mecanismo de manipulação de exceções do Java é uma maneira simples e clara de lidar com as "situações excepcionais" que podem surgir no tempo de execução e permitirá que você insira todo o seu código de manipulação de erros em um local de leitura fácil. Ele se baseia no fato de você saber que o método que está sendo chamado é perigoso (isto é, que o método pode gerar uma exceção), o que lhe permitirá escrever um código que lide com essa possibilidade. Se você souber que pode ocorrer uma exceção quando chamar um método específico, terá como se preparar para - e possivelmente até mesmo resolver - o problema que a causou.
Mas como saber se um método lança uma exceção? Você encontrará uma cláusula throws na declaração do método perigoso.

o

método getSequencerO é perigoso. Ele pode falhar no tempo de execução. Portanto, deve 'declarar' o risco que você estará correndo quando o chamar.

228

A

1 f

A

..

~
:

~ l:

manipulação de exceções

Obtains lhe ddàull :;~qucllccr_
[{c/ums:,

the llctàuJt scqUCtlCcf Throws:
tQ reSQurce rcstncll
"lo l,-!':.x,.ner •' 1:lt,;~_:(d,i.":--'-1::>"';:.il,"l:':"l.'~='='O:l~lS:--­,C'~ ' ,
-

íf lhe scqucncer I;; 1101 ,'lv:lilable dlle "

ESsa parte lhe informará Pode ocorrer essa exceção nesse caso, Por causa de resérições de recursos (o que Poderia Significar Q'.ze o ,seqüenciador já está sendo Usado).

QU.~~o

o Compilador precisa saber que VOCÊ tem
consciência de que está chamando um método perigoso.
Se vo" ;n",;, o tranqüilo. 'O compilador ficará '6d;go perigO em "'gO chamado bloco t,y/catch. o Um bloco tryk alch intoona'" ao compdado, quc vo,' s abe qoc "'go excepcional pode ocorrer no método que está sendo chamado e que você "'tá prcpacado para mao;pul", i" o. O ,ompilado, não" imporl",," 'om a "''''''ira como vo,' mao;poI"'á; importaolc é qoc Você ;nlonne qoc está cuidando do problema.

°

em Waikiki .... '. Car.o nerd~~ A vida' , ',. no e) h heap. CUrta (prinCipalmente Corra o risco ',. , esq(Jeça de P eVer qUalquer, prOblema antes de algo rUI"m ' ocorrer. li '
J

~oel'd

Caro compilador Sei que esto aqui m 'as voce Correndo riscos " ~, acha pena? O qu ~' que vale a ' e uevo fazer? .
J

~

J

nao dar certo na-o

_ente.Mas Para o ca~Ode

" .'

impor t

javax. s ound.midi . *;

pUb l ic c l ass MusicTestl pUblic void play()

try ({

System.out -println("successfullY go t } SYstem . out . println ("Bummer ") ;

se~eneer

~ blOCO 't:xy.r

insere o método perigoso em

Q~

c<queneer , MidiSY"em ..•.. ' oeeSeqneneer();
a seque ncer");

} Catch(MidiunavailableException ex)
II fecha play

(
cria um bloco ' catch ' com o que será feito se a situação s2cepcional ocorrer _ em Outras palavras, uma exceção MidiunavailableExCeption será lançada pela chemada de getsequencer(} _

pUblic static void main(Stringr] args) ( IviUSlcTesCLrrTt ' = rfE!w ' Hu s iCTestl. -íl;_ _ _ _ __. mt · Play() ; II fecha main II feCha a classe

'----.----

Você está aqui t>-

229

exceções sao objst:Js

Uma exceção é um objeto ... De tipo Exception.

o que é bom, porque seria muito mais complicado de lembrar se as exceções tivessem o tipo Brócolis.
Lembre-se de que, segundo os capítulos sobre polimorfismo, um objeto de tipo Exception pode ser uma instância de qualquer subclasse ' de Exception.
Throwable getMessage() p rintSt ackT rac e()

Já que Exceptiol2 é um objeto, é isso que você estará capturando. No código a seguir, o argumento de catch é declarado com o tipo Exception e a variável de referência do parâmetro é ex.
é igual
a declarar o

argumento de um método

try {
.Exception

/

II executa algo arriscado ~

} catch(Exception ex)
II tenta reso l ver

{

IOException

InterruptedException

Esse código só será executado se uma exceção for lançada.

o que inserir em um bloco catch vai depender da exceção que for
Parte da hierarquia da classe
Todas as c.lasses estendem
Iii.

Exception~

classe

Throwab2e e herdam dois

métodos - cbave~

lançada. Por exemplo, se um servidor estiver desativado, você pode usar . " o bloco catc h para tentar acessar outro servidor. Se o arquivo não estiver presente, você pode pedir ajuda ao usuário para encontrá-lo .

Se seu código é que captura a exceção; de quem é o código que a lança?
Você passará muito mais tempo no código Java manipulando exceções do que criando e lançando-as. Por enquanto, é preciso saber apenas que quando seu código chamar um método perigoso - um método que declare uma exceção - será esse método que lançará a exceção para você, que o chamou. Na verdade, você pode ter criado as duas classes. Não importa realmente quem escreveu o código .. . O que importa é saber qual método lança a ex ceção e que método a captura. Quando alguém criar um código que possa lançar uma exceção, deve declará-Ia.
lança uma exceção

[ ~~q <_--\~~_-;~ i"iC
seu códi go chama um método perigoso

r

classe com um método perigoso

CD Código

perigoso que lança uma exceção:
~ decls,ra.çâo}
esse método DEVE informar para todo mundo {por
que

~le lança.

UJJla exceçâo BadE;xceptíon

public void takeRisk() if (abandonAllHope)

throws BadException {

throw new BadException ( ) ;

(~-------------------­

--

t

II
I

~

j

.1

jJ

I' I

, I'

l"

I

••

,

r).

o

compiiador verifica tudo exceto RuntimeExceptions.

Ele verificará:

Q)

lançar

I

UJ!·'

,

,

I" I' •

throW's
chama.r
jfl!

Il l(

1(, j

I ~

,

i i lo

I

l

a.r-""

demonstrar
IHoI 111<1

/llI'

'J J"

ir

II.-_~...-_~....__..___J

5
'I!

.
I ItU ·,! ',' ' i l l r \ ! .

:nr

1· :~(
'\

,
I i,..-..
I'

InterruptedE>< ception

"

III II

~

J.l

~,~---" ~~un.timeE"cePtion

'r '\

h
r-. ,
I

h
i V"'\ Não exi s ·tem

. !lJul:CPointerException

Perguntas Idiotas
Es pere um momento! Por que essa é a PRIIV1EIRA vez que temos que capturar uma exceção? E quanto às exceções que já ocorreram como NullPointerException e a de divisão por zero? Já vi aié uma exceção Nu mberFormatException causada pelo método Integer.parselntO. Por que não tivemos que capturá-Ias?
O co mpila clor ve rifi ca todas as subclasses de Exception, exceto qua nd o elas são de um tipo especial, RuntimeE xcep ti on. Qua lq uer classe de exceção que estenda RuntimeException passará despercebida Runti meE xceptions podem ser léln l; adas em CjunlCjuer local, com ou sem declarações th rows ou blocos try/catch. O Compil ador não se preocupa em ver ificar se lIm método declara que lanç;J Lima RuntirneException ou se o chamad or sabe que essa exceção pode ocorrer no tempo de execução.

P:

R:

Isso está me irritando. POR aUE o compilador não se preocupa com essas exceções de tempo de execu ção? Eias ramoém não POdé(fl fazer :'iGO parôí?

P:

prOVe n ;2i"':t-.:

R:

A muion,l dJei RUlltlrneExr;eptir:,l::; :"':"~.J '''''''\r'~! ~ f;~'; :le f~!I--:"" 1'1'1

c. . .

~;er~l [)(i<J il'';-lri"
l..-d'Y)r

rI<,-;

um pr . /[) k:íi1éJ
II; 1t!1

iVl
I

,n (lr'::'

P :q

~ ( :I II'~ 111

1<o.):)í\/t-:!

irJgic,3 ele seu código, em vez ele se r I-=: uí8vef ou eV IL I; Ji.)cê njf_' /-;or.../e ~1.:lr3 ntir
,) ,.!

<.

discriminação dos poptos que o arquivo estará presente. Não pode garantir que o servidor estará ativo. Mas pode se certificar de que seu código não üSB-{ndices qüe ültf"ô põssení o taitTãfíim-dê- urna -11Mb iL (é para isso-que- existe o atributo -.iength). QUEREMOS que as Runtime Exceptions ocorram na hora do desenvolvimento e teste. Não queremos codificar um bloco try/catch, por exemplo, e ter a sobrecarga que ele gera , para capturar algo que não deveria ocorrer. Um bloco try/catch é para a manipu lação de situações excepcionais e não falhas em seu código. Use seus blocos catch para tentar se recuperar de situações que você não possa garantir se serão bem-sucedidas. Ou , pelo menos, exiba uma mensagem para o usuário e um rastreamento de pilha, a fim de que ele possa descobrir o que ocorreu.

DISCRIMINAÇÃO DOS PONTOS '
- Um método pode lançar uma exceção quando algo falhar no tempo de execução. - Uma exceção é sempre um objeto de tipo Exception. (O que signjfica, como você deve se lembrar dos capítulos sobre polimorfismo, que o objeto é proveniente de uma classe que tem Exception em algum local mais acima em sua árvore de herança.) - O compilador NÃO se importa com exceções do tipo RuntimeException. Uma RuntimeException não precisa ser declarada ou inserida em um bloco try!catch (embora você possa fazer uma ou as duas coisas). - Todas as exceções com as quais o compilador se preocupa são chamadas de 'exceções verificadas', o que na verdade significa exceções verificadas pelo compilador. Só RuntimeExceptions são excluídas da verificação do compilador. Todas as outras exceções devem ser declaradas em seu código, de acordo com as regras. - Um método lança uma exceção com a palavra-chave throw, seguida de um novo objeto de exceção:
t hrow new NoCaffe ineExc eption () ;

dica metacognitiva
d aprender algo Se você estiver tentan o . última m que essa seja a novO, faça co t s de ir dormir. . aprender an e . COlS a a ndo voce colocar este livro . portanto, qua ue consiga se separar de lado (supondo q " desafiador do que dele) não leIa nada malS . . d uma caIxa de a parte traseIra e, .clsa de tempo ' , . TM Seu cerebro ple CheenoS . leu e aprendeu. o que voce Para processar alaumas horas. Se voce , Isso pode levar", ' d' tamente d . lao novo lme la b e o Java, parte tentar guar aI a", ' s o que aprendeu so r d . apo d se per er. desse conhecimento po e
A A A

, ue isso não se aplica aO E claro q 1 bl'II' dade física. · d de uma la aprendIza o ' lt' roa série de luta ão afetará seu Trabalhar em sua u I tiva provavelmente n espor aprendl'zado de Java. Para obter os melhores u ltados , leia este lIvro (o resu pelo menos olhe as fl auras) imediatamente e ' antes de dormIr.

- Métodos que possam lançar uma exceção verificada devem anunciá-la com uma declaração throws Exception. - Se o seu código chamar um método que lança uma exceção verifi cada, ele terá que garantir ao compilador que foram tomadas precauções. - Se você estiver preparado para manipular a exceção, encapsule a chamada em um bloco try!catch e insi ra seu código de manipulação/ recuperação de exceção no bloco catch. - Se você não estiver preparado para manipular a exceção, ainda poderá satisfazer o compilador, 'desviando-se' oficialmente dela. Falaremos sobre como se desviar um pouco mais adiante neste capítulo.

Coisas que você quer fazer
Quais desses itens você acha que podem lançar uma exceção que o compilador verificaria? Só estamos procurando as coisas que você não pode controlar em seu código. Fizemos o primeiro.
(Porque era o mais fácil.)

o que

pode dar errado

Vconectar-se com um servidor remoto _acessar uma matriz fora de sua extensão _ exibir uma janela na tela _ recuperar dados em um banco dc dad os _ ver se um arquivo de texto está onde você acha que ele deveri a estar

(; St' l'vídol' estCt desativ,ldu

_criar um novo arquivo ler um caractere na linha de comando

232

captt~lo 11

manipulação de exceções

o controle do fluxo em blocos try/catch
Quando você chamar um método perigoso, uma das duas coisas pode acontecer. O método perigoso ser bemsucedido e o bloco try ser conc luído ou o método peri goso lançar uma exceção para o método que o c hamou.

"Se o bloco try for bem-sucedido (doRiskyThing( ) não lançou uma exceção)
o código do bloco catcl! nunca será executado_
try (
primeiro o b loco try é . executado e em ,_ segu" ida, o Fc cóàigo abaix~ de catch é executado .
l

CD
r-----

~o () f
~ nt

b

x.doRiskyThing(); f,g e tNum() ;

catch ( Exception e x )

System . out.println("fa l hou") ;

v
resto do bloco try nunca será executado; o que é bom porque o restante desse bloco depende do suces so da chamada a doRiskyThings ( ) •

21--.... Sys 't em . out .prirtt ln("Conseguimos!") ;

Se o bloco try falhar (porque doRiskyThings( ) lançou uma exceção)
o bloco try

executado; mas a chamada a doRískyT)Hngs ( )
lança

try (

CD

o

Foo i nt b f.g etNu m();

uma

portanto, o r esto do bloco não será executado. __ O bloco catcl! é ..te execut ado e o mét odo continua daí

C"
2

} catch -(EXcept i o n e x ) (
System . out .prin t ln("fa l hou");
.

C
3

}

" j ystem .out . p r in'tl n ( "Co nseguimo s!" ; ; s

"'- ""::="Finally: para as coisas que você quiser fazer ,---...
independentemente do que ocorra.
Se você quiser cozinhar algo, começará acendendo o forno. Se sua tentativa falhar totalmente, você terá que desligar o forno. Se sua tentativa for bem-sucedida, você terá que desligar o forno. Você terá que desligar o forno de qualquer maneira!

Um bloco finally é onde você inserirá um código que deva ser executado independente de uma exceção.
try { tu r nOvenOn () ; x. bake () ; catch (BakingExcept i on ex) ex . printStackTrace();

(

finally {
turnOvenOff();

\/ccà está aquI

j>-

233

exercício sobre
<)

sonlrc..ie ô(-; f: ~!XO

Sem finally, você terá qu e inserir o método turnOvenOffO tanto em try quanto em catch porque terá que desligar o fom o independel/.temente do q-tiê ocorra. Um biõcõ-f'inaJl y pen11ltlrág üe você in sira todo o seu importante código de encerramento em um local em vez du pli cá- lo dessa fo rma:
try {

turnOvenOn() ; x . bake(); turnOvenOff(); catch (BakingException ex) ex.printStackTrace(); turnOvenOff() ;

{

Se o bloco try falhar (uma exceção), o controle do fluxo passará imediatamente para o bloco catch . Quando o bloco catch for concluído, o bloco finally será executado. Quando o bloco finally for concluído, o resto do método será executado. Se o bloco try for bem-sucedido (sem a ocorrência de exceções), o controle do fluxo saltará o bloco catch e passará para o bloco finally. Quando o bloco finally for concluído, o resto do método será executado. Mesmo se o bloco try ou catch tiver uma instrução de retorno, finally será executado! O fluxo saltará para o bloco finally e, em seguida , voltará à instrução de retorno.

Aponte seu lápi s

Controle do fluxo
Examine o código à esquerda. Qual você acha que seria a saída desse programa? Qual seria a saída se a terceira linha do programa fosse alterada para: String test = "yes";? Considere ScaryException como uma classe que estende Exception.
public clas s Te s tExceptions { public s t a tic void main(String [ ] a r gs) {

Saída quando test = "no"

String t est = "no"; try { System.out.println("start try") ; doRisky(test) ; System . out.println("end try"); catch ( ScaryException se) { System . out . println ("scary exception"); finally { System . out. println (" finally") ; System . out . println("end of main");
}

Saída quando test

="yes"

static void doRisky(Str i ng test) throws ScaryException ( System . out . println("start risky"); if ("yes".equals(test)) ( throw new ScaryException(); System . out.println("end risky");
returni

U"]'EW JO pua - ÁllEU"]';t - uo"]'~da::>xa Á.:rE::>S - Á:l[S"]'.:r ~.:rE~S U"]'EW ;tO pua - ÁllEU"]';t - Á.:r~ pua - Á:l[S"]'.:r pua - Á'[S"]'Z ~.:rE~S -

Á.:r~

~.:rE~S

:"saÁ,,=~sa~

Á.:r~

~.:rE~S

:

"ou,,=~sa~

opUEnO opUEnO

234

capítulo 11

manipulação de exceções

Mencionamos que um método pode lançar mais de uma exceção?
Um método pode lançar váli as exceções se precisar. Mas a declaração de um método deve incluir todas as exceções, verificadas que ele pode lançar (porém, se duas ou mais exceções tiverem a mesma superclasse, o método poderá declarar apenas a superclasse),

capturando várias exceções

o compi lador se certificará de que você manipulou todas as exceções verificadas lançadas pelo método que está sendo chamado, Empilhe os blocos catch abaixo de try, um após o outro. Em algumas situações a ordem em que você empilhar os blocos catch será importante, mas falaremos sobre isso um pouco mais adiante.
Esse método declara duas, pode oontar r DUAS exceções.

public class Laundry ( public void doLaundry() throws PantsException, ""LingerieException II código que poderia lançar uma das duas exceções

/

public class Foo { public void go () Laundry laundry = new Laundry(); try { laundry.doLaundry();

} catch(PantsException pex)
II código de recuperação

{
""

} catch(LingerieException lex)
II código de recuperação

~
. .'

se doLaundr~() lançar uma ( ----------------------- PancsExceptíon, irá para O bloco catcb dessa exoeção.
se doLaundry() la.i·lçar uma ~('-------------- LingeríeExoeption r irá para o

{

blooo catch dessa exceção.

}

Exception

As exceções são polimórficas
As exceções são objetos, lembre-se. Não há nada de tão especial sobre elas, exceto por serem algo que pode ser lançado, Portanto, como todo bom objeto, as exceções podem ser referenciadas polimorficamente. Um objeto LingerieException, por exemplo, poderia ser atribuído a lima referência ClothingException. Uma PantsException poderia ser atribuída a uma referência Exception. Você entendeu. A vantagem das exceções é que um método não precisa declarar explicitamente qualquer exceção que possa vir a lançar; ele pode declarar uma superclasse das exceções. Algo com blocos catch -- você não precisa criar um bloco catch para cada exceção possível contanto que o bloco (ou blocos) catch que tiver consigam manipular qualquer exceção lançada.

Todas as exceções têm Exception como superclasse.

IOException

ClothingException

CD

Você pode DECLARAR exceções usando um supertipo das exceções que lançar.

public void doLaundry ()
~h,--._ Declarar uma

throws ClothingException

ClotllingException permitirá que você lance qualquer subclasse dessa classe. Isso signif:rca que dOLaundry() poderá la.nçar PantsEJ'Ception, l.i ngerieException , Te-eShirtException €i Dre ssBllirtException _ _ _ _ _ _ _ _""!"'_ _ _. sem declarar explicitamente oada uma . ,

?

1--

-

.-?, ~ .""

fi t \ \,~_J.j~)
você está aqui
~

235

exceções

® Você pode CAPTU B_AR Axceçães-usando--Lm"'+..supertipo da exceção lançada.
try { laundry.doLaundry() ;

---

try { laundry.doLaundry() ;
I;'

c ··,

\0~~~~
catch(ClothingException cex) II código de recuperação catch(ShirtException sex) II códig o de r ecuperação

.,

pode captura'lt'
~~alquer

subclasse de ClothíngException

s ó pode capturar TeeShirtExceptíon e DressSbirtException

Só porque você PODE capturar tudo com um superbloco catch polimórfico, não quer dizer que sempre DEVA fazê-lo.
Você poderia escrever seu código de manipulação de exceções e especificar somente um bloco catch, usando o supertipo Exception na cláusula catch, para poder capturar qualquer exceção que possa ser lançada.
try { laundry.doLaundry(); catch(Exception ex) { II código de recuperação ...

(~------------------

Recuperação do QUÊ? E s se bloco catch capturará QUALQUER exceção, portanto, você não saberá au tomati c amen t e o que deu erra do.

Crie um bloco catch diferente para cada exceção que você tiver que manipular exclusivamente.
Por exemplo, se seu código lida com (ou se recupera de) uma TeeShirtException diferentemente de como manipula uma LingerieException, crie um bloco catch para cada uma. Mas se você trata todos os outros tipos de ClothingException da mesma maneira, adicione um bloco catch dessa classe para manipular o resto.
try { l aundry .doLaun dry();

\.'~ :
E ·~
..
~.t

]

catch(TeeShirtException tex) { ~ II recuperação de TeeShirtException _______________ TeeShírtException e LingerieException precisam de um código de recuperação d i ferente, portant o , você deve usar blocos catcb distintos . catch(LingerieException lex) { II r e cuperação de LingerieException

V

;
\j.

:
~:...

.\.
- -;..

Todas as outras Clot:híngExceptíons serão catch(ClothingException cex) ( -----------------------capturadas aqui. II re c uperaçã o de todas as outras e xce ções

236

capítu!o .1 t -

manipulação de excHções

Vários blocos catch devem ser ordenados do menor para o maior
Quanto mai s alto na árvore de herança, maior a 'cesta' de captura. Conforme você descer na árvore de herança, em direção a classes Exception cada vez mais especializadas, a 'cesta' de captura ficará menor. Trata-se apenas do velho polimorfismo.
O bloco catch de uma ShirtException é suficientemente amplo para capturar uma TeeShirtException ou uma DressShirtException (e qualquer subclasse futura de algo que estenda ShirtException). Uma ClothingException é ainda mais ampla (isto é, há mais coisas que podem ser refe renciadas com o uso de um tipo ClothingException). Ela pode usar lima exceção de tipo ClothingException (duh) e qualquer subclasse desta classe: PantsException, UniformException, LingerieException e ShirtException. O pai de todos os argumentos de captura é o tipo Exception: ele capturará qualquer exceção, inclusive exceções de tempo de execução (não verificadas), portanto, provavelmente você não o usará exceto em testes.

TeeShi rtE;~ceptions

são

catch (TeeShirtExcepti o n

tex)

capturadas aqui, nenhuma outra exceção seria adequada .

catch(ShirtException sex }

TeeShírtExceptíons nunca chegarão aqui, mas todas as outras subclasses de ShirtException são capt uradas nesse ponto.

catch(ClothingException cex )

Todas as ClothíngExceptions são capturadas aqui, embora TeeShirtException e ShírtK~ception nunca cheguem a esse pon to.

~ ~ .­
~

l,
~

Você não pode colocar cestas maiores embaixo de cestas menores

fi.
r'\

Bem, você pode, mas esse cód igo não será compilado. Os blocos catch não são como os métodos so?recarregados em que o bm~iS ad~quado é selecionado. comf.o~ bltOCOS catch, ai JV( M simples m1ente inicia ~10 I pnmelro e prossegue para alXO ate encontrar um que seja su IClen emente amp o em outras pa avras, esteja ~- em um nívetsaítciefftemenre-atnn1a- ârVUte lle rlÍenlll[uia} jJeua tJl ,-ulil-' uli:l l i:l CALOC','a:O-:-S"e--o--SCü-pri-meiro b-loco ' catch for catch(Exception ex), o comp ilador saberá que não adi anta adicionar nenhum outro - eles nunca .: ' serão alcançados.

I~ h

jf\

VOGé

está aqui.

237

Não faça ísso!
try {

laundry . doLaundry();
\.

(l .

catch(ClothingException cex)

~=~ ~~

{

II recuperação de ClothingExcepti on

Blocos de mesmo nível podem ficar em qualquer ordem, porque um não pode capturar a exceção do outro.
Você poderia inserir ShirtException acima de LingerieException e ninguém notaria . Porque mesmo que ShirtException seja um tipo maior (mais amplo) já que pode capturar outras classes (suas próprias subclasses), ele não pOde capturar uma Lingeri eException, logo, não há problema .

catch(LingerieException lex)

{

II recuperação de LingerieExcepti on

catch(ShirtException sex)

II recuperação de ShirtException

Aponte seu lápis

Suponhamos que esse bloco try/catch tenha sido codif icado de maneira válida. Sua tarefa é desenhar dois diagramas de classes diferentes que possam refletir as cl asses Exception. Em outras palavras, que estruturas de herança de classe tornariam os blocos try/catch do código do exemplo válidos?
try { x . doRisky ( ) ; catch(AlphaEx a) { II recuperação de AlphaEx catch (BetaEx b) ( II recuperação de BetaEx catch(GammaEx c) ( II recuperação de GammaEx catch(DeltaEx d) { II recuperação de DeltaEx

••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
Sua tarefa é criar duas estruturas try/catch válidas di fere ntes (semelhante à encontrada anteri ormente à esquerda) , para representar de maneira precisa o diagrama de classes também mostrado à esq uerda. Supon hamos que TODAS essas exceções possam ser lançadas pelo método que tem o bl oco try.

BarEx

BiffEx

BoinkEx

manipulação de exceções

Quando não quiser manipular uma exceção ...

Se não quiser manipular uma exceção, você pode desviar-se dela declarando-a.
Quando você chamar um método perigoso, o compilador precisará que o informe. Quase sempre, isso significa inserir a chamada perigosa em um bloco try/catch. Mas há outra alternativa, simplesmente desvie -se dela e dei xe que o método que chamou você capture a exceção.

exceções~nda que, tecnicamente, não seja você que irá lançá-las, isso
não importa. Você continuará deixando a exceção passar direto. Mas se você se desv iar de uma exceção é porque não tem um bloco try/ catch, portanto, o que acontecerá quando o método perigoso [doLaundry()] realmente lançar a exceção? Quando um método lança uma exceção, ele é removido da pilha imediatamente, e a exceção é lançada para o próximo método - o chamador. Mas se o chamador se desviar, não haverá um bloco catch para ela, portanto, o chamador será removido da pilha imediatamente, e a exceção será lançada para o próx imo método e assim por diante .. . Onde isso vai acabar? Você verá um pouco mais adiante.

É fácil- só é preciso declarar que é você que está lançando as

Você não a lançará REALJ!clENTE, mas, já que não tem um bloco try/catcn para o método public void foo () throws ReallyBadException { ~(------- perigoso que chamou, passou a / / chama o método perigoso sem um bloco try/catch ser o "método perigoso". Porque , agora , quem o chamar laundry.doLaundry() i terá que lidar com a exceção. }

Desviar-se (declarando) só retirda o inevitável
Cedo ou tarde, alguém terá que lidar com o problema. Mas e se main( ) se desviar da exceção? '
p ub li c cla ss Washer { Laundry laundry = new Laun dry() ;
ps dois métodos se desviam pub l i c void f oo() throws ClothingException { (------------------------ da exceção (declarando-a), laundry. doLaundry() ; portanto, não bá ninguém
para
manipula - ~a!

Esse

public s ta t i c vo id main (S t ring[] a rgs) throws ClothingException { Washe r a new Washer() ; a . foo () ;

~

código será compilado sem problemas.

você esta aqui :.-

239

manipule ou declare
~ doLaUndry() lança urna ClothingE&c e ptioll

se desvia da exceção

O main () se desvia da . - - - ----- - ~--6~e69ã.o

main() chama foo ( ) fco() chama doLaundry() doLaundry() está sendo executada e lança ~~a ClothingE2ccep t ion

doLaudry{) é removido da pilha imediatamente, e a exceção é retornada para fo o() . Ma s foo() nâo' t em um bloco try/ca tch, portanto .• .

foo() é removido da pilha e a exceção é retornada para . . . quem? O quê? Não há mais ninguém exceto a JVM e ela es tá pensando: "Não espere que EU o livre disso."
imediata~ente

Estamos usando a camiseta para representar uma ClothingExcept ion . Eu se i. e u sei . . . você pre f ere a calça jeans .

Manipule ou declare. É a lei.
Bem, já vimos as duas maneiras de satisfazer o compilador quando você chamar um método perigoso (que lance uma exceção).

@) Manipule
Ins i ra a chama da arri scada em um bloco try/catch try { laundry.doLaundry (); catch(ClothingException cex) II código de recuperação
Esse bloco catch deve ser suficientemente para manipular todas as exceções que { ( --------------------- doLaundrf() pode lançar. Caso contrário o compilador ainda reclamará que você não está capturando todas as exceções.

® Declare (desvie-se)
De c lare que SEU método lan ça as mesmas exceções do método perigoso qu e você es tá chamando .

o método doLaundry{) l~~ça uma ClothingExceptioTI, mas, ao declarar a exceção, void fo o() throws ClothingEx ception { ~(~-------------­ o método foo() se des viará dela. Não bá um l aundry.doLaundry() ; bloco try/catch.
Mas isso signifi ca que agora quem chamar o método fooO terá que obedecer a regra Manipule ou Declare. Se fooO se desv iar da exceção (declarando-a) e mainO chamar fooO, mainO terá que lidar com a exceção.
publ ic class Washer { Laundry laun dry = new Laundry() ; public voi d f oo() throws ClothingEx c ep tion laundry.doLaundry() ;

PROB.r..E.MA I !
Agora main () não será compilado e veremos o erro "exceção não-relatada". Para o compilador, o método foo() lança uma exceção.

publi c static void main (String[) args) { ~(~-------­ Wa sher a = n ew Was her () ; a . foo(); ( -------------------------------------- Já que o método foo() está se desviando da ClothingException lançada por doLaundry(), main() terá que inserir a . foo{) em um bloco try/catch ou declarar que também lança ClothingException!

Voltando ao nosso código musicaL ..
Como você j á deve ter esquecido, começamos este capítul o com a análi se ini cial de um código JavaSound. Cri amos um objeto Sequencer, mas ele não seria compilado, porque o método Midi.getSeq uencerO declara uma exceção verificada (Midi Unavai lableException). No entanto, podemos corrigir isso agora inserindo a chamada em um bl oco try/catch.
240 capítuio 11

manipulação de exceções
p ubl i c void play ()

try {

l'Vã.o 11aVe1:'d proble.ma.s em ollamar

getSequencer ( } , agora ~Je o inserimos Seque ncer s ec~enc e r = MidiSystern . ge t Sequencer () ; ~--------­ em um bL o co try/catch. Systern . out.print l n ( "Suc ce ssfully got a s e quencer" ) ;

} catch(MidiUnavailableException ex)
System. Qu t . println ("Bummer " ) ; } II fecha play

o parâmetro de catch tem qu'e ' ser a { "'(- - - -- - - - exceção ·certa'. Se escrevêssemos
'ca t ch (FileNotFoundExc e ption ;f ) ' , o código não seria compilado, porque poLimorficamente uma MidiUnavaiLableException não caberá em uma FileNotFoundException. Lembre-se de que não é suficiente tê!.lC um bl oco c atch .. . Você t em que capturar o que está sendo lançado!

Regras das exceções
(!) Você
não pode ter um bloco catch ou finally sem um bloco try

® Você

não pode inserir código entre os blocos try e catch
try x . doStuff(); int y = 43; cat ch (Excep tion ex ) { }
NÃo É VÁLIDO I

v oid go() { Foo f = new Foo ( ) ; f . foof () ; catch ( FooException ex ) { }

Mio É

v.ÁLIDO!

Onde está o bloco try?

Você não pode inserir código entre os bLocos try e catch .

® Um bloco

try DEVE ser seguido de um bloco catch ou finally

~Mesmo se o bloco try tiver apenas o bloco
finally (sem catch), ele deve declarar a exceção.
Um

try ( x .doStu ff() ; finally ( II encerramento

porque você tem um bloco fina 1. Ly, ainda que não haja U.!n bloco catch • . Mas você não pode ter apenas um bLoco
VÁLIDO,

void go( ) throws FooException try ( x.doStuff() ; } fi nally { }

bloco try sem um bloc o

catch não satisfaz a regra 'manipule ou declare' .

try .

Receita de Código
(

Você não precisa fazer isso por sua própria conta, mas será muito mais divertido se o fizer.

I:
!'')
I
f--"

l,'"

a resto deste capítulo é opcional; você pode usar o código predefinido em todo os aplicativos musicais.
Mas se quiser aprender mais sobre JavaSound, vire a página.

i r- -

I r-.

você está aqui.,.

241

classes MIOI de JavaSound

Criando som real

---

----------------

Lembre-se de que, quase no início do capítulo, examinamos como os dados MIDI armazenam as in stru ções do que deve ser reproduzido (e como deve ser reproduzido) e também di ssemos que na verdade eles não geram nenhum som que possamos ouvir. Para que o som saia dos alto-falantes, os dados MTDI têm que ser enviados através de algum tipo de dispositivo MIDT que use as instruções e as converta em som, acion ando um instrumento de hardware ou um in strumento 'vi rtual' (si ntetizador de software). Neste livro, estamos usando somente dispositivos de software, portanto, aqui está como isso funciona com JavaSound:

Você precisa de QUATRO coisas:
o dispositivo que
reproduzirá a música.

® A música

a ser reproduzida ... Uma canção.

®

A parte da seqüência que contém as informações reais .

~ As informações
reais sobre a música: notas a serem reproduzidas, duração, etc.

reproduz

contém uma

armazena

Seqüenciador

----"J )

Seqüência - - - - -) Faixa

o seqüenciador é o dispositivo que fará com que uma can ção seja realmente reproduzida. Considere-o como um player de CDs musicais.

A sequencia é a canção, a peça musical que o seqüenciador reproduzirá. Neste livro, considere a seqüência como um CD de música, porém reproduzindo apenas uma canção.
Neste livrol consídere a seqüênci a como um CD c om uma úni c a can ção (com apenas uma faixa ) . As informações sobre como reproduzir a canção residem na r ai;ca (Tue f a z par te de. seqüênci a .

Neste livro, só precisamos de uma faixa, portanto, imagine um CD de música com apen as uma canção. Uma única faixa . É nessa faixa que residirão todos os dados (info rmações MID I) da canção .

Um e v ento MIDI é uma mensagem que o seqüenciador cons i ga e ntender . Ele poderia dizer ( se falasse português ) : "Nesse momento, reproduza C médio, com essa velocidade e intensidade, e mantenha o durante esse período de tempo." O evento MIDI também pode solicitar algo como "Altere o instrumen to atual para a flauta".

E você também precisa de CINCO etapas:

CD Capture
® ®

um Seqüenciador (Sequencer)

e abra-o

sequencer player player. o pen();

=

MidiSystem .getsequencer();

Crie uma nova Seqüência (Sequence)
Sequence seq = new Sequence(timing,4);

Capture uma nova Faixa (Track) na seqüência
Tr ack t
= seq.createTrack();

GD
242

Preencha a faixa com eventos MI DI (MidiEvents) e fo rneça a seqüênc i a ao seqüenciado r
t. add( myM idi Ev en tl) ; p layer. se tSequ ence( seq) ;

capít~iD) 'i

manipulação ele exceções

o

player.start(

)i

Seu primeiro aplicativo reprodutor de sons
Digite e execute-o. Você ouvirá o som de alguém tocando apenas uma nota em um pi ano' (Certo, talvez não sej a alguém, mas algo.)
import javax . sound . midi.*;
~(~--------------------------------- Não esqueça de importar o pacote midi

public class Min i MiniMusicApp public static void main(String[] args) MiniMiniMusicApp min i = n ew MiniMiniMusicApp(); mini . play() ; II fecha main public void play() try {

captura um objeto Sequencer e o abre (para ~ Sequencer player = MidiSys t e m. getSequencer(); ~ ~Je possamos usá-lo ... um seqJenciador não
pl ayer . open ( ) ;

«

vem aberto). Não Se preocupa com os argumentos do const.J:·utor de Sequencer. Basta copiá -los (considere-os como argumentos predefinidos). Solicita à Sequence um objeto Track. Lembrese que o objeto Track reside em Sequence e os dados MIDI residem em Track. Insere alguns MidiEvents a~ Track. Essa parte é quase toda de código predefinido. A única coisa com a qual você terá que se preocupar são os argumentos do método setMessage() e os argumentos do construtor de NidiEvent . Exa~inaremos esses argumentos na próxima página.

~

Seque nce seq

new Sequence (Sequence . PPQ,

4);

~

®

Track track

seq.createTrack(); «~---------------

Shor tMessage a = new ShortMes sage(); a.setMessage(144, 1, 44, 100) ; MidiEvent noteOn = new MidiEvent(a, 1 ) ; track.add(noteOn);

ShortMessage b = new ShortMes sage(); b . setMessage (128, 1, 44, 100); MidiEvent noteOff = new MidiEvent(b, track . add(noteOff) ; p l ayer . se t S equenc e ( s eq); player . start () ;
Il. ~

_________________________

Fornece a seqüência ao seqüencíador (como inserir o CD no CD player) Inicia o seqüencíador (como Se pressionássemos PLAY)

~<~--------------------------------


~

catch (Exception ex) cx . printStackTrace () ;
)

-A:-_.

II fec h a play
II fecha class

,.

você está aqui

~

243

um aplicativo para sons

Criando um MidiEvent (dados__da canção) _____________ _
Um MidiEvent é uma instrução para parte de uma canção_ Uma série de MidiEvents é como música impressa ou o rolo de um piano mecâni co_ A maioria dos MidiEvents com a qual nos preocuparemos descreverá algo que deve ser feito e a hora de fazê-lo. A parte referente à hora é importante, já que o momento exato é tudo na música. Essa nota vem depois daquela Um MidiEvent informa e assim por diante. E já que os MidiEvents são tão detalhados, você terá que informar em que fazer e quando fazê-lo. que momento a nota deve com.eçar a ser reproduzida (um evento NOTE ON) e quando ~ ;[od§L in§trução ,deve inclujr interromper sua reprodução (evento NOTE OFF). Portanto, é lógico que acionar a o momento exato de sua . mensagem "pare de reproduzir a nota G" (mensagem NOTE OFF) antes de "comece a execução. reproduzir a nota G" (NOTE ON) não funcionaria.

º

Na verdade a instrução MIDI é inserida em um objeto Message; o MidiEvent é uma combinação de Message mais o momento em que essa mensagem deve 'ser acionada'. Em outras palavras, o objeto Message pode solicitar "Comece a reproduzir C Médio" enquanto o MidiEvent solicitaria "Acione essa mensagem na batida 4". Portanto, sempre precisaremos de um objeto Message e de um MidiEvent. O objeto Message informa o que fazer e MidiEvent quando fazê-lo.

.Em outras palavras, em que ;'
batida ela deve ocorrer.

G) Crie

um objeto Message

ShortMessage a

=

new ShortMessage() ;
Essa mensagem diz "comece a reprodu z i r nota 44 N (examinaremos os outros números na próxÍJn..a P?f!.; 1"a)

® Insira

a Instrução no obj eto Message
1, 44, 100);

a.setMessage(144,

~~------------------------------ a

® MidiEvent

3 Crie um novo MidiEvent usando o objeto Message
noteOn = new MidiEvent(a,

As instruções estão na mensagem, mas o adicionará o momento em que elas devem ser acionadas . Es s e 1); ~~~-------------------- NiãiEvent solioita ~Je a mensagem 'a'
r.:l'idiE~'ent

seja acionada na primeira batida
(batida 1) .

QD

Um objeto Track armazenará todos os objetos Mídí~ent. O objeto Sequence os organiza ra de acordo com c moment o a~ · q~e cada um tiver que ocorrer s, em Adicione O MidiEvent ao objeto Track seguida , o objeto Seq~encer DS track . add(noteOn ) ; ~(~----------------------------------------- reproduzirá nessa ordem. ifocê pode ter 'v"ários e ventos ocor rendo exat&Zru3Iltt? 1'1 0 mesmo momento. Por exemplo, pode querer que duas notas sejam reproduzidiis simultaneamente ou até mesmo que inEtrumentos diferentes reproduzam sons distintos ao mesmo tempo.

Mensagem MIOI: a parte principal de um MidiEvent
Uma mensagem MIDI contém a parte do evento que informa o que fazer. A instru ção que você realmente deseja que o seqüenciador execute. O primeiro argumento de um a instrução é o tipo da mensagem. Por exemplo , uma mensagem de tipo 144 significa "NOTE ON" . Mas, para executar um evento NOTE ON , o seqüenciador precisa saber algumas coi sas. Imagine o seqüenciador dizendo "Certo. reproduzirei uma nota, mas em que canaL? Em outras palavras, você quú que eu reproduza uma nota de bateria ou de piano? E que nota ? Dó maior? Ré sustenido? E j á que falamos nisso, com que velocidade devo reproduzir a nota'?" Para gerar uma mensage m MIDI, crie uma instância de ShortMessage e chame setMessageO, passando os quatro arg umentos da mensagem. Mas lembre-se de que a mensagem só informa () que fazer, portanto, você ainda terá que in seri-Ia em um evento que adicione quundo essa mensage m deve ser ' aciollada ' .

244

capituio 11

manipulação de exceções

Anatomia de uma mensagem
primei ro argumento de setMessage() sempr e repr esenta o 'tipo' da mensagem, enquanto os outros três representam coisas dife rente s dependendo do tipo da mensagem.

o

o objeto Message diz o que fazer, o MidiEvent informa quando fazê-lo.

a.setMessage( 1 44,

1,

44,
/

3 últimos argumentos variam dependendo do tipo da mensagem. Essa é uma mensagem NOTE ON, portanto os outros argumentos são para as coisas que o seqüenciador precisa saber para reproduzir uma nota.

(!) Tipo

da mensagem

® Canal Considere

144 s i gnifica NOTE ON

o canal como o músico de uma banda. O canal 1 é o músico 1 (o tecladista), o canal 9 é o baterista , etc.

Nota a reproduzir Um núme ro de O a 127 , indo das notas baixas às altas. a reproduzir

Velocidade Com que rapidez e intensidade pressionou a tecla? O é tão suave que provav elmente você não ouvirá nada , mas 1 00 é um bom padrão .

Altere uma mensagem
Agora que você sabe o que existe em uma mensagem Midi, pode começar a testar. Pode alterar a nota que é reproduzida, sua duração, adicionar mais notas e até mesmo mudar de instrumento.
Altere a nota Tente um número entre O e 1 27 nas mensagens note on e note off.

a.setMessage(144,

1,

20 , 100 );

Altere a duração da nota Altere o evento note off (e não a mensagem) para que ele ocorra em uma batida anterior ou posterior .

b.setMessage(128,

1, 44,

10 0);

MidiEvent noteOff = new MidiEvent(b,

3 );

Altere o instrumento Adicione uma nova mens agem, ANTES da me nsagem de reprodução da nota, que configure o instrumento do cana l 1 com algo d iferen t e do piano padrão . A mensagem de mudança de instrumen to é a '192' e o terceir o argumento repre senta o i nstrumen t o prop ri amente dito (tente um númer o entre O e 127 )

você está aqui

~

245

~-~---------------------------------------------------------

altere o instrumento e a nOta

Versão 2: usando argumentos

d_~Jinoa ge

comando para testar sons

Essa versão continuará reprod uzindo apenas uma nota, mas você poderá usar LU'gumentos de linha de comando para alterar o instrumento eil nota. Experi mente passar doi s valores int de O a 127 . O primeiro inteiro configurará o instrumento e o segundo, a nota ser reprod uzida.
import javax.sound.midi.*; pubIic cIass MiniMusicCmdLine {
I I esse é o primeiro

pubIic static void main(String[) args) MiniMusicCmdLine mini = new MiniMusicCmdLine(); if (args . Iength < 2) System.out . println("Não se esqueç a dos argumentos do instrumento e da nota " ) ; } eIse { int instrument = Integer.parselnt(args[O)); int note = Integer.parselnt(args[l)); mini.pIay(instrument, note);
}

II fecha main

public void play(int instrument, int note) try { Sequencer pIayer = MidiSystem . getSequencer(); p1ayer.open() ; Sequence seq = new Sequence (Sequence . PPQ, 4); Track t rac k = seq.createTrack(); MidiEvent event
=

nu11;

ShortMessage first = new ShortMes sage() ; first.setMessage(192, 1, instrument, O); Midi Event changelnstrument = new MidiEvent(first, 1); track.add(changelnstrument); ShortMessage a = new ShortMessage(); a.setMessage(144, 1 , note, 100); MidiEvent noteOn = new MidiEvent(a, 1); track . add(noteOn) ;
Execute- o com dois argumentos int à e

ShortMessage b = new ShortMessage(); b.setMessage(128, 1, note, 100); MidiEvent noteOff = new MidiEvent(b, 16) ; track . add(noteOff) ; player.setSequence(seq) ; player.star t() ; catc h (Exc eption ex) {ex.printStackTrace() ; }

O a

127~

Tente

es~es

para começar :

II fe cha p1ay II fecha c1ass

Onde chegaremos com as outras receitas de código
BeatBox

Bass Drum

Clo<.d Hi- Hat =: ~~ =C~ g~

Capítulo 15: o objetivo
Ao terminarmos, teremos uma BeatBox funcional, que também será um cliente de bate-papos de bateria. Teremos que aprender sobre as GUls (inclus ive a manipulação de eventos), a EIS, rede e segmentos. Os três próximos capítulos (1 2, 13 e 14) nos apresentarão esses assuntos.

Open Hi-Hat : '

Acoustic Snare Crash Cymbal

= = C.=== = ='=;'=:::' = = C: '=~::== c: ==:: = C == = = = =
'= ~ ==:= ~~

g ,= =:; ~ ~2= ~ =c:::r= ~ Cc.:=
~

~;

~
• Tempo Up ...

3.mpoDown ,..--_._------,.
s endlt

~

Hand Clap
High Tom
Hi Bongo

Maracas

==c::: ~= ==<:; ~::= fY!~~ ::
~ C~ ~ ~~~C~ 2 ~=~C~ C

dance beat

Whi stle

LowLonga
Cowbell
Vlbraslap
.~

Low- mi d Tom =:'= ~,:--'.- r- .- -. High Ag ogo

=::2==-'= ==.=-- == == =
~

-

,-. --. ;,

.-..

Chri s: groove2 revised

- - _._.... _----_.__.

__ _

... ..._

- ----_._- ----"'"-

246 c ,,!pitulo 11

manipulação de eXGeções

capítulo 12: eventos MIDI
Essa rece ita de código nos permitirá construir um pequeno "vídeo musicar' (é um exagero chamá-lo assim) que desenhará retângulos aleatórios de acordo com a batida da música MIDl. Aprenderemos como construir e reproduzir vários eventos MIDI (em vez de apenas alguns, como fizemos no capítulo atual).

batida um

batida dois

batida três

batida quatro

Capítulo 13: BeatBox independente
Agora construiremos realmente a BeatBox, a GUI e todo o resto. Mas teremos limitações - assim que você alterar um padrão, o anterior será perdido. Não haverá um recurso de salvar e recuperar, e e la não se comunicará com a rede. (Mas você ainda poderá usála para trabalhar nas suas habilidades em padrões de bateria.)

Capítulo 14: Salvar e recuperar
Você criou o padrão perfeito e agora poderá salvá-lo em um arquivo e recarregar quando quiser reproduzilo novamente. Isso nos preparará para a versão final (Capítulo IS ), onde em vez de gravar o padrão em um arquivo, o enviaremos através de uma rede para o servidor de bate-papo.

Este capítulo explorou o maravilhoso mundo das exceções. Sua tarefa é definir se cada uma das declarações a seguir sobre exceções é verdadeira ou falsa.

Verdadeiro ou falso
1. Um bloco try deve ser seguido por um bloco catch e um bloco fin ally. 2. Se você criar um método que possa causar uma exceção verificada pelo compilador, deve inserir esse código perigoso em um bloco try/catch. 3. Os blocos catch podem ser polimórficos. 4. Só exceções 'vetificadas pelo compilador' podem ser capturadas.
1Í~

S. Se você definir um bloco try/catch , um bloco finally correspondente será opcional.

6. Se você definir um bloco try, poderá complementá-lo com um bloco catch ou finally correspondente, ou com ambos. 7. Se você criar um método que declare que pode lançar uma exceção vetifioada pelo compilador, também deve inserir o códiao que lança a exceção em um bloco try/catch. b 8. O método mainO de seu programa deve manipular todas as exceções não-tratadas lançadas para ele. 9. O mesmo bloco try pode ter muitos blocos catch diferentes. 10. Um método só pode lançar um tipo de exceção.
II . Um bloco finalIy serú exec utado independentemente de um a exceção ter sido lançada.

12. Um bloco finally pode existir sem um bloco try. 13. Um bloco try pode existir sozinho, sem um bloco catch ou finally. 14. Manipular uma exceção às vezes é chamado de 'desviar-se'. 15. A ordem dos biócos
tlliêrl /lLIJlca

é inrpoflclll lC.

- ------~ -

16 . Um métoclo com um bloco try e um bloco final1y pode opcionalmente dec larar a exceção. 17. Exceções de tempo de execução devem ser manipuladas ou declaradas.

você está aqui..

247

exercício: írnés COiTl I:ódigo

~

:r;:,;?;; ~ [
'

~~

_

-

_Jmª$ c9rn_ çódig-º- .

..

~
.

; ,,' ".

Um progra.m a Java fUllC.i onal está todo lllisturado sobre a geladeira. Você conseguiria reorganizar os trechos de código para criar um programa Java funcional que produzisse a saída listada a seguir? Algumas das chaves caíram no chão e são muito pequenas para que as recuperemos, portanto fique à vontade para adicionar quantas precisar!

r--~system. out. print ("r")

System.out.print("t") ; doR i sky (tes t) ;"I!!""'i:~~"Ii1I'''!'"I''"!!t'!'~~,","",......,..,.........

..Jl

System.out.println("s") ;

class public

MyEx

extends

Exception

{~

}

class

ExTestDrive

System . out . print("a") ;

MyEX() ; catch (MyEx
& ,.,

e)

static vo i d doRisky(String throws MyEx { System.out . print("h") ;

t)

~.

,.

\

public static void main (~tr in g String test = args[OJ,

[1

args)

248 eapituto 11

manipulação de exceções

Verticais
2. Sendo utilizado atualmente

Horizontais
1.0arvalor -'-, 4. Retirado do topo ...._ .6. Tudo isso e mais! . 8. Iniciar 13. Não se desviar 15. Objetos que representam problemas . 18. Uma entre as '49' da Java 19. Hierarquia de classe 20. Não dá para manipular 23. Tipo primitivo comum . 24. Receita de código 26. Ação de método imprevisível 27. O oposto de Picasso
Mais dicas:
···sOJawI}N ·S (a[dwexa

3. Criação de modelo 5. Classe do APl quase sempre estática 7. Não está relacionado com o comportamento 9. Não mostre às crianças 11. Crie mais um independente 12. Javac notou sua presença 14. Tentativa arriscada 16. Aqu isição automática 17. Método de alteração 20. Anuncie que se desviará 21. Lide com isso 22. Dê más noticias 25. Uma de minhas funções 27. O modelo 28. Inicia uma cadeia de eventos

..

-";: ~~.

~ 10. A árvore genealógica

o)un fuo:J ap odl) wn 9 w9qwel JeJepap ap zafl w3 ewa[qoJd wn el:J!u[ ·92: >peno ·02:

·6~
T~

opesn .?~.1.LOpUJIPptnll:bt)...)====-:_ Jo"j!_·~r_ _-,- Jlsqe o~N LG I Oj8-,el[! w eJ ep eunjJoJ
I;j

·9 ~

efler Olj[!J wn ·9
S!ElUOZPOH

o!êjped no 8:Ji[ql}d 98 ·6

você está aqui

~

249

so lu ções clo: exc·

C,::;IOS

r-Imãs com -- -

códiQO

-

cla s s MyEx extends Exception { } public class ExTe stDri ve ( p ubl ic static void main(String [] a rgs) String test = args[O ]; try ( {

Verdadeiro ou falso
1. Falso, um dos blocos ou os dois . 2. Falso, você pode declarar a exceção. 3. Verdadeiro. 4. Falso, a exceção de tempo de execução pode ser capturada.

System .out .print("t") ; doR is ky(test) ; System.out.print("o"); catch ( MyEx e) (

System.out .print("a") ; finally ( System . out . print("w") ; System o ut . println("s " );
}

5. Verdadeiro.
6. Verdadeiro, os dois são aceitáveis. 7. Falso, a decl aração é suficiente. 8. Falso, mas se ele não fizer isso a JVM pode ser encenada. 9. Verdadeiro. ]0. Falso. 11. Verdadeiro . Geralmente ele é usado para encerrar tarefas parcialmente concluídas. 12. Falso. 13. Falso. 14. Falso, desviar-se é sinônimo de declarar.
15. Falso, exceções mais amplas devem ser capturadas pelos últimos blocos catch.
if

static void doRisky(String t) throws MyEx ( System . o ut . print("h"); ("yes".equals(t)) throw new MyEx ( ) ;

16. Falso, se você não tiver um bloc.;o calch, deve declarar a exceção.
17. Falso.

~ ~~

Respostas das Cruzadas Java

3 !?O

capítulo J 1

usando :- g:'

Uma história muito gráfica

Encare a verdade, você precisa criar GUls. Se estiver
construindo aplicativos que outras pessoas irão usar, você precisará de uma interface gráfica. Se estiver desenvolvendo programas para você mesmo, vai querer uma interface gráfica. Mesmo se você acredita que durante o resto de sua vida escreverá somente código no lado do servidor, onde a interface de usuário cliente é uma página Web, cedo ou tarde terá que criar fe rramentas e vai querer uma interface gráfica. Está certo, os aplicativos de linha de comando são nostálgicos, mas não de uma' maneira positiva. Eles são fracos, inflexíveis e pouco amigáveis. Dedicaremos dois capítulos ao trabalho em GUls e aprenderemos mais recursos-chave da linguagem Java, incl usive a Manipulação de Eventos e as Classes Internas. Neste capítulo, inseriremos um botão na tela e faremos com que ele execute algo quando for clicado. Desenharemos na tela, exibiremos uma figura jpeg e trabalharemos até mesmo com um pouco de
~Á=
~nit""'\"'1I":l ~

_ _ __ _ _ _ _

t..Â1 1111 I cc y C t v .

-~ ~

ii ...

JS,':: f> _ :Y1

nove> capítclio

251

sua primeira 9l.

Tudo começa com uma janª@
Um JFrame é o objeto que represema um a janela na tela. É onde você i nserirá todos os elementos da interface como os botões, caixas de seleção, campos de texto e assim por diante. Ele pode ter uma barra de menu amigável com itens de menu. E terá todos os pequenos ícones de janela para qualquer plataforma em que você estiver trabalhando, para a minimi zação, maximização e fechamento da janela.

"Se eu deparar com mais um aplicativo de linha de comando, você está despedido."

o JFrame terá uma aparência diferente, dependendo
da plataforma em que você trabalhar. Esse é um objeto JFrame no Mac OS X:

eoo
file

Panic

------~-------------

Deviate

______ _

(i'G~:m?

>e choose me

Criar uma GUI é fácil:
um JFre.me c om uma barra de menu e

Crie uma moldura (um objeto JFrame) JFrame frame = new JFrame ();

dois elementos gráficos ( um botão comum e um botão de rádio )

®

Crie um elemento gráfico (botão, campo de texto, etc.) JButton button = new JButton("click me") Adicione o elemento gráfico à moldura frame.getContentPane( ) . add(button);

Insira elementos gráficos na janela
Quando você tiver um JFrame, poderá inserir coisas ('elementos gráficos ') nele adicionando-as ao objeto. Há vários componentes do Swing que você poderá adicionar; procure-os no pacote javax.swing. Entre os mais comuns estão JButton , JRadioButton, JCheckBox, JLabel, JList, JScrollPane, JSlider, JTextArea, JTextField e JTable. A maioria é muito simples de usar, mas alguns (como JTable) podem ser um pouco mais complicados.

Cc-".u.sidez-e
:ro~ê

iToC'ê não adicionará os elE!.Went os i5Lr~t Ç!_ment...e a. moldu:ra ~ ............... __-._..... . _.._._ & moldura como o con=-orno de ja.fle2a.;
..
'

adicionaxa

(.;$

elêlllentos ao

~é.:ine~

da janela"

Exiba a GUI (forneça um tamanho e torne-a visível) frame . setSize(300,300) ; frame.setVisible(true) ;

Sua primeira GUI: um botão em uma moldura
import javax.swing . * ; ~----------------------public class SimpleGuil public static void main
não se esqueça de i1íTp0:r;,G.z esse pacoce swillg

(String[]

args)

{

cxia uma moldura e u!t~ Dotão (você poõe passar pa=a c con~t~utor

JFrame frame = new JFrame(); JButton button = new J Bu tton ("click me") ;

~

deseja no botaoJ

essa l:':nhe. fará com que o pTogrema seja Gncerrado assim q./}te" voe;:' f'8clJ.b.7' lJ. jaIle1.a frame . setDefaul tCloseOperation (JFrame. EX IT_ON_CLOSE) ; ~ ela não tor illcluida, D .1;),:,",;:;rá..';3. ficará

(se

frame . getContentPane() . add(button); frame . setSize(300.300);
~---------

frame . setVisible(true) ;

:.'":.",

252

capítuio.12 .

usando a

Vejamos o que acontece quando executamos o código:
%java SimpleGuil

Não existem

Uau! Esse é um botão realmente grande.
o botão pre encheu todo o
espaço disponível na moldura. Posteriormente aprenderemos a controlar onde (e com que t amanho) o botão ficará na moldura.

Perguntas Idiotas
Um botão terá a aparência do Windows quando essa plataforma estiver sendo usada? Se você quiser. Você pode selecionar entre alguns "formatos" classes da biblioteca principal que controlam a aparência da interface. Quase sempre é possível selecionar entre pelo menos duas aparências diferentes: a aparência Java padrão, também conhecida como Metal, e a aparência nativa de sua plataforma . As telas do Mac OS X deste livro usam a aparência Aqua do OS X ou a aparência Metal. Posso fazer um programa ter a aparência Aqua o tempo todo? Mesmo quando ele estiver sendo executado no Windows? Não. Nem todos os formatos estão disponíveis em todas as plataformas. Se você não quiser ter problemas, pode configurar explicitamente a aparência com Metal, para saber exatamente como ela será exibida independentemente de onde o aplicativo for executado, ou não especificar uma aparência e aceitar os padrões. Ouvi dizer que o Swing é muito lento e que ninguém o utiliza.

P:

R:

Mas nada aconteceu quando eu cliquei nele ...
Isso não é totalmente verdade. Quando você pressionar o botão, ele exibirá a aparência de que foi 'pressionado' ou 'apertado' (as diferenças vão depender da aparência da plataforma, mas ele sempre fará algo para mostrar que foi pressionado). A verdadeira dúvida é "Como fazer o botão executar algo específico quando o usuário clicar nele?"

P:

Precisamos de duas coisas:

Um método a ser chamado quando o usuário clicar (o que você quiser que ocorra como resul tado do clique no botão) .

R:

uma maneira de saber quando acionar esse método. Em outras palavras, uma maneira de saber que o usuário clicou no botão!

fL:l;~
" ~ -'

.

~

. ~~­
J'"

).~'

'r9:
c A
;:;.:
~.)4,~".

Quando o usuário clicar, queremos saber. Estamos interessados no evento 'usuário fez algo com o botão'.

Isso era verdade no passado, mas não acontece mais. Em máquinas fracas , é possível sentir os problemas do Swing. Mas nos desktops modernos, e com a Java versão 1.3 e posteriores, talvez você nem note a diferença entre uma GUI do Swing e uma GUI nativa. O Swing é muito usado atualmente, em todo tipo de aplicativo.

P: R:

,)1IL
esro1

253

-

- - -- -- - - - - - -- - - - - -

ouvintes ( ;:; SV!3filry:;

_ çapturando um

eventost~U,J,§'lJáC~ _,

Suponhamos que você qui sesse que o texto do borjo fos se alterado de click me para J've been clicked quando o usuário pressionar o botão, Primeiro podemos criar um método que altere o texto do botão (uma pesquisa rápida no APl lhe mostrará o método):
publ i c void changel t() button.setText("I've been c l icked'" );

' PrimeilO, o botão-pTecisa saber -quenos importamos.
tece c om voce . f.j\ El, bot \V com o que aco n . ão, eu me preocupo "

Seu

'd '

co

r l~J

i

E agora? Como saberemos quando esse método deve ser executado? Como saberemos quando o botão foi clicado? Em Java, o processo de capturar e manipular um evento de usuário se chama manipulação de evento. Há muitos tipos de eventos diferentes em Java, embora a maioria envolva ações de usuário em GUI. Se o usuário clicar em um botão, isso será um evento. Um evento que representa "o usuário quer que a ação desse botão ocorra". Se for o botão de uma ação "lenta", é porque o usuário quer que a ação lenta ocorra. Se for o botão Enviar de um cliente de batepapo, o usuário quer que a ação 'envie minha mensagem' ocorra. Portanto, o evento mais simples é quando o usuário clica no botão, indicando que deseja que uma ação ocorra. No que diz respeito aos botões, geralmente não temos que nos preocupar com qualquer evento intermediário como 'o botão está sendo pressionado' ou 'o botão está sendo solto'. O que queremos dizer ao botão é "não me importa como o usuário o manipulará, quanto tempo ele manterá o botão do mouse pressionado sobre você, quantas vezes ele vai mudar de idéia e desi stir antes de pressionar, etc. Basta informar quando o usuário quiser realmente fazer algo! Em outras palavras, não me chame a menos que o usuário clique indicando que deseja que você faça o que se propõe a fazer! "

/

~~
® O usuário
clicou em mim!

Em segundo lugar, o botão precisa de uma maneira de nos chamar quando ocorrer um evento de clique.

o

poder do cérebro

1) Como você poderia dizer a um obj eto d e botão que se impo rta com seus eventos? Dizendo que é um ouvinte atento? 2) Como o botão o chamará? Suponhamos que não houvesse uma maneira de você informar ao botão o nome de seu único método [changelt() ]. O que poderíamos usar para garantir ao botão que temo s um método específic o que el e poder á chamar quando o evento ocorrer? [dica : lembre - se de Pet]

Se você se importa com os eventos do botão, que diga "estou

'implemenJe 'ÚÚ;Tla" interfâc~

escutando seus

eventos".

Uma interface de escuta é a ponte entre o ouvinte (voc ê) e a origem do evento (o botão),

Os componentes de GUl do Swing são a origem dos eventos. Em jargão Java, a origem de um evento é um objeto que pode converter ações do usuário (um clique com o mou se, o pressionamento de uma tecla, o fechamento de lima janela) em eventos. E como praticamente todo o resto em Java, um evento é representado como um objeto. Um objeto de alguma classe de eventos. Se você pesqui sar o pacote java.awt.event do APl , venl várias classes de eventos (fáceis de identificar todas têm Event no nome). Você encontrará MouseEvent, KeyEvent, WindowEvent, ActionEvc nt e muitas outras.

A origem de um evento (como o botão) cria um objeto de evento quando o usuário faz algo relevante (como clicar no botão). A maioria dos códigos que você escrever (e todos os códigos deste livro) receberá eventos' em vez de criá-los. Em outras palavras, você passará a maior parte do tempo como um ou vinte de eventos em vez de ser a origem, deles. Cada tipo de evento tem uma interface de escuta correspond ente. Se você lJui ser MOllseEvents, impl emente a interface MouseLi stener. Qu er WindowEvcnts? fmpl cmcnte WindowListener. Você entendeu. E le mbre-se das regras de

usando 2:

sua interface - para impl e mentar uma inte rface, -você terá que declarar q ue a implementa (a classe Dog implementa Pet), o CJue significa CJue terá que criar métodos de impLementação para cada método da interfaceAlgumas interfaces têm mais de um método, porque o próprio evento tem diferentes versões. Se vocêimplementar MouseListener, por exemplo, poderá capturar eventos de mousePressed, mouseReleased, mouseMoved, etc. Cada um desses eventos de mouse tem um método separado na interface, ai nda que todos sejam um MouseEvent. Se você implementar MouseListener, o método mousePressedO será chamado quando o usuário (adivinhe) pressionar o botão do mouse. E quando o usuário o soltar, o método mouseReleasedO será chamado. Portanto, para eventos do mouse, há apenas um objeto de evento, MouseEvent, mas vários métodos distintos, representando os diferentes tipos de eventos.

Como o ouvinte e a origem se comunicam :

"Certo, você passou a ser um ActionListener, portanto Sei como chamá-lo quando houver um even to - chamarei o métOdo actionPerformedO que sei qUe você te m."

Quando você implementar uma interface de escuta, estará fornecendo ao botão uma maneira de Ghamá-Io, A interface é onde o método de retorno de chamada é declarado, A origem do evento
O botão é a origem de ActionEvents, portanto, ele tem que saber que objetos são ouvintes ínteressados. Ele tem um método addActionListenerO para fornecer aos obj etos interessac\os (ouvintes) urna maneira de lhe informar qUe têm interesse.
Quando o método addActionListenerO do botão for executado (porqUe um poss ível ouvinte o chamou) , o botão pegará o parfnnetro (uma referência do obj eto ouvinte) e o armazenará em uma lista. Quando o usuário clicar no botão, esse 'ac ionará' o evento chamando o métOdo actionPerformedO em cada ouvinte da lista_

o ouvinte
Se sua classe quiser ser informada dos ActionEvents de um botão, você terá que implementar a interface ActionListener. O botão precisa saber que há interesse, portanto, você se registrará nele chamando seu método addActionListener(this) e - assando uma'referência p ActionListener (nesse caso, você é a interface ActionListe ner, logo, passe this). O botão precisa de uma maneira de chamá-lo quando o evento ocorrer, portanto ele chamará o método da interface de escuta. Como uma interface ActionListener, você deve impl ementar seu -:---:--:--único método, ------actionPerformec\O. O compilador verificará isso.

r .

~

--

você está aqui

i>

255

capturando

e'/e'l~OS

Capturando o ActionEvent de
Implemente a

UITL

botão

interface ActionListener (informe a ele que você quer

Registre-se no botão escut a r os even to s)

®

Defina o método de manipulação de eventos (implemente o método actionPerformed() da interface ActionListener)

impor t import

javax . swing . *; java. awt. event. *;

'E:.......-------'------.-----

uma noto-a in strução ae import ação para o pacot e no qual Acti onLístener e ActionEvent est Êi.o

CD
public class S i mpleGuilB implementa ActionListener { JButton button; public stat ic void main (String[] args) S imp leGu il B gu i = new Simpl eGuil B() ; gu i .go () ;

~

implementa a interface .. Isso representa numa instância de SimpleGU.:r13 É-m. ActíonListener fl botão fornecerá e,:rentos somente para quem implementar ActionLls tener)

public vo id g o() JFrame frame = new JF r ame(); but ton = new JBut ton ("click me");

®

button. addActionListener (this) ;

tE'E'---- -- - - - -

reç;istre seu interesse junto ao botão . Xsso dirá ao batão "Me adicione à sua lista de ouvintes". a arg'..!msnto que voei Pi;.SSêZ DE';,!7g ser um objeto de uma classe que implemente Actio::i.Listener!

frame.getContentPane() .add(button) ; frame . setDefaultCloseOperation(JFrame . EXIT_ON_CLOSE) ; fr ame . set Siz e( 300, 300) ; frame . setVisible (true) ;

imple..'!1snte o método actionPe.:-for.meã ()

da

interface ActionListener. Esse é realment e o método de manipulação de eventos!
~ public void actionPerforrned(ActionEvent event) button. setText ("I 've been clicked!");
{

<E----

O botão chamará esse método para per.w~tir que você s~.iba q-üe um &1r anto ocorreu. Ele lhe
enviar á um cbjato ActionEv-ent: co.mo a!:"gumento r

mas não precisaremos dele~ Saber que o evento ocor~eu é o bastante para nós.

Ouvintes, origens e eventos
Em grande parte de sua meteórica carreira em Java, você não usará a origem de eventos. (Independentemente de o quanto você achar que é o centro de seu universo social.) Acostume-se com isso. Sua tarefa é ser um bom ouvinte. (O que, se você fizer sinceramente, pode melhorar sua vida social.)

o evento

registras (dos ouvintes) . capturar eventos do usuário e chamar o método de manipulação de eventos do ouvinte (quando o usuário clicar em mim).

Ei. e eu? Também estou participando. sabe como é! Como um objeto de evento. Sou o argumento do método de retorno de chamada de eventos (da interface) e minha tarefa é retornar dados sobre o evento para o

o
do

objeto de evento CONTÉM DADOS sobre o evento

o evento
256 capítulo 12

usando " Qui

Não existem

perguntas Idiotas
Por que não posso ser uma origem de eventos? Você PODE. Acabamos de dizer que quase sempre você será o receptor e não a origem do evento (pelo menos no início de sua brilhante carreira em Java). A maioria dos eventos que pode ,.. lhe interessar será 'acionada ' por classes do APl Java e tudo que você terá que fazer é ser seu ouvinte. Você pode, no entanto, projetar um "" ~"""""r"'ma em que precise de um evento personalizado, digamos , StockMarketEvent, lançado quando seu aplicativo observador do mercado de ações encontrar algo que ele " considere importante. Nesse caso, você criaria o objeto StockWatcher como sua origem de eventos e faria as mesmas coisas que um botão (ou qualquer outra origem de eventos) - criar uma interface de escuta para seu evento personalizado, fornecer um método de registro (addSotckListener()) e, quando alguém o . chamasse, adicionar quem chamou (um ouvinte) à de ouvintes. Assim, quando um evento de . ação ocorresse, você poderia instanciar um objeto StockEvent (outra classe que você criará) e enviálo para os ouvintes de sua lista, chamando seu ~ método stockChanged(StockEvent ev). E não se esqueça de que, para cada tipo de evento, deve baver uma interface de escuta correspondente [portanto, você criará uma interface StockListener com um método stockChanged()] .

P: R:

Não entendo a importância do objeto de evento que é passado para os métodos de retorno de chamada de eventos. Se alguém chamar meu método mousePressed, de que outras informações eu precisaria? Quase sempre, na maioria dos projetos, você não precisará do objeto de evento. Ele nada mais é do que um pequeno portador de dados, para enviar mais informações sobre o evento. Mas em algumas situações você pode ter que consultar o evento para saber detalhes sobre ele. Por exemplo, se seu método mousePressedO for chamado, você saberá que o mouse foi pressionado. Mas e se quiser saber exatamente onde ele foi pressionado? Em outras palavras, e se você quiser saber as coordenadas x e y na tela que indiquem onde o mouse foi pressionado? Ou em alguns casos você pode querer registrar o mesmo ouvinte em vários objetos. Uma calculadora exibida na tela, por exemplo, tem 10 teclas numéricas e já que todas fazem a mesma coisa , talvez você não queira criar um ouvinte separado para cada tecla. Em vez disso, pode registrar um único ouvinte com cada uma das 10 teclas e quando capturar um evento (porque seu método de retorno de chamada de eventos foi chamado) poderá chamar um método no objeto de evento para descobri r quem foi a verdadeira origem desse evento. Em outras palavras, que tecla enviou esse evento.

P:

R:

~

Apo nte seu l á pis

-~

Como saber seum objeto é a origem de um evento?.

Cada um desses elementos gráficos (objetos de inteli'ace de usuário) é a origem de um ou mais eventos. Ligue os elementos aos eventos que eles podem causar. Alguns elementos podem ser a origem de mais de um evento e alguns eventos podem ser ' gerados por mais de um elemento.

Elementos gráficos
caixa de seleção campo de texto lista de rol agem botão

Métodos do evento
windowClosing() actionPerformed() itemStateChang ed() mousePressed() keyTyped() mouseExited() focusGained()
- - - .-

Um método que comece com "- -'àdd', termine coni~'Listé-nêr' e use como argumento uma' interface. de escuta. Se você vir:
a ddKeyLi s tener(KeyL istener -k)

~:..
Lo'". ~ ~

caixa de diálogo botão de rádio item de menu

saberá que uma classe com
_-.-___ .A. ... ~,.,...a..
c;,,;,c I l l v_ I.VUV Çi

".;.

,

KeyEvents. Há nomeação.

um padrão. de
lo-

~ Q

n.J"...i.aorn do
VI
I~"""III . ,--",

você está aqui

257

criando um painel

U~~2<; " 1.

\/nlt::lnrl n - -._-. -_.-

~ r - - -- (lr~fir.::1 - n::1rtp ;;;)- - --------

Agora que sabemos um pouco mais sobre como os eventos funcionam (aprenderemos mais posteriormente) , voltemos à in serção de elementos na tela. Passaremos algum tempo examinando algumas maneiras divertidas de usar um ambie nte gráfico, antes de retorn arm os à manipulação de eventos.

Três maneiras de inserir elementos em sua GUI:
Insira elementos gráficos em uma moldura
Adicione botões, menus, botões de rádio, frame _getContentPane() .add(myBut t on); etc.

File

Panic

Deviate

o pacote javax . swing tem vários tipos de e l ementos g ráficos_

®

Desenhe figuras 2D em um elemento gráfico
Use um objeto gráfico para desenhar formas . graphics_fillOval(70,70,lOO,lOO); você pode desenhar muitas outras caixas e círculos; o APl Java2D está cheio de métodos gráficos divertidos e sofisticados .

I~ra ~ figura JPEG em um elemento grifico Você pode inserir suas próprias fotos em um elemento gráf ico_

graphics . drawlmage(myPic,

lO,lO,this);

Crie seu próprio elemento gráfico de desenho
Se você quiser inserir figuras suas na tela, a melhor opção é criar seu próprio elemento gráfico de desenho. Você inserirá esse elemento gráfico na moldura, da mesma forma que um botão ou qualquer outro elemento, mas quando ele for exibido terá suas figuras. Você pode até fazer essas figuras se moverem, em uma animação, ou as cores mudarem na tela sempre que c]jcar em um botão.

É muito fácil.

Crie uma subclasse de JPanel e sobreponha um método, paintComponent( ).
Todos os seus códigos gráficos serão inseridos no método paintComponentO. Pense nele como o método chamado pelo IJ"!!'~!""""-----' r;~ sistema que diz "Ei, elemento gráfico, é hora de receber desenhos". Se você quiser desenhar um círculo, o método paintComponent terá um código para isso. Quando a moldura que tiver seu painel de desenho for exibida, paintComponentO será chamado e seu círculo aparecerá. Se o usuário minimizar a janela, a JVM saberá que a molclura precisará de "reparos" quando for maximi zada, portanto chamaní paintComponentO novamente. Sempre que a JVM achar quea ex ibi ção preci sa de atuali zação, seu método paintComponentO será chamado. Mais uma coisa. você nunca chamará esse método por sua conta! O argumento do método (um objeto Graphics) é o espaço de desenho que será inserido na tela real. Não é possível capturá-l o por sua própria conta; ele deve ser fo rnecido!i&;lIiIiIIlIiIiIIlIiIiIIiIIIiEil_=-" pelo sistema. Você verá posteriormente, no entanto, que [Iode solicitar ao sistema que atualize a tela frepaint()], o que acabará fazendo com que paintComponcntO seja chamado.

258

capítulc 12

usando a gw

import java . awt . *;

(~------____________________

-===__ _------::::::====(~-------

vcce precisará dessas duas i11Scruçõe.s

import javax .swing . *; ~
Cr:i.a uma subcl asse de JPaIlêl,
t:.U:

81 emento gráf.ico <rue \roce

class MyDrawPanel extends JPanel {

adicionará a uma moldura como qualquer outra coisa. EJlcetc
por ser seu próprio elemento gráfíco personalizado.

Esse

public void paintComponente(Graphics g)

{

~

e o importantíssimo método g::'áfi".;o. Você trüNCA o chamará por sua própr ia conta. O sistema o cbamará e dira "Aqui está uma superf~cie de desenho nova em folba,
de tipo Graphi cs,

na qual você pode desen21.::r agora/' .

g . setColor(Color.orange); g.f il lR ec tI20 , 50, lO O,lOO) ;

( ----------

SUponhamos que

'g'

fosse uma máquina de desenllo .
~~e

Você

está dizendo para ela com
qual

cor pintar e, em seguida,

que forma desenhar o tamanho)

(cam as coordenadas de onde inserir e

Coisas divertidas que podem ser feitas em paintComponent( )
Examinaremos mais algumas coisas que você pode fazer utilizando o paintComponentO. O mais di vertido, no " entanto, será quando você começar a experimentar sozinho. Tente usar vários números e procure no APL a classe Graphics (posteriormente veremos que sempre é possível fazer ainda mais do que a classe Graphics oferece) .
seu arqui,.o entra aqui

~xiba

uma figura JPEG

Image image

~

n e w I magelcon ("ca tzi l la. jpg") . getlmage () ;

g.draw l mage(image,3,4,this) ;

II
r, t".. . i"

x, y de onde o canto esquerdo da figura deve ficar. Essa instrução diz " 3 pixeds a partir da borda esquerda do pai nel e 4 pixel s a partir da bDrda superior". Esses números sempre se referem ao elemento gráfico (ne sse caso sua subclasse Jpanel) e não à moldura inteira .
AS coordenadas

Desenhe um círculo colorido aleatoriamente em um plano de fundo negro

public void paintComponent(Grpahics g)

preenche o painel inteiro com preto (a cor paàrãoj
Os dois

primeiros argumentos de finem o canto

g.fillRect(O,O,th i s . getWidth(),

this . getHeight());

~

supc=rior esquerdo (x.. y ), em relação ao painel" de onde o d$senbo começará i portanto, 0 1 0 sígni.fica ltCCInece a O pixels Od borda esquerda e

O pixels da borda díreita H • Os outros dois

~

f;

int re d ~ (int) (Math . random() * 255) ; int green ~ lint) (Math.random() * 255); int blue ~ ( int) (l<1ath. random () * 255);
CC'lC'r randomColo r

largura desse recângulc seja tão ampla ~aanto o painel [tb.J.;s~ wid ti1( }] e a alt ura. também (tb.i S .Í10igh. t)n
Você
~ode

argumentos infcnna..>n "Faça com que a

criar uma cor passando 3 ints para

= new

\.01

or (red . ~eIL~l.,L~LL-_

!"§..oressI:1tll-!' os

valores RG3.

g . setColor(randomColor) ; g . fill OvalI 70,70,lOO,lOO) ;

comece il '10 pixe ls da esqu e rda e 70 do tope, faca cer 100 pixels de larfTura e 100 da alt:~Ia_

você eSla aqui ....

259

criano gradientes

~:r-:--

I

~"'a~!

. :-.;

Por trás de toda boa referênçjª_QC9phics e)Çi§Je. ________._õ 1",v.. c. r\l1 ó.+I"'\"'''~ ",,,,,,, Ao """,....,..." ,"!Uv YVuv jJU\.Iv um objeto Graphics2D. chamar em uma referência
V\.llJ~
, " I ,,..,

o argumento de paintCo ll1ponen tO é decl arado com o tipo Graphics
(ja va.a wt. Graph ics).
publi c vo id p ai nt Comp onent (Graphi cs g ) { }

Graphics:
drawlmage() drawLineO drawPolygonO drawRectO drawOvalO fiIIRectO fillRoundRectO setColor()

Portanto, o parâmetro 'g' É-UM objeto Graphics. O que significa que ele

poderia ser uma subclasse de Graphics (por causa do polimorfismo).
E realmente é.

o objeto referenciado pelo parâmetro (g' na verdade é uma instância da classe Graphics2D.
Por que se preocupar? Porque há coi sas que você pode fazer com uma referência Graphics2D que não poderia fazer com uma referência Graphics. Um objeto Graphics2D pode fazer mais coisas do que um objeto Graphics e existe realmente um objeto Graphics2D por trás da referência Graphics. Lembre-se do polimorfismo. O compilador decidirá que métodos você pode chamar com base no tipo da referência e não no tipo do objeto. Se você tiver um objeto Dog referenciado por uma variável de referência Animal:
Anima l a = new Dog();

Para converter o objeto Graphics2D em uma referência Graphics2D:
Graphics2 D g2d = (Graph i cs2D) g;

NÃO poderá dizer:
a . b a rk() ;

Métodos que você pode chamar em uma referência Graphics2D:
fill3DRectO draw3DRectO rotateO scaleO shearO transformO setRenderingHintsO

Mesmo sabendo que na verdade trata-se de um objeto Dog. O compilador examinará 'a ' . verá que tem o tipo Animal e decidirá que não há botão no controle remoto da classe Animal para barkO. Mas você ainda poderá converter o objeto de volta ao tipo Dog que ele realmente é escrevendo:
Dog d = (Dog) a ; d.ba rk() ;

Portanto, o que importa com relação ao objeto Graphics é isto:

Se você precisar usar um método da classe Graphics2D, não poderá usar o parâmetro de paintComponent ('g') diretamente a partir do método. Mas poderá convertê-lo com uma nova variável Graphics2D.
Graphics2D g2d = (Graph i cs2D) g ;

(essas não são listas de métodos completas, verifique o APl para ver mais)

A vida é curta demais para pintarmos o círculo com uma cor sólida quando há uma composição em gradiente esperando por você.
public void paintComponent(Gra ph i cs g) Graphic s2D g2 d = (Graph i c s2D ) g ; (
~~------------

na verdade trata-se àe um objeto Grapbics2D disfarçado àe um simpLes objeto Grapbics converta-o para que possa:m.os chamar algo que Graphi.cs2 D tem mas que Grapb ícs n ã o tem

Gr adientpaint gradient

new Grad i entpaint

(70,70,Color.blue , 150,150 , Co l or . o r ange) ;

ponto 1nicí a l
COZO

1
I

ponto firléz ]

I
!

ini. cia 1

cor final
vir~ual

g2d . setPaint(gradient) ;

~(~-----------------------

isso configurará o pince1
grad:i p.nt:r-.oJtl -."f?"7

com um

';:;e:.

ll..mê

ro"-'r F01:! c-a

g 2d . fil l Oval( 7 0 , 70 , l OO,lOO );

o método f,i.1,,}(l"'''0.J (t nCf '!!"er.:JE;3.~~ ;'S":i.;-:'7~.~,';. .r:': ';'.;.7 tlpx:.ec.tJ.C:l:;,a. iZA. rnrm_e. ("n r 8.1 com <> qt:~':', ~ -;,ri.'í.rE<-t:· cl1.r:::-egndo o:rr:. .:Jst!: pincel {~Etc: é
J

260_ capítuio 12.

usando 2
public void paintComponent(Graphics g) Graphi c s2D g2d = (Gr a phics2D) g; (

int red = (int) (Nath.random() * 255); int green = (int) (Nath.random() * 255); int blue = (int) (Nath.random() * 255); Color startColor = new Color(red, green, blue); red = (int) (Math . random() * 255); green = (int) (Math.random() * 255); blue = (int) (Math . random() * 255); Color endColor = new Color(red, green, blue);

código é
cria.r cores

inicio e o f i"Ir!. do gradiente .. Teste-o.f

Gradientpaint gradient = new GradientPaint(70,70,startColor,150,150,endColor); g2d.setPaint(gradient) ; g2d.fillOval(70,70,lOO,lOO) ;
}

DISCRIMINAÇÃO DOS PONTOS
EVENTOS
criar uma GUI, comece com uma janela, que geralmente é um JFrame
JFrame frame = new JFrame();

FIGURAS
- Você pode desenhar figuras 2D em um elemento gráfico. - Você pode desenhar uma figura .gif. ou .jpeg diretamente em um elemento gráfico. - Para desenhar suas próprias figuras (inclusive uma figura .gif ou .jpeg), crie uma subclasse de lPanel e sobreponha o método paintComponent(). - O método paintComponent() é chamado pelo sistema da GU!. VOCÊ NUNCA O CHAMARÁ POR SUA CONTA. O argumento de paintComponent() é um objeto Graphics que lhe fornecerá uma superfície sobre a qual desenhar que acabará sendo exibida na tela. Você não pode construir esse objeto por sua própria conta. - Os métodos comumente chamados em um objeto Graphics [o parâmetro de paintComponent()] são:
graphics.setColor(Color.blue) ; g .fi llRect(20,50,lOO,120) ;

Você pode adicionar elementos gráficos (botões, campos de texto, ao JFrame usando:
frame.getContentPane() .add(button);

nprn",r'T<1

- Diferente da maioria dos outros componentes, o JFrame não que você adicione elementos diretamente, portanto, será preciso adicioná-los ao seu painel de conteúdo.

- Para fazer a janela (o objeto JFrame) ser exibida, você deve um tamanho e torná-la visível:

Para saber se o usuário clicou em um botão (ou executou alguma ação na intelface de usuário) você precisa ouvir o evento de Para ouvir um evento, você deve registrar seu interesse em uma de evento. Uma Oligem de evento é o elemento (botão, caixa de seleção, etc.) que 'aciona' um evento com base na interação do usuário. - A interface de escuta fornecerá para a origem do evento uma maneira de chamar você, já que definirá o(s) método(s) que ela chamará quando um evento ocorrer. - Para registrar-se em uma origem e ouvir os eventos, chame o método de registro dessa origem. Os métodos de registro sempre têm a forma: add<.EventType>Listener. Para se registrar e ouvir onEvents de um botão, por exemplo, chame:
button.addActionListener(this);
• ....... vU<vmv

- Para desenhar uma figura .jpg, crie um objeto Image usando:
Image image = new Imagelcon("catzilla .jpg") .getlmage();

e desenhe a figura usando:
g.drawlmage(image,3,4,this) ;

••• ... 'v,"'vo

a interface de escuta implementando todos os de manipulação de eventos que ela tiver. Insira seu código manipulação de eventos no método de retorno de chamada do vinte. Para ActionEvents, o método é:
public void actionPerformed(ActionEvent event) ( button . setText ("you clicked!");

- O objeto referenciado pelo parâmetro Graphics de paintComponent é na verdade uma instância da classe Graphics2D. A classe Graphics2D tem vários métodos inclusive: fill3DRect(), draw3DRectO, rotate(), scaleO, shearO, transformO - Para chamar os métodos de Graphics2D, você deve converter o parâmetro de um objeto Graphics para um

- O objeto de evento passado para o método manipulador de eventos terá informações sobre o evento, inclusive sua origem.

· l"hj::a:::~~~:?~:

[Graohicc2D)

g;

1.I0CB

esta

261

construindo uma molcJu : él U8 Ou ,

Podemos caoturar um evento.
- - . - - - - 1~

_. - -

-- -

-

. -- -

-- -- - - ~

-

- - - _ . _._... _-

--_.

Podemos desenhar figuras. Mas podemos desenhar figuras enquanto capturamos um evento?
Associemos um evento a uma alteração em nosso painel de desenho. Faremos o círculo mudar de cor sempre que você clicar no botão. Veja como é o fluxo do programa:
Inicie o aplicativo

® A moldura

Layouts de GUI: inserindo mais de um elemento gráfico em uma moldura
Abordaremos os layouts de GUI no próximo capítulo, mas daremos uma olhada rápida aqui para podermos continuar. Por padrão, uma moldura tem cinco regiões onde os elementos . podem ser adicionados. Você só pode~d ~~ , ---~" adicionar um elemento em cada " ~~l região da moldura, mas não entre em pânico! Esse elemento pode ser um painel contendo mais três elementos inclusive outró' painel que contenha mais dois elementos e ... Você entendeu. Na : verdade, estávamos 'trapaceando' quando adicionamos um botão à moldura usando:
frame.getContentPane() .add(button);

é construída com dois elementos gráficos (seu painel de desenho e um botão). Um ouvinte é criado e registrado no botão . Em seguida, a moldura é exibida e aguarda o usuário clicar.

®

o usuário
clica no botão e esse cria um objeto de evento e chama o manipulador de eventos do ouvinte .

o manipulador de eventos chama repaint() na moldura. O sistema chama paintComponent() no painel de desenho.
SCI'

frame.getContentPane() .add(BorderLayout.CENTER, button) ;

aàicionaâo a ela .

~ Voila! Uma nova cor é
pintada porque paintComponent() é executado novamente, preenchendo o círculo com uma cor aleatória. norte

região padrão

oeste leste

qCl'.:1. ..f.,mente

a

."LqaLÔ"TiaJ

ele adi,ciolJór elenienc(),s; de)

deseja illseriz' o elemcJJto grdficc

Dados os cenários da página xxx, escreva o código que adicionar~ o botão e o painel à moldura.

262 capitulo.

usando

"l
r'\

O circulo mudará de cor sempre que você clicar no botão.
import javax .s wing . *; import java .awt . *; import java .awt.event .*; public class SimpleGui3C implements ActionListener { JFrame frame; public static void main (String[] args ) SimpleGui3C gui ; new SimpleGu i3C () ; gui . go () ;
-,;:.-

r\
Á

() bot::~o está na reg'L~10 SUL

A

publ ic void go () frame ; new JFrame (); frame . s e t DefaultCloseOperation (J f rame . EXI T_ON_ CLOSE) JButton button ; new JButton("Cnage colors"); button . addActionListener ( this); MyDrawPanel ' drawPanel ; new MyDrawPanel(); frame.getContentPane () frame.getContentPane () frame.setSize (300,300 ) frame.setVisible(true )

i

A
Á

<t-«: ......----------

ilt..i~ci01Jcl

o

ouvinte

A
A

.J:
e-~c.'

.add (Bo rde,r Layout .SOUTH, button); .add (BorderLayout.CENTER, drawPanel) ; ; ;

«

Aa.l'':-.lc!.!a

os

âC1S

el~mencos

-:;z:áf.iccs

(bct:~o

'= pc.ioe::" de

public vo id actionPerf ormed(Ac tionEvent event ) ( frame.repaint (); ~< :......---------------------------

sel i.:;i:-e
reGEI i.l1a _
~

,..'

a

-"....$50

-

moldura que se
519..i1.11: l.C.:i

..

~

I~ruc:

paintCempon2nt;'

-,.:t' ~-

será chamado em cada elemento

class MyDrawPanel extends Jpanel ( public void paintComponent (G raphics g) II Cód i go para preenchimento da f orma ova l com uma cor al e atória II Consu l te a página XXX para v e r o código
.~~~

o método paintComponen t ()
':]0 p3.i11::::1 d~ âesenfl0

será

cha.mBdc 5E:-mpra
t.;:Eiu (:1 z-.i.,,)

<..11.1 (;

o

. .::'.l

.i

(~a.r

.

.~

~~-------------------------------------------------------------------------------------------------------------------Façamos um teste com DOIS botões
~

:....

~..:-

-.

o botão da região sul continuará agindo como antes, simplesmente chamando repaint na moldura. O seg undo
botão (que inserire mos na região leste) al terará o texto de um rótulo. (Um rótulo é apenas texto na tela.)

Portanto, agora precisamos de QUATRO·elementos gráficos

norte o rótulo entra rá aqui
;~

botão de alteração do rótulo ficar á aqui

I

<t:
centro leste

---.- o painel de desenho entrará no centro

A

A

,.
~,

o botão de alteração da cor entrará aqu i

263

"

vários ::;,)\

E orecisamos capturar DOIS eventos
I • __ _ _

_

~

____

~

___

~

__

Hummm. Isso é possível? Como capturar dois eventos se voce tem somente um método actionPerformed()?

f.
Chang, Label

Esse botão altera a cor do cir culo
'.

Como capturar os eventos da ação de dois botões distintos, se cada botão tem que fazer algo diferente?

~;.

tL·

"'..

CD opção

um: Implemente dois métodos actionPerformed( )

class MyGui implements ActionListener ( I I vários trechos de códigos em alguns locais : public void actionPerformed (Act ionEvent event) frame.repaint() ;

(~ Mas
public void actionPerformed (ActionEvent event) labelo setText ( "That hurt!");

~

i s so

e

i mpcssí 't."'e l J

Falha: Não é possível! Você não pode implementar o mesmo método duas vezes em uma classe Java. Ele não será compilado. E mesmo se você pudesse fazê-lo, como a origem do evento saberia qual dos dois métodos chamar?

®

opção dois: Registre o mesmo ouvinte nos dois botões.

class MyGui implements ActionListener { II declara diversas variáveis de instância aqui publ ic void go ( ) II constról a gui colorButton = new JButton () ; labelButton = new JButton(); colorButton.addActionListener (th is ) ; 'E----labelButton.addActionListener(this); ~­ li mais código de gui aqui ...

F:egis!;:re (;. meswo ou,;,inte nos doi.s botões

public void actionPerformed (ActionEvent event) { if (event . getSource ( ) c o lorButton ) frame .repaint() ; cIse { labelo s etText ( "Tha t 's hurt I " ) ;

~C~~~~~2

·:;r tS b0tão -=- ~~;.~ ()~ou .... c q'"JJl:: faze.r ..

o obj&tc és evento parE ciescobrir ? <..!s~ ;"550 pêra decidi r

Falha: isso funcionará, mas na maioria dos casos não é boa prática de 0 0 . Um man ipulador de eventos fazendo muitas coi sas diferentes significa que você tera um único método executando essas tarefas. Se precisar alterar como uma origem é mani pulada , terá que -. mexer com o manipulador de todos os eventos. Às vezes é uma boa solução, mas geraimenie afeia a manutenção e a extensibilidade.

264

--~-

usando

A
A

Como capturar os eventos da ação de dois botões distintos, se cada botão tem que fazer algo diferente?

A

® opção

três: Crie duas classes AcíionUstener separadas.

"""

I'

class MyGu i ( JFrame frame ; JLabel label ; void gui () ( l/ código que instancia os dois ouv intes e registra um l/ no botão da cor e o outro no botão do rótulo l/ fecha class

class ColorButtonLi s tener implement s ActionL is ten er public void acti onPer for med (ActionEven t e vent) ( frame . rep ai nt() ;

ivãc func.lona Z'aJ Essa cl as se .não tem wna referância à variave l 'frame r da
c~asse

M!J'Gui

class Labe lButtonListener implemen t s ActionL is t e ner public void actionPerformed(Ac ti onEvent eve nt) { label osetText ("That hur t !"); ~< ~

_________

Problema; Essa
=efar·§ncia. da

c:ass~

ndO tem
~ label

va=ié~Tel

'

Falha: essas classes não terão acesso às variáveis sobre as quais precisam atuar, 'frame' e 'Iabel'. Você poderia corrigir isso, mas teria que fornecer a cada uma das classes de ouvinte uma referência da classe principal de GUI , para que dentro dos métodos actionPerformedO o ouvinte pudesse usar a referência dessa classe e acessar suas va riáve is. Mas isso seria abandonar o encapsulamento, portanto, provavelmente teríamos que criar métodos de captu ra dos elementos gráficos da GUI [getFrameO , getLabelO , etc.]. E você poderia ter que ad icionar um construtor à classe do ouvinte para poder passar a referência da GUI para o ouvin te na hora em que ele fosse instanciado. E, bem, fica ria mais confuso e complicado.

Tem que haver uma maneira melhor!
Não seria maravilhoso se pudesse ter duas classes de ouvinte diferentes, mas elas pudessem acessar as variáveis de instância da classe principal de GUI, quase como se as classes de ouvinte pertencessem a outra classe. Assim você teria o melhor dos dois mundos. Sim , isso seria um sonho. Mas é apenas ilusão ...

h

I

265

classes -

~.

A classe interna vem nos socorrer!
Você pode ter uma classe aninhada dentro de outra. É fácil. Basta certificar-se de que a definição da classe interna esteja dentro das chaves ela classe externa.

A instância de uma classe interna deve ser vinculada a uma instância da ciasse externa*.
Lembre-se de que quand o falamos de uma classe interna acessando algo da classe externa, na verdade estamos falando ele uma instância ela classe interna acessanelo algo em uma instância ela classe externa. Mas que instância? Qualquer instância da classe interna pode acessar os métodos e variáveis de qualquer instância da classe externa? Não!

Classe interna simples:
class MyOuterClass
class MylnnerClass { void go(l t. .

Um objeto interno deve ser vinculado a um objelo externo espec(fico no heap.

A cl~ss$ interna é totalmente i.oseride: na class E extêrna

, ",

A classe interna recebe permissão especial para usar qualquer coisa da classe externa. Até mesmo o que for privado. E ela pode usar essas variáveis e métoelos privados ela classe externa como se as variáveis e os membros tivessem sido definidos na classe interna. É isso que é tão útil nas classes internas - elas apresentam a maioria das vantagens de uma classe comum, mas com direitos de acesso especiais.

Classe interna usando uma variável da classe externa
class MyOuterClass private int x;
c lass MylnnerClass vo id g o () { x =4 2; (~----------l /fecha a classe interna

usa "x" come S6
fosse uma

Um objeto intemQ. . . . . compartilhará de um~'IIIIIIIIIIIW ligação especial com um objeto externo.

varúhrel da cla.t!tse
----

il'2ternel

(!)cr i e uma instância da classe exte rna.

) l/ fech a a classe externa

~cri e uma inst ânc ia da
classe in terna , usando a instânc ia da classe
ext erna.

~ AgOra os ob j et o s exter n o e i nterno e stão intimamente ligados .

,.,.. :~~

...

~ Ui'

'.)ma

e>:rec1!.f'
dI2 1~ tr,=,

éI(!Ul.

p'lr",

1)1',

r·r1<.; ' ....

IIl\!i I ()

,:,'s!v·'r-j;)]
n~r.

-

IHOn

r-J ",:;~(:.. iJlt:",~ rna
j~~;x,
.Jlfld

c1c;f';' r:!.id.:.:.
pi:::l:;S~H
:

':1-:-

')TT

m"" ~ í.d",
USi::I!1rj Q

<=>"".,... ,'t r;,,-·r.
JaV':1

t'~;:;IC;

v","r,"m')i"
<.1 r

..,. vuco?
t..:ld!::;St'

IJ(,dE.ú€:ssa s .

od6. a

zuc

Virlé

sem nunça ~ nC(,nLl

266

usando

Como criar a instância de uma classe interna
x

--'
i

... '

,

Se você instanciar uma classe interna a partir de um código que estiver dentro de uma c lasse externa, a instància da classe externa ~ení aquela a qual o obj eto interno se 'vincu lará' , Po r exemplo, se o código dentro de um método instanciar a classe interna, o objeto interno se vinculará ü instância cujo método estiver se ndo executado, O código de uma classe externa pode instanciar uma de suas próprias c lasses internas , exatamente da mesma fo rma q ue instanciaria qualquer o utra c lasse ... new Mylnner( ). class MyOuter

~,

~1

." \-::-:-1 ::.;.

~

'outer'

MyOuter

---l

..,
private int x;
<~--------

-_.--

Mylnner inner = new Mylnner ( ); publi c void doStu ff() inner . go() ;

d._ _ __

ã
k t;

\outer

Chama um met:odo .na class,e

,
•.

MyOuter

class Mylnner ( vo id go( ) { ( --------------------x = 42

o
: _~ se

_método da classe

i~tgr~a

~x'

da classe 'S.rrt ernar como per~sncêssa à c!aS3e

ã::.; I :;
\if
Mylnner nner

Ilfecha a classe interna Il fecha a classe externa

interna.

":..J

Nota lateral
Você pode criar uma instância interna a partir de um código sendo executado fora da classe externa, mas terá que usar uma sintaxe especial. É provável que você passe sua vida inteira usando Java e nunca precise criar uma classe interna a partir do amb iente externo, mas caso esteja interessado .,.
c l ass Foo { public static void main (St ring[] args) ( MyOuter outerObj = new MyOuter(); MyOuter . Mylnner innerObj = outerObj.new Mylnner();

~. ,€:-

Agora podemos fazer o código com dois botões funcionar
public class TwoButtons JFrame frame; JLabel label; public static void main )String[] args) TwoButtons gui = new TwoButtons(); gui . go () ;
Ch.U191!.
ta~!

a classe pri~cipal da GUI não implementa ActionListener agora

public void go () ( frame = new JFrame (); frame . s etDefa ult CloseOp eration (JFrame .EXIT_ON_CLOSE) ; JButton labelButton
=

labelButton.adQ~ctionListener(new

new JButton("Change Label"); LabelListener());
·i..=
~'9gi3::;=-'":

ia

O~.1v.z.:--t,,=,,;;,
.;

d:;
-~.a

JBu tton colorButton = new JButton ( "Change Circle"); colorButton . addActionListener(new ColorListener()); label = new JLabel("I'm a label"); MyDrawPanel drawPanel = ne'''' 11yDrawPanel ( ) ;
I

.... .. s~""J. '.:.=e

':~ ':;-~"3.

g;

cio:::; ... _

~

IIIIIIIL _

r--,

i

267

classes '
frame f rame frame frame . getContentPane() . getContentPane () . g etContentPane( ) . getContentPane () . add(BorderLayout . SOUTH, colorBu tton) ; . add (Bo rderLayout . CENTER, drawpanel) ; .add (BOrde rLayout . EAST, labelButton) ; . add (BorderLayout . IrJEST, l abel) ;

frame . setSize ( 300,30 0) ; frame . setVisible ( true) ;

"""'.","-,~jI!:

obJS'to

Col.Dr~is:t€ne:r

c l as s La bel Li stene r imp l ements Acti o nListener ( ~ publi c vo id a ctionPe rf ormed(Act ionEvent event) ( .~ ) label osetTex t ( " Ouch ''' ) ; ~

«

a

class~

interna sabe da
\ lé.-bel,'

'>

exi.sténcia de

l / f e cha classe lnt e rna 'classCoÍorLis-tener imp.lements ActiónLis-tener p u b lic void actionPerf o rme d (ActionEvent even t) frame.repaint( ) ; ( -----------------------------------------l/f echa classe i n terna

Agora podemos t-er DOIS
Action1d}~:te].1 ers

na mesma

classed
a classe interne pode usar a ve.riável de instância , Írame ~ sa-n ter uma
I

~eferência

e~~lícíta c~asse

do

objeto da

externa

Tudo sobre o Java
Entrevista desta semana: --Instância de uma classe interna
Use a Cabeça!: O que torna as classes internas importantes? Objeto interno: Por onde começo? Nós possibilitamos a implementação da mesma interface mais de uma vez em uma classe. Lembre-se de que você não pode implementar um método mais de uma vez em uma classe Java comum. Mas com o uso de classes internas, cada classe interna pode implementar a mesma interface, portanto, você poderá ter todas essas implementações diferentes dos mesmos métodos da interface. Use .a Cabeça!: Por que você poderia querer implementar o mesmo método duas vezes? Objeto interno: Voltemos aos manipuladores de eventos de GUI. Pense nisso ... Se você tiver três botões e quiser que cada um tenha o comportamento de um evento diferente, use três classes internas, todas implementando ActionLi stener -- o que significa que cada classe pode implementar seu próprio método actionPerformed. Use a Cabeça!: Então os manipuladores de evento não são a única razão para o uso de classes internas') Objeto interno: Oh, lógico que não . Os manipuladores de evento são apenas um exemplo óbvio. Sempre que você precisar de uma classe separada e ainda quiser que essa classe se comporte como se fi zesse parte de outra classe uma classe interna será a melhor - e às vezes a única maneira de fazer isso. Use a Cabeça!: Ainda estou confuso aqui. Se você ljuer que a classe interna se comporte como se pertencesse à classe externa, por que ter uma classe separada? Por que o código da classe in terna não poderi a simplesmen te estar na classe ex te rna ') Objeto interno: Eu só lhe mostrei um cenári o, em que você estaria precisando de mais de uma implementação de uma interface. Mas mesmo quando você não estiver usando interfaces, pode precisar de duas classes diferentes. porque essas classes representariam duas coisas distintas. Trata-se de uma boa prática de 00. Use a Cabeça!: Opa. Espere aí. Eu achava que grande parte do projeto de 00 tivesse a ver com reutilização e manutenção. Você sabe como é, a idéia de que, se houver duas classes separadas, elas poderão ser alteradas e usadas independentemente, e não ter tudo inserido em uma classe etc. Mas com uma classe interna, no final das contas você ainda estará trabalhando com uma classe real, certo? A classe externa será a única que poderá ser reutilizada e separada de todo o resto. As classes internas não são exatamente reutilizáveis. Na . verdade, ouvi falar que são "Re-inutilizáveis - repetidamente inúteis". Objeto interno: Sim é verdade que a classe interna não é tão reutilizáveL de fato às vezes não é nem um pouco reutili zável , porque está intimamente ligada às variáveis de instância e métodos da classe externa. Mas Use a Cabeça!: - o que só comprova meu ponto de vista! Se elas não são reutilizáveis, por que se preocupar com uma classe separada? Quero dizer, exceto no que di z respeito ao problema da interface, que para mim soa como um paliativo. Objeto interno: Como eu estava dizendo. você precisa . considerar o teste É-Um e o polimorfismo . Use a Cabeça!: Certo. E eu os estou con siderando porque ... Obj eto interno: Porque as classes ex terna e interna podem ter que passar em testes É-UM dflerentes ! Com ecemos com o exemplo do ou vin Le de G Ui polim órfico. Q ue tipo ue

." .

.)tlI

.-ª!
'.~

268

4'" ;:t~.

lisanclo

~.

.--t
,-t,

argumento é declarauo para II métouo de registro de ouv intes do botão'l Em outras palavras. se você fo r até (1 APl e pesquisar. que tipo de coisa (tipo de classe o u interface) você tem que passar para o método addActionLi stener() ? Use a Cabeça!: Você tem que passar um ouvinte. Algo 4Ut' implemente uma interface de escuta específica, nesse caso ActionListener. Sim, sabemos de tuuo isso_Onde quer chegar? Objeto interno: Quero mostrar que, polimorficamente. você tem um método que usará apenas um tipo específico. A lgo que passe no teste É-UM de ActionLi stener. Mas - e esse é o ponto principal - e se sua classe tiver que fazer parte do teste É-UM de algo que tenha como tipo uma classe em vez de uma interface? Use a Cabeça!: Você não faria sua classe estender a classe da qual precisa fazer parte? Não é assim que as subclasses funcionam? Se B for uma subclasse de A, então, em qualquer local que A for esperada, B poderá ser usada. O velho ' passe um objeto Dog onde Animal for o tipo declarado' . Objeto interno: Sim! Bingo!-Então o que aconteceria agora se você precisasse passar no teste É-UM de duas classes diferentes ? Classes que não sejam da mesma hierarquia de herança? Use a Cabeça!: Oh, bem você teria apenas que ... Hummm. Acho que estou entendendo. Você sempre poderá implementar mais de uma interface. mas só poderá estender uma classe. Você só poderá passar em um tipo de teste ÉUM quando se tratar de classes. Objeto interno: Exatamente! Sim, você não pqde ser um objeto Dog e um objeto Button ao mesmo tempo. Mas se for um objeto Dog que às vezes precise ser um objeto Button (para poder ser passado para métodos que usem um objeto Button), a classe Dog (que estende Animal, logo, não pode estender Button) pode ter uma classe interna que aja em nome do objeto Dog como um objeto Button, ao estender Button e, portanto, sempre que um objeto Button for necessário o objeto Dog poderá passar seu objeto Button interno em vez dele próprio. Em outras palavras, em vez de usar x.takeButton(this) , o objeto Dog chamará x.takeButton [new MyInnerButtonOl. Use a Cabeça!: Pode citar um exemplo claro? Objeto interno: Lembra-se do painel de desenho que usamos , quando criamos nossa própria subclasse de lPanel? Nesse exato momento, essa classe é uma classe não-interna separada. E isso é bom, porque a classe não precisa de acesso especial às variávei s de instancia da classe principal de GUI. Mas e se precisasse? E se esti véssemos criando uma animação nesse painel e ela capturasse suas coordenadas no aplicativo principal (digamos, com base em algo que o usuário fizesse e m algum local da GUI). Nesse caso, se transformarmos () painel de desenho em uma classe interna, ela poderá ser uma subclasse de lPanel, enquanto a classe externa continuan'í não sendo a subclasse de nenhuma outra c lasse. Use a Cabeça!: Sim, entendi! E de qualquer for;:;la o paineCde desenho não é suficiente mente reutili zável para ser uma classe

separada, já CJue na veruade uesse ap li cativo de OU!.

ü

que e le üesellÍ1af

~e rú

específico

Ob.ieto interno: S im ' Você e nte ndeu' Use a Cabeça!: Bom. Então podemos passar para a natureza do relacionamento e ntre você e a instância exte rna. Objeto interno: O q ue hú de e rrado com vocês? Essa não é uma fofoca só rdida demais para um tópico sério como o polimorfismo? Use a Cabeça! : Ei, você não te m idéia de quanto o público paga por um bom tablóide cheio de fofocas. Então quer dizer que alguém cria você e se torna instantaneamente ligado ao objeto externo. é verdade ? Objeto interno: Sim é verdade. E sim, algumas pessoas comparam isso a um casamento arranjado. Não podemos opinar sobre o objeto ao qual seremos ligados. Use a Cabeça!: Certo , usarei a analogia do casamento. Você pode se divorciar e casar novamente com um elemento diferente? Objeto interno: Não, é para a vida toda. Use a Cabeça!: A vida de quem? Sua? Do objeto externo? As duas ? Objeto interno: Minha. Não posso ser ligado a qualquer outro objeto externo. Minha única saída é a coleta de lixo. Use a Cabeça!: E quanto ao objeto externo? Ele pode ser associado a algum outro objeto interno? Objeto interno: Agora entendi. É isso que você queria. Sim, sim. Meu suposto ' companheiro' pode ter quantos objetos internos quiser. Use a Cabeça!: Selia como uma monogamia serial ? Ou ele pode ter todos ao mesmo tempo? Objeto interno: Todos ao mesmo tempo. Aí está. Satisfeito? Use a Cabeça!: Bem, faz sentido. E não esqueçamos, foi você que exaltou as virtudes de se ter "várias implementações da mesma interface" . Mas faz sentido uma classe externa com três botões precisar de três classes internas diferentes (e, portanto, de três objetos de classes internas diferentes) para manipular os eventos. Obrigado por tudo. Tome um lenço.

"

i

......
í-' ,

269

Usando uma classe interna em animação
Vimos por que as classes intern as são úteis em ou vintes de e vento s~ já que você poderá implementar o mesmo método de manipul ação de eventos mais de um a vez. Mas agora exam inaremos como uma classe interna pode ser útil quando usada como um a subclasse de algo que a classe externa não estend a. Em outras palavras, quando a classe interna e a classe extern a estão em árvores de herança diferentes ! Nosso obj eti vo é criar uma animação simples, em que o círcu lo se mova através da tela do canto superior esquerdo para o canto inferi or direito .

Não e xistem

Por que esta mos aprendendo animação aqui? Duvido que eu tenha que cria r jogos. Você pode não ter que criar jogos, mas talvez ten ha que criar simulações, em que as coisas mudem com o tempo para mostrar os resultados de um processo. Ou pode ter que construir uma ferramenta de visualização que , por exemplo, atualize um gráfico para mostrar a quantidade de memória que um programa está usando ou para que você sa iba o volume de tráfego que está sendo receb ido através de seu servidor de balanceamento de carga. Qualquer coisa que precise usar um conjunto de números em alteração constante e os converta em algo útil para a obtenção de informações. Isso tudo não soa empresarial? É claro que essa é apenas a "justificativa oficial ". A verdadeira razão para estarmos abordando isso aqu i é somente porque é uma maneira simples de demonstrar outra utilidade das classes internas. (E simplesmente porque gostamos de animação, mas nosso próximo livro da série Head First é sobre a J2EE e sabemos que não poderemos falar sobre animação nele.)
~~-,

P:

R:

. ~"

iní ci o

fi m

Veja como é simples o funcionamento da animação

C!)

Desenhe um objeto em uma coordena da x e y e spe c í fic a g . fill Oval( 20, 50,l OO, lO O) ;
~

20 p:l xeL s a parr::tr da:. esqueráa ,

50

pí.Jte~s

e p.e.rti z' 0.0 t.opo

~ Rede s e nhe o obj eto em uma coordenada x e y d i f e r ente
g . fillOval(25,55,lOO,lOO ) ;
~-'

do topo ( o Obj fBto se moveu um pouco para bi5.::',ro e pera a éireica)

~ Repita a etapa a nt eri or com valo r e s a l t erados para x e y e nquant o a anima ção t ive r que c ontinu ar.

o que queremos realmente é
como ...

algo

, "'~ , Aponte seu lápis

"

Mas onde obterei as novas coordenadas x e y? E quem chamará repaint( )?
class MyDrawPanel estends Jpanel ( public void paintComponent(Graphics g ) ( g . setColor(Colo r . orange ) ; g . fill Oval(x,y, lOO,lOO) ;
II /'r-.
II

,I
\(
í

Vej a se consegue proj etar uma s olução s imples que faç a a bo la ficar ani mada do canto superior esquerdo do painel de de senho até o canto inferior direito . Nossa resposta está na próxima página, portanto, não vire essa página até ter acabado ' Dic a importante : faça com que o painel de desenho seja uma classe interna . Ou tra dica: não insira nenhum tip'o de loop de repetição no método pa i ntCompon ent() . Escreva suas idéias (ou o código ) aqui:

qJ.-e pé:..:..nt ~:;:lPQ:'1eI.rt () :fc~ .::!:?"ma:.I...lt". e fO ....~:...TJ.2 O"iF ,& 2. $0(:-:::2 ~:é"S~,!""",""i.;~aa. êm Ul'1 .i..~Cé..;: d~fe.rez:ce

Sem~.'l'$

270

usando

o código

simples da animação concl uido

import javax . swing . · · import java . awt . ·';

public cla ss SimpleAnimation (

int x int y

70; · ~~~__________________________________________________ 70; "

Y

do c:.rcli":'o

public static vo i d main (String(] args) SimpleAnimation gui = new SimpleAnimation(); gui . go () ;

public void go() JFrame frame

=

new J Frame ();

frame .se tDefaultCloseOperation(JFrame . EXIT_ ON_CLOSE) ;
Nada ãe nevo aqu.i... Cria os alemencos

MyDrawPanel drawPanel

new MyDrawPane l ();

g=aficos e os

i~sere

na

mo:du~a.

fr ame . getContentPane() . add(drawP ane l); frame.setSize (300,300); frame . setVisible(true);

for (int i

o; i

< 130;

i++) 1

~------

Repete isso

~30

vez~s.

x++;

y++ ;

Incrementa as coordenadas x e

y~

drawpanel. repa·int ();

( :.------:.--------------- - -

Solicita ao painel que se radefina (paz3 que possamos ver o círculo no novo 1ocal).

try { Thread.sleep(SO ) ; (~-~~-~----------------­ ) catch(Exception ex ) f

Retarda um pouco o círcu l o

(caso

contr~Tic

ele se movímentará tão rapidamente que você não o VER~ se mover)~ Não se
preocupes você não ara obrigado a saber disso. Abordaremos os segmentos no

r
} l/ fecha o método go()

capítulo 1.5.

class MyDrawPanel e xtends JPa nel {

(------~---------

Agora

~

~~a

classe

inéerna~

public vo id paintComponent(Grap h ics g) g .s etColor(Color .g reen) ; g .fi llOval(x,y,4 0 ,40 ) ;

Usa a.s ccord-enadas . e y CO::.t:_i21Ud.:'7l8nt_s x atualiziidas da. clas.se extez;na ..

} l/fecha a classe interna l/fecha a clas s e exte r na

271

animação com

o uso de urna classe interna

Humm. Ele não se moveu ... Gerou um borrão.

o que deu errado?

----~~- ~

Há uma pequena falha no método paintComponentO· Não é exatamente a aparência que queríamos.

Esquecemos de apagar o que já existia! Portanto, exibimos trilhas.
Para conigir isso, tudo que temos que fazer é preencher o painel inteiro com a cor do plano de fundo, antes de cada vez que desenharmos o círculo. O código a seguir adiciona duas linhas no início do método: uma para a configuração da cor com branco (a cor do plano de fundo do painel de desenho) e a outra para o preenchimento do retângulo inteiro do painel com essa cor. Em português, o código está dizendo "Preencha um retângulo começando em x e y = O (O pixels a partir da esquerda e O pixels a partir do topo) e torne-o tão largo e alto quanto o painel é atualmente".
public void paintComponent(Graphics g) { g.setColor(Color .white) ; g. fillRec t (O, O, this. getWidth (), this. getHeight () );

getf<Jidth getHeight <E:' ------ herdados () e JPanel. () Cle

são métoclos-

g.setColor(Color.green); g.fillOval(x,y,40,40);

Aponte seu lápis (opcional, só por diversão)

Que alterações você faria nas coordenadas x e y para produzir as animações abaixo (presuma que o primeiro exemplo se move em incrementos de 3 pixels)?

1

2

l:J D DO
início fim início fim início fim

X -±.L Y -±.L X

1

2
Y X
3

3

DD

y

D D DD -/ D
início fim início fim

X y

X Y X y

I

início

fim

272

usando

Receita de código

J

batida um

batida dois

batida três

batida quatro

~:-

Criaremos um vídeo musical. Usaremos figuras aleatórias geradas pela Java que estarão sincronizadas com as batidas musicais. No percurso registraremos (e escutaremos) um novo tipo de evento não referente à GUI, acionado pela própria música.
Lembre-se de que essa parte é toda opcional. Mas achamos que ela lhe fara bem. E
você gostará. E poderá usá-la para impressionar as
pessoas ~

(Certo,
mesmo

talvez só funcione com pessoas
)

real~ente

fáceis de impressionar, mas

a~si1l1 •••

Escutando um evento não referente à GUI
Certo, talvez não seja um vídeo musical, mas criaremos um programa que desenhará figuras aleatórias na tela conforme a batida da música. Resumindo, o programa escutará a batida da música e desenhará um retângulo aleatório a cada batida. Isso nos apresenta algumas questões novas. Até aqui, escutamos somente eventos de GUI, mas agora precisamos escutar um tipo específico de evento MIDI. Na verdade, escutar eventos não referentes à GUI é como escutar eventos de GUI: você implementará uma interface de escuta, registrará o ouvinte em uma origem de evento e, em seguida, sentará esperando que a origem chame seu método manipulador de evento (o método definido na interface de escuta). A maneira mais simples de escutar a batida da música seria regi strar e escutar os eventos MIDI reais , para que sempre que o següenciador capturar o evento. nosso código também o capture e possa desenhar a figura. Mas ... Há um problema. Ümerro, na verdade, que não nos permitirá escutar os eventos II/IIDI que gerarmos (o~ de NOTE ON) . Portanto, precisamos de um paliativo. Há outro tipo de evento MIDI que podemos escutar, chamado ControllerEvent. Nossa solução é nos registrarmos para escutar ControllerEvents e, em seguida, nos certificarmos de que, para cada evento NOTE ON, um ControllerEvent correspondente seja acionado na mesma .'batida' . Como podemos nos certificar de que o ControllerEvent será acionado ao mesmo tempo? Ele será adicionado à faixa da mesma forma que os outros eventos' Em outras palavras, nossa seqüência musical será a seguinte: BATIDA 1 - NOTE ON, CONTROLLER EVENT BATIDA 2 - NOTE OFF BATIDA 3 - NOTE ON, CONTROLLER EVENT BATIDA 4 - NOTE OFF e assim por diante. Antes de nos aprofundarmos no programa completo, no éntanto,to rnemos um pouco mais fácií criar e aàiciunar mensagens/eventos MIDl já que nesse programa, çriaremos vários deles.

273

método utilitário para eventos

Uma maneira mais fáci l de criar mensagens/
- C;VCIILO";:'

_ .. ,. -_4-"C!'

o

que o programa de arte musical precisa fazer:

®

criar uma série de mensagens / e v ent o s MID I para repr oduzir notas a l eatórias em u m pi ano (ou o i n stru me nt o q ue você escolher) .

~ Re g istrar um ouvin t e p a r a o s even t os . ~ I ni c ia r a e xe cução do seqüenciado r.
~ Semp re que o método manipulado r de
e v en t os d o ouv i nt e f o r chamado, de s enha r um r etângulo aleatór io no p aine l de des e nho e chamar repaint .

Nesse exato momento. criar e adicionar mensagen s e eventos a uma faixa é tedioso. Para cada mensagem , temos qu e cri ar a instância da men sagem (nesse caso, ShortMessage) , chamar setMessageO, criar um MidiEvent para a mensagem e adicionar o evento à faixa . No código do último capítulo, percouemos cad a etapa necessária à criação de qualquer men sagem. Isso significa oi to linh as de código apenas para fazer uma nota ser reprodu zida e em seguida inten'omperm os a reprodução ! Qu atro linhas para adicionar um evento NOTE ON e quatro para adicionar um evento NOTE OFF.
ShortMessage a = new Sho rtMes s age () ; a. s e tMessage(144, 1, note, 10 0) ; Midi Event noteOn = new MidiEve nt (a , 1 ) ; track . add (noteOn ) ;

Ele será construído em três etapas:
~ Versão Um: código que s i mp li f i c a a
criação e a diç ão d e e v e nto s MIDI, que c ri aremos vári os d e les. já

Sho r tMes s age b = new ShortM essage () ; b. se t Mes sa g e ( 1 2 8, 1 , note, 100); MidiEv ent n ot eOff = new MidiEv ent (b , 16 ) track . add (noteOff ) ;

Coisas que têm que ocorrer para cada evento:

~

Ve rsão Dois : reg i st r a e escuta os eve ntos, mas sem f i gura s . Exibe uma mens agem n a linha d e coma ndo a cada b a tida . Versão Três : o aplic a ti vo fina l. Adi ciona as figuras à v e rsão dois .

C!)

Crie uma instância da mensagem. Sho r t Message first = new Sho rtMes s a g e () ; Chame setMessage() com as instruções. first . setMe s sage ( 192, 1, i n s t rume nt, O)

~

®

~ Crie uma instância de MidiEvent para a mensagem.
Mi di Event noteOn

=

new MidiEvent ( first,l ) ;

(i) Adicione

o evento à faixa.

Construiremos um método utilitário estático que cria uma mensagem e retorn a um MidiEvent
o evento
QUAA~

~tick' para essa mensagem tiver que ocorrer

Os quatro
/ ,.,

ar~~entos

da mensagem.

~~- ------~-- ,,/- '-", -'--"-~--- --"pub l i c stati c MidiEvent ma.keEvent ( int comd , int chan , int one, int t wo, i n t t i ck)
Midi Even t event try { ShortMessage a = new ShortMessage () ; ~ a . s etMessage (comd , chan, even t n e w Mi di Even t(a, one , t wo) ; tick) ; )\
parâ~etros

1

{

=

null;
uau !

Um ll'letodo com ci.nco parâmetros,

Cria a mensagem € o eV$~tc, do método.

)" cat c h(Bxcept i oJl e) retu r n event;
~------------

com a

mensage~)~

274

capitulo 12

usando :;, 1--::

Exemplo: como usar o novo método estático makeEvent( )
Não há manipulação de eventos o u figuras aqui, apenas uma seq üênc ia de 15 notas asce ndentes na escala. O objetivo desse código é sim plesmente ensinar como usar nosso novo método makeEvent(). O código das d uas próximas versões ficar:í muito menor e mai s ~ imple s graças a esse método.
import j a v ax . s o und. midi . 'k
;

(---------------------------( args)

não e s qu e ça a imp crca qao

public class MiniMu s icPIaye r1

pubIic static void main(String[J try Sequencer sequencer sequencer . open ( );

MidiSystem . getSequencer();

( -------------- cria ( e abre) um seQÜenciador

Sequence seq = new Sequence (Sequence . PPQ, 4) ; ~---------------­ c r ia uma seQÜência Track track = seq . createTrack(); ( ---------------------------- e uma faixa for (i nt i = 5; i < 61; i+ = 4) cria vários event os para fazer
as notas ascenderem (notas 5 a 61 do piaIlO)

track . add(makeEvent(144,1,i ,lOO ,i) ) ; erack.add(makeEvent(128,1,i,lOO,i + 2)); l/ fim do Ioop

(-------- - ----

chama nosso novo método makeEvent () para criar a mens agem e o evento a , em seguida, adiciona o resultado (o MidiEvent retornado por make~rent ( » à faixa , São pares
NOTE ON (14 4 ) e NOTE OFF (12 8 )

sequence r.setSequence ( seq ) ; ?(-------------------- ínicia a execução sequencer.setTempolnBPM (220) ; ) sequencer . start() ; catch (Exception ex) (ex.printStackT race() ; } l/ fecha main

~

pubIic stati c MidiEvent makeEvent ( int comd, MidiEvent event null; try ( ShortMessage a = new ShortMessage(); a .se tMessage(comd, chan, one, two) ; event = new MidiEvent(a, t ick ); catch(Except i on e ) return event; l/ fecha class ( )

int chan,

int one,

int two,

int tick )

·A
À

Versão Dois: registrando e capturando ControllerEvents
import javax . sound.midi.*; pubIic cIass MiniMusicPlayer2 i mplements ControlerEventListener ( pubIic static vo id main(String[) args ) MiniMusicPIayer2 mi ni = new MiniMusicPIayer2(); mini . go () ; public void go () try ( Sequencer sequencer s e quencer. o pen() ;
Precisamos escutar os
~< ~---

Control 1 erEvents , portanto , ímplementa~os a int erface de
escuta.

MidiSystem.getSequencer() ;

Regist ra eventos no

,-....

I

seQÜenciaãor. O mé·tod o d e
d _ _ __
'-

int [J eventsII,'lant = (127) ;- -::-:--:-----,-=;::-7.,------..,....-, seque~ce; . addControll';;-rEventListene-r (this, eventsIWant) ; Sequence seq = new Sequen ce(Sequence.P PQ, Tr a ck t rac k = seq . createTrack() ; 4);

registro de event o s usar á o ouvinte E wna matriz in t representando e 1~sca ae Contro llerEvents que você qui ser ~ Queremos soment: e ü.m e ven co , #127.

você esta aqui

275

eventos ce ·'c.)

:c'a:::u
i < 60; i+= 4)
Vêja como iãentifícS1IlC'S a ba.tida. -' inssrimos _._3~P-=:~,"=" P:~ÓPRJ.(,; C:Jnt:ro~ l€z:E'tren:: \176 significo.
~Je

f or

( in t- i = 5;

c

even~o

óo tipo

Co~c=o:lerEvent}
é

com um
1.27 ~

t-rack . add(makeEvent(176,1,127,0,i) ) ;

~----

arg-.une.t! co
Es s~E:

pEt.J..""&

o número do e1'ento que

e \~'ent o
~~ n~ta

não t ará. fvP:IJA! I-Jó:::;; o ínserimos

track.add(makeEvent(128,1,i , 100,i + 2)) ; I! fim do loop sequencer . setSequence(seq) ; sequencer . setTempolnBPM(220) ; sequencer.satrt(); ca tch (Excep t ion ex) {ex .printStackTrace();} l/ fecha

lJJ?E1u"J'!..S para podermos capturar UJli; e:ren~o sempre

ror reproãuziàa~ Em outras sua úní ca fínaliàade é ~~e ~lgo ~Je possamos escutar seja a cionaão (nâo podemos
~~e

pa~avrasf

escutar eventos lxro'rE ONJOF.'F) " Ob s er'fre que esta...'TIOS fazendo esse evento ocorrer no l.SESf>1.0 momento de NOTE ON. PortanL0 quando o evento NOTE O!.J ocorrer, sa.beremos disso porq'..le l.\fOSSO evento será acionado ao mes.mo tempo ..
1

o :método manipulador
publi-c void controlChange (ShortM.essage event) 8ystem.-Out.println("la") ;
}

de

eventos (da interface de escuta ControllerEvent).
Sempre que capturarmos o
even t o.. exibir€!J.7los

nla"

na

public MidiEvent makeEvent(int comd, int chan, M.idiEvent e v ent null ; try ( ShortMessage a = new ShortMessage(); a:setMess a ge(comd, c han , one, two) ; event = new Midi Event(a, t ick ); catch (Exception e) return e vent; l/ fecha class { }

int one,

int two,

int tick)

lil'..1J.a de comando .

Trechos diferentes da versão anterior foram realçados em cinza. (E não estamos executando o código todo dentro de main() dessa vez.)

Versão Três: desenhando figuras sincronizadas com a música
Essa versão final continua o desenvolvimento da versão dois ao adi cionar as partes de GUL Construiremos uma moldura, adicionaremos um painel de desenho a ela e, sempre que capturarmos um evento, desenharemos um novo retângulo e redefiniremos a tela. A única diferença da versão dois é que as notas serão reproduzidas aleatorj,m1ente e não simplesmente ascendendo a escala. A alteração mais importante no código (além da construção de uma GUI simples) é que faremos o painel de desenho implementar o ControllerEventListener em vez do próprio programa. Portanto, quando o painel de desenho (uma classe interna) capturar o evento, ele saberá o que fazer e desenhará o retângulo. O código completo dessa versão está na próxima página.
o
painel de desenbo é
~~

A classe interna do painel de desenho:

ouvinte~

Configuramos um fl ag com fal so e só o config'.lraremos com v" erdadeiro c1ass MyDrawPanel extends Jpane l implements ControlerEventListener boolean ~Sg = false; ~-----------------------­ . quando capturarmos um €1l"ento. public void controlChange (ShortMessage events) Capturamos um evento, portanto~ msg = tru e; ~(ii!~-_._-----,-----------------­ ' configuramos o 1:18.g com. repaint () ; ~-'-------------------------------------------- verdadeíro e chamamos repaínt{).

pub1ic void paintComponent(Graphics g) if (msg ) { ~(--------------------------------------------­ Graphics2D g2 = (Graphics2D) g ; int r = (in t) (Math.random() * 250); int gr = (int) (Math .random() * 250) ; i nt b = (int) (Mat h . random( ) * 250 ) ; g. setColor (new Color(r,gr,b)) ; int. ht .= (int) ((Math . random() * 120) + 10) ; int width = ( int) (( MathRandom() * 120) + 1 0); int x = (int ) (( MathRandom() * 40 ) + 10 ); int y = (int) (( MathRandom () * 40 ) + 10); g .f illRect(x,y,ht, wi d th); msg = fa lse ; Il fe cha if l/fe cha o mét odo l/ fecha a classe interna

Temos que usar um flag porque
OtTTP_ll coi.sa pode e.cionar um método repe.i.nt- () e SÓ queremos aesen..'u1r quando bau'ver um

ControllerEvent.

o .resto é o c0cigo da. 9'eração de
t:\m2 cor aleetéz"i Ci; e de d~senh o

de um retbngulo

s~~d-aleet6rior

276

;""'.')

s i

usando ; ;

Essa é a li stagem completa do código da Versão Três. Ele foi desenvolvido diretamente a partir da Versão Dois. Tente coment<Í- lo você mesmo, sem olhar as p<Íginas anteriores.

import import import import

javax.sound.midi.*; java.io.*; javax.swing.* java.awt . *;

public class MiniMusicPlayer3 static JFrame f = new JFrame ("My First Music Video"); static MyDrawPanel ml; public static void main(String[] args) MiniMus i cPlayer3 mini = new MiniMusicPlayer3(); mini. go () ; l/ fecha o método public void setUpGui() ml = new MyDrawPanel(); f .set Cont entPane (ml); f.setBounds(30,30,300,300); f . setVisible(true) ; ) l/ fecha o método public void go () setUpGui () ; try ( Sequencer sequencer = MidiSystem.getSequencer(); sequencer.open() ; sequencer.addControllerEventListener(ml, new int[] Sequence seq = new Sequence (Sequence. PPQ, 4); Track track = seq.createTrack(); int r = O; for (int i

(127});

O; i

< 60;

i+= 4)

r = (i nt) ((Math.random() * 50) = ! ); track . add(makeEvent(144,1,r,100,i)); track.add(makeEvent(176,1,127,0,i)); track.add(makeEvent(128,1,r,100,i + 2)); l/ fim do loop sequencer.setSequence(seq); sequencer.start(); sequencer.setTempolnBMP(120) ; catch (Exception ex) (ex . printStackTrace();} l/ fecha o método public MidiEvent makeEvent(int comd, int chan, MidiEvent event null; try ( ShortMessage a = new ShortMessage(); a . setMessage(comd, chan, one, two); event = new MidiEven t (a, tick); catch(Exception e ) { } return event; I l/ f e c ha o métod o int one, int two, int tick)

-- ---------------------------~--------------------------------

...

exercício:
class MyDrawPanel extends JPanel implements controllerEventListener = fc.lsc ; public void controlChange(ShortMessage event ) msg = true; repaint() ; (

publ i c void paintComponent(Graphics g) if (msg) ( Graphics2D g2

{

=

(Graphics2D) g;

int r = (int) (Math . random() * 250); int gr = (int) (Math . random() * 250); int b = (int) (Math . random() * 250); g . setColor(new Color(r,gr,b)); int ht = (int) ((Math .random () * 120) + 10); int wi dth = (int) ((Math .random() * 120) + 10) ; int x int y (int) (int ) ((Math . random() ((Math . random() width);

* 40) + 10); * 40) + 10);

g . fillRect(x,y,ht, msg = fa1se;

} / /fecha i f l/ fec ha o método l/ fecha a classe interna l/ fecha a classe

Candidatos desta noite:

, Exercício

Qualquer uma das personalidades elegantes deste capítulo pode participar!
Tenho a GUI inteira em minhas mãos Qualquer tipo de evento tem uma
O m étodo~chave do ouvinte

Quem

Seu e u. ?

Esse método fornece a JFrame seu tamanho Você adiciona código a esse método, mas nunca o chama

Um grupo de figurões Java, vestidos a rigor, estão participado do jogo "Quem sou eu?". Eles lhe darão uma pista e você tentará adivinhar quem são, com base no que disserem . Suponha que eles sempre dizem a verdade quando falam de si mesmos . Se por acaso disserem algo que possa ser verdadeiro para mais de um deles, seíecione todos é:H.lueies aos quais a frase possa ser aplicada. Preench a as linhas em branco próximas à frase com os nomes de um ou mais candidatos .

Quando o usuário faz realmente algo , isso se chama Em sua maioria são origens de eventos Retorno dados para o ouvinte Um método addXxxListener() informa que um objeto é uma ____________ Como um ouvi nte se registra
O método onde todos os códigos de figuras são inseridos

Norm almente estou ligado a um a instância
O .g' de (Graphics, g) na verdade pertence a uutra classe O método que faz paintComponentO ser executado

O pacote onde a maioria dos componentes do Swing reside

.

~

.~

.~

\--'

~

~.

1:'

usando

Quebra-cabeças na Piscina

Seja o compilador

o arquivo Java dessa página representa um arquivo-fonte completo. Sua tarefa é person ificar o compilador e determinar se esse arquivo será ICOme)lIaao. Se não for compilado, corno você o corrigiria , e se for compilado, o que ele fará?
import javax . swing . * ; import java.awt.event . *; import java.awt.*; class InnerButton JFrame frame ; JButton b; public static void main(String() args) { InnerButton gui = new InnerButton(); gui . go() ;

import javax . swing.*; import java . awt . *; public class ~nimate int x = 1; int y = 1; pub1ic static void main(String[j args) Animate gui = new Animate (); gui .go () ;

{

public void go(); JFrame = new JFrame() ; frame. setDefaultCloseOperation (JFrame . EXIT_ON_CLOSE) ; ___________ . getContentPane() .add(drawP); __________ .setVisible(true); for (int i = O; i < 124; __________ ) {

public void go () frame = new JFrame(); frame . setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE) ; b = new JButton ("A") ; b . addActionListener(); frame . getContentPane() .add (BorderLayout . SOUTH, b) ; frame . setSize(200,100); frame . setVisible(true) ;

try ( Thread . sleep(50) ; } catch(Exception ex)
}

{ }

class MyDrawP extends Jpane1 { public void paintComponent(Graphic

class BListener extends ActionListener public vo id actionPerformed(ActionEvent e) if (b . getText() . equals("A") b . setText ("B") ; else { b. setText ("A") ; . fillRect( X,y,x-500 ,y-250 ) . fillRect(x,y,500-x*2,250-y*2) g . fillRect(500-x k 2,250-y*2,x,y) i++ g . fillRect(O,0,250,500) i++,y++ g .EiII Rect(O,O,500,250) i++,y++,x++ x++ lmimate Erame = new .r;nimate () y++ 9 MyDrawP drawp = new MyDrawP() draw ContentPane drawP = new ContentPan€() frame drawP . paint () paneI drawP.setS ze(500,270)

- r--.

279

QUé!..:!do esse

código for

Quem sou eu?
Tenho a GUI inteira em minhas mãos Qualquer tipo de evento tem uma

irnport javax.swing . *; import java . awt . event . *; import java.awt . *;

corrígido; el.e criará uma GUI.
com
q'Je tL'tI

botão

JFrame interface de escuta actionPerformedO setSize90 painComponentO event componentes do swing objeto de evento origem de evento addActionListenerO paintComponentO classe interna Graphics2D repaint(O javax.swing

class InnerButton JFrame frame; JButton b ;

O método-chave do ouvinte
Esse método fo rnece a JFrame seu tamanho Você adiciona código a esse método, mas nunca o chama Quando o usuário faz realmente algo, isso se chama Em sua maiOlia são origens de eventos Retorno dados para o ouvinte Um método addXxxListenerO informa que um objeto é uma Como um ouvinte se registra
O método onde todos os códigos de figuras são inseridos

se al t ernará e ntre A e B quando você clicar nele.

pub1ic static void main(String[) args) { InnerButton gui = n e w InnerButton (); gui . go () ;

public void go () { frame = new JFrame() ; fr ame . s e tDe f aultC 10 s eOpe rat i on (JFrame .EXIT_ON_ CLOSE);
Actio -istener é ~~ ínterfaCB, as ~nterfaces são implementadas e não
es:tendida.s~

b = new JButton ( "A" ) ; b.addActionLi stener() ; fr ame . g e tConten tPane () . a dd (Borde rLayout.SOUTH, b); frame . setSize(200,100); frame . setVi sible(true) ;

Normalmente estou ligado a uma instância

o 'g' de (Graphics, g) na verdade pertence a outra classe
O método que faz paintComponentO ser executado

O pacote onde a maioria dos componentes do Swing reside

class BListener extends ActionListener public void actionPe rformed (A c tionEvent e) if (b . getText() . equa1s("A" )) { b.setText(" B" ) ; else { O metodo b . setText ("A") ; ad::lAct.ianz..istenerO usa 'W"'ua cl asse que implementa a int:errace ActionListener .

Pool Puzzle
import javax . swing.*; import java.awt . *; p ubl i c c l ass Anima te int x = 1; int y = 1; public static void main (S tring[ ) args ) { Animate gu i = new Anima t e (); gui. go () ; public vo id go( ) ; cTFrame frame = new JFrame () ; frame . setDefaul t 'C loseOpe ration (JFrame . EXIT_ON_ CLOSE) ; MyDrawP drawP = new MyDrawP() ; frame. getContentPane() . add(drawp) ; frame.getSize(500 , 270); frame . s et Visi ble (t rue ) ; for (int i = O; i < 124; i++ , x++ , y++ ) { x++ ; drawP. repaint ( ) ; t ry { Thread . sleep(50) ; } catch (Exception ex)
}

{ }

class MyDrawP extends JPanel { public void pa intComponent(Graphic g ) { g.setColor(Color.white) ; g.fillRect(C , Q, 500,250); g.setColor(Color . blue) ; g.fillRect(x,y,500-x*2,250-y*2) ;

280

,j·W . . .

13 usando o

,,,'C·~·-,"· . . f·
,-

~I;
~.

ri·

~E

Trabalhe em Seu Swing

POí que a bola não va i para onde quero que ela vá (como quando atingi o rosto de Suzy Smith )? Tenho que aprender a controlá-Ia.

o Swing é fácil. A menos que você se importe realmente com o '.
local onde as coisas acabarão ficando na tela . O código Swing parece fácil, mas, depois de compilar, executar e examiná-lo nos damos conta "ei, isso não deveria estar ato O que torna fácil a codificação é o que torna difícil o controle - o Gerenciador de Layout. Os objetos do Gerenciador de Layout controlam o tamanho e o local dos elementos gráficos em uma GUI Java. Eles executarão várias tarefas por você, que nem sempre gostará dos resultados. Você pode querer dois botões do mesmo tama'nho, o que eles não terão. Pode querer que o campo de texto tenha três polegadas, mas ele terá nove. Ou uma. E abaixo do rótulo em vez de ao lado dele. Mas, com um pouco de esforço, você pode fazer os gerenciadores de layout se curvarem à sua vontade. Neste capítulo, trabalharemos em nosso Swing e, além dos gerenciadores de layout, aprenderemos mais sobre os elementos gráficos. Criaremos, exibiremos (ond e quisermos) e os usaremos em um programa. Nãu estj parev3í1do muito bom pôíô Süzy.

281

componentes

Componentes do Swing
-- .-_._- ~

..

- ~~

. -

.. . . . . . . . . . . . . . . . . . . .. ..!_ ! . . . . . . . . . . . . . . .. ..........

't.

Componente é o termo mais correto para o que temos chamado de elemento gráfico. As coisas que você vai inserir em uma GUl. As coisas que um usuário verá e CO/71 as quais imeragirâ. Campos de texto , botões, li stas roláveis, botões de rádio , etc. são todos componentes. Na verdade, todos estendem j avax. swing . JComponent .

Um elemento gráfico é tecnicamente um Componente do Swing. Quase tudo que você inserir em umÇl GUI estenderá j avax . swing. JComponent.

. ......... ...... ......... .......... .
Gerenciadores de layout
Um gerenciador de layout é um objeto Java associado a um componente específico, quase sempre um componente de plano de fundo. O gerenciador de layout controla os componentes que se encontram dentro do componente ao qual ele está associado. Em outras palavras, se uma moldura tiver um painel, e o painel ti ver um botão, o gerenciador de layout do painel controlará o tamanho e a in serção do botão, enqu anto o gerenciador de layout da moldura controlará o tamanho e a inserção do painel. O botãG, por outro lado, não precisa de um gerenciador de layout, porque não contém outros componentes. Se um painel tiver cinco elementos, mesmo se cada um desses cinco elementos tiver seus próprios gerenciadores de layout, seu tamanho e local no painel serão controlados pelo gerenciador de layout do painel. Se, por sua vez, esses cinco elementos ti verem outros elementos, então, esses outros elementos serão inseridos de acordo com o gerenciador de layout do elemento que os contém. Quando dizemos conter, querem os na verdade dizer adicionar com o em, um painel contém um botão porque o botão foi adicionado a ele através de algo com o:
myPanel . addíbutton) ;

Os componentes podem ser aninhados
No Swing, praticamente todos os componentes podem conter outros componentes . Em outras palavras, l'ocê pode inserir quase tudo em qualquer outra coisLl. Mas, na maiori a das situações, você adicionará componentes de interaçao CO/11 o usuário como botões e listas em componentes de plano de jimdo como molduras e painéis. Embora seja possível inserir, digamos, um painel dentro de um botão, isso seria muito estranho, e não lhe renderá nenhum prêmio de aproveitamento. Com exceção de JFrame, no entanto, a diferença entre componentes interativo.l· e componentes de plano defundo é artificial. Um JPanel, por exemplo, geralmente é usado como o plano de fundo para o agrupamento de outros componentes, mas até esse componente pode ser interati vo. Exatamente com ocorre com os outros componentes, você pode se registrar para ouvir eventos de lPanel , inclusive cliques no mouse e pressionamento de teclas.

Quatro etapas para a criação de uma GUI (revisão)

@

crie uma janela (um JFrame). JFrame frame = new J F rame() ; crie um componente (botão, campo de texto, etc . ) . JButton button = new JButton(" c lick me"); Adicione o componente à moldura . f rame . g etCont ent Pa ne() . add(BorderLa y o ut . EAST,

®

bu tton) ;

Exiba-o (forneça um tamanho e torne-o visível). frame . setSize(300,300); frame . setVisible(true) ;

Insira componentes interativos :
':.!:Butt:Oll

seleçione-me

.~

_

.

Esse é l.lll\ campõ. de texto .

Em componentes de plano de fundo:

Os gerenciadores de layout vêm em várias versões, e cada componente de pl ano de fundo pode ter seu próprio gerenciador de layout . Os gerenciadores de layout têm suas próprias políticas a segui r quando constroem um layout. Por exemplo. um gerenciador de layout pode insistir que todos os componentes de um painel tenham o mes mo tamanho, organizados em uma grade, enquanto outro gerenciador pode permitir que cada componente tenha seu próprio tamanho, contanto que fiquem empilhados verticalmente. Aqui está um exemplo de layouts aninhados:
JPanel panelA JPanel panelB new JPanel ( ) ; new JPanel ( ) ;

pane lB . add (new JBu t t. on (" button 1 ") ) ; panelB.add(ne ", JButton("button 2")) ; panelB . add(new JButton("button 3" ) ); panelA . add (panelB) ;

282

usando

Como gerenciador do layout, é de minha respo nsabilidade o tama nho e a inserção de seus compon entes . Nessa GUI , fu i eu que decidi o tamanho desses botões e onde eles estão com relação uns aos outros e a moldura.

p ~l nlC

D~\!I~t~

~,d(.

me";

~ choo s c rfte:

Painel A
....
-:;r:~:"'("\l,,=

se =::em

..- 3~._ê2

.~

cont::r:3'2.6:ra
ess~

3.:;;anas os e":~:ne:!:,:: - ..l,._ ..... Ded'"J.s di~etaJnent:e a pa.l.J:!el e nao concrc1ara. -,_2('::....-1. ~ • .;) ::51:;& a él.ni.:"""~adc
'"!

Como o gerenciador de layout decide?
Diferentes gerenciadores de layout têm políticas distintas para a organização de componentes (como organizar em uma grade, fazer com que todos tenham o mesmo tamanho, empilhá-los verticalmente, etc.), mas os componentes que estiverem sendo dispostos terão pelo menos alguma pequena influência na questão. Geralmente, o processo de dispor um componente de plano de fundo é seme lhante ao descrito a seguir:

Diferentes gerenciadores de layout têm características distintas
Alguns gerenCiadores de Iayout respeitam o tamanho que o componente quer te r. Se o botão quiser ter 30 por 50 pixels. será isso que o gerenciador de layout alocará para ele. Outros gerenciadores de layout respeitam somente parte do tamanho preferido pelo' componente. Se o botão quiser ter 30 por 50 pixels, ele terá 50 pixels e a largura que seu painel de plano de fundo ti ver. Outros respeitam somente a preferência do maior entre os co mponentes que estão sendo dispostos, e os demaiss componentes desse pai nel serão todos criados com esse mesmo tamanho. Em alguns casos, a tarefa do gerenciador de layout pode se tornar muito co mple xa, mas quase se mpre você conseguirá descobrir o que provavel mente ele fa rá, quando conhecer as características desse gerenc iador de layout.

Um cenário de layout:

E!)

Crie um p aine l e adic ione t rês botões a ele .

®

o gerenciador de l ayout do pa i nel perguntará a cada
botão que tamanho ele prefere ter .

do painel usará ® o gerenciador de layout se deve respeitar suas políticas de layou t para decidir todas, parte ou nenhuma das preferências dos botões. Adicione o painel a urna moldura.

o gerenciador de layou t da moldura pe rguntará ao painel o tamanho que ele prefere t er . o gerenciador de layout ® políticas de layout para da moldura usará decidir se deve
todas, suas respeitar parte ou nenhuma das preferências do painel .

Veja mos ... O primeiro botão quer ter 30 pixels de largura, o campo de texto precisa de 50 , a moldu ra tem 200 pixe ls de largura e eu tenho que orga nizar tudo ve r tica lmente ..

283

••

gerenciadores

~

(..,

"h',:Jl 'T

Os três grandes gerenciadores de layout: -- -- - - -limite , fluxo e caixa
BorderLayout
Um gerenciador BorderLayout di vide um componente de plan o de fundo em cinco regiões. Você só poderá adicionar um componente por regi ão a um plano de fundo controlado por um gerenciador BorderLayout. Os componentes dispostos por esse gerenciador geralmente não conseguem ter seu tamanho preferido. BorderLayout é o gerenciador de layout padrão para uma moldura!

r

T-\

I!

I\

1-\._ __ J-,,---

I

um componente por I € gião

\_-----

FlowLayout
Um gerenciador FlowLayout age como um processador de pal avras , porém com c.omponentes em vez de palavras. Cada componente recebe o tamanho que deseja, e eles são dispostos da esquerda para a direita na ordem que são adicionados, com a "mudança automática de linha" ativada. Portanto, quando um componente não couber horizontalmente, ele passará para a "linha" seguinte do layout. FlowLayout é o layout padrão para um painel!
Componentes são adicionados da esquerda para a direita, passando para uma nova linha quando necessário

BoxLayout
Um gerenciador BoxLayout é como FlowLayout pelo fato de cada componente poder ter seu próprio tamanho e pelos componentes serem inseridos na ordem em que são adicionados. Mas, diferente de FlowLayout, um gerenciador BoxLayout pode empilhar os componentes verticalmente (ou horizontalmente, mas em geral só nos preocupan10s com a disposição vertical). É como FlowLayout, mas em vez de ter a ' mudança do componente para outra linha' automaticamente, você poderá inserir um tipo de 'tecla retum de componentes' e forcá-l os a começar em uma nova linha.

,--------

J

Componentes
adicionados de cima

para baixo, um p or 'linha' .

I\ ld

F"""'-i

----r\-\

BorderLayout leva em consideração cinco regiões: leste, oeste, norte, sul e centro

~Iterofilismo
cerebral
Como o gerenciador BorderLayout definiu esse tamanho para o botão?
BorderLayout está. no pacote j a:t""D. .. ~t,..rt

Adicionaremos um botão à região leste:
import javax . swing . *; impor t java. awt . * ; _ _ _ _ _ _ _ __._ _ _ _ _ _ __
~

public class Bu tt onl ( public static void main (String[) args ) ( Buttonl gui = new Buttonl () ; gui.go() ;
específice a

Quais são os fatores que o gerenciador de layout tem que considerar? Por que o botão não ficou mais largo ou mais alto?
I \

public void go() ( JFrame frame = new JFrame(); JButton buLton = new JButton ( "c lic k me ") ; frame.getContentPane() . add(Bo rder Layout . EAST, frame . setSize(200,200) ; frame . setVisible ( true) ;

/

região

,

button) ;
dick me

~

usand o

Veja o que acontece ao fornecermos mais caracteres para o botão ...

Tentaremos inserir um botão na reg ião norte
public void go () JFrame frame = new JFrame(); JButton button = new JButton ("There is no spoon ... "); frame . getContentPane() . a dd ( BorderLayout . NORTH, button); frame.setSize (200,200) ; frame.set lf isible(true ) ;
)

public void go () { i JFrame frame = new JFrame ( ) ; \.,. JButton button = new JButton("click like you mean it" ) ; frame . getContentPane() . add("BorderLayout .EAST, button); frame . setSize(200,200); frame . setlfis ib le(t r ue) ;

eoo
ih ere is no
SpOOfl . ..

\

..,

. "'.

I

o botão ficou com sua a ltura preferida, mas com a l a r~ur3 àa mo ..... ~u.ra ..

Agora façamos o botão pedir para ser mais alto
Como fazer isso? O botão já está com o máx..imo da largura que pode ter - a largura da mo ldura. Mas podemos tentar torná-lo mais alto fornecendo uma fonte maior.
public void go () ( JFrame frame = new JFrame(); JButt on button = new JButton ( "Cli ck This'''); Font bigFont = new Fontl"serif", Font.BOLD, 28) ; button. setF on t IbigFo n tl ; frame.get Con tentPane() . add (BorderLayout . NORTH, but on); frame . se tS ize(200,200) ; frame. se t Visible ( true);

=~
. li'

f

Jt;
12', .,........,

Uma

fon~e

ma20r forçara a

~

mel ura a alocar mais espaço

~ ,
r'"
h
r-...

f.. ~I

eoo
r

para a

alt~rd

do botão.

eoo
Click This!

clic k hk e Vou mean it

c::
';-.,

r

."
--,--,....
r

"
r

~ r

-

285

"
I'"

layout .

Acho que estou entendendo ... Se eu estiver na região leste ou oes.te , ficarei com minha largura preferida , mas a altura será definida pelo gerenciador de layout. E se eu estiver na região norte ou sul, ocorrerá o oposto - ficarei com minha altura preferida , mas não a largura.

._. . . ._._._L_~=_== .
Norte

I

8;=======~;===========~~~~r ;=====~

I

1.. !
I
I

-J...
Oeste

I

I

I
II
II

I

:-:~
1

i
Ir,

~i'"
"i

l, ~ '~

,

Centro

Leste

! c::.
I c
I

t'\ ..., a,

<o

Mas o que acontece na região central?
A região central fica com o que sobrar!
(Exceto em um caso especial que examinaremos posteriormente.)
public vo id go () JFrame frame JButton JButton JBu tton J Button JBut ton { new JFrame();

! '"
~~=====_ ~ ~~==========~,====~J
, Sul

i

i

I I

new JButton (" East" ) ; east west n ew JButton( "Wes t" ) ; north = new JButton'" ("No rth") ; south = new JButton("South" ) ; center = new JButton("Center"); . add (BorderLayout . EAST , east ) ; . add(BorderLayout . WEST, west ); . add (Bo r derLayout . NORTH , north); . add(Borde rLayout . SOUTH, south); . add (BorderLayout . CENTER , cente r ) ;

frame . getContentPane( ) frame .getContentPane() frame. getConten tP ane () frame . getContentPane () frame . getContentPane ()

QUe!:láo 'troce

':'n.se.!:"'.L::" a..lguma coisa na 2~e. gi ã.o
Sé es=.snàerá de wr lêdc a pcrtento os e-lelIt6nCOS é1.s.s e oeste- não fice.1.~ã.o tão al tos

norte ou svl.,. a::"õ
ot:.r ro dã mo1.dura"

frame .s etSize(3 0 0,300) ; frame.set VisibIe ( true ) ;

re ç-i E>f: s
~~~~tc

l$~ te

sG~iarr.

se as

:eg~óes

nort ~

6

SU:

í/-'~ I ) I \ \
,

I

l. - - - -...)

l --'

(

l ~·

~ l~~ ,t=fJ

i.I I I

,______ 1

TI

)

l

FlowLayout leva em consideração o fluxo dos componentes:
da esquerda para a direita, na ordem em que foram adicionados.

Adicionemos um painel à região leste:

o gerenc iador de layou t de um objeto lPanel é FlowLayollt. por padrão. Quando adicionarmos um painel a uma moldura, seu
tamanho e in serção ainda estarão sob o controle do geren ciador BorderLayout. Mas qualquer coisa que estiver dentro do painel [e m outras palavras, os componentes adicionados ao painel pela chamada a panel.add(aComponent)J estarão sob o controle de Se U gerenciador FlowLayoul. Começaremos inserindo um painel vazio na região lesle da moldura e na próxi ma página adicionaremos elementos ao painel.
impor t j avax .swing . * -

import java . awt. .*; public cI ass Pan ell pubIic stat i c void main (String l ] ar gs) Panell gui = new pa n ell() ; g u i .go() ; (

286

usando

public void go () JFrame frame = new JFrame(); Jpanel paneI = new Jpane l () ; panel . setBackground(Color.c1arkGray) ; frame . getContentPane() . ac1d(BorderLayout.EAST, frame.setSize(2 00 , 200) ; frame . setVisibIe(true) ;

paneI ) ;

~:1;

_-:: __

.:.:..,- ...

Adicionemos um botão ao painel
pubIic void go ()
JFrarne frame :: new JFrame()
i )

ge..-enciaáo:r de ':'a.yout: de pdi:r:el

;àe f':':L"'.:C.

Jpanel p ane I = n ew J panel ( )

i

panel.setBackground(Color . darkGr ay) ;

JSUCcoo bu"oo

o

oe. JBu"oo ,",hook me")

panel .add(button); ~ ~ frame . getContentPane() . add(Borde r Layout.EAST, paneI); fr a me .s e t Size(250 , 200) ; frame . se tV is ib Ie (tru e) ;

ij
/'

.;.,v tro.LE. c b otão Si o gerd nci a dor d~ l ~.'.i""out dii . on .:noláurõ. (de c...lmi t el c:).tlr:::-ola .::; pa":nel.

painel..

painel

»

o painel se expandiu ! E c botão ficou com seu tamanho preferido nas duas dimensões, por~~e o painel usa o layouc de fluxo e o botão fa z parte do f'~E",d (e ruío
da moldur a ) ,

fonte e na quantidade de caracteres, quero ter 70 pixels de largura e 20 de altura.

controla

I

r--

- 7""")

.::;:....

-

-

'_0""

_.

.'

.... L.

".:

..

287

o que acontecerá se adicionarmos
botões ao painel?

DOIS

pubIic void go() { JFrame frame = new JFrame(); JpaneI paneI = new JpaneI ( ) ; paneI.setBackground(Color . darkGray) ;

JButton button = new JButton("shock me"); ri' JButton buttonTwo = new JButton("bliss"); paneI . add(button); ( ------------------paneI.add(buttonTwo); ~(~---------------

//
aciicíona os DOIS a.o painel

Se o código anterior fosse alterado para O código a seguir, qual seria a aparência da GUI?

JButton button = new JButton ("shock me"); JButton buttonTwo = new JButton ("bliss") ; JButton buttonThree = new JButton ("huh?") ; pane I . add(button); paneI .add(buttonTwo) ; panel.add(buttonThree);

frame.getContentPane() . add(BorderLayout .EAST, frame.setSize(250,200); frame.setVisible(true);

pane I);

o que queríamos

o que obtivemos

Queremos os hot ões um acima do outro
a~pilhados

o painel se expandiu para ins erir os dois botões lado a lado.
Desenhe qual acha que seria a aparência da GUI se v ocê e x ecutasse o código à esquerda. (Em seguida, teste-o!)

Obser'f.,"'e que o botão tbliss T é menor do q-ü.e o botão \ shoc1: me? .. . É a.s5in~ qtl€ o ~a..y'out: de fZuxo funciona. O bo'.;ão obtém exatamente o que precisa (e nada ~~ísj~
c-

o
D~-

BoxLayout vem nos salvar!

{
\

c::3l l O

Ele manterá os componentes empilhados, mesmo se houver espaço para inseri-los lado a lado.

Diferente de FlowLayout, BoxLayout pode forçar a criação de uma 'nova linha' para fazer os componentes passarem para a linha seguinte, mesmo se houver espaço para eles se ajustarem horizontalmente.
Mas agora você terá que alterar o gerenciador de layout do painel do FlowLayout padrão para BoxLayout.
.J._lcera. o gerencJ..ador áe

pubIic void go ( ) { JFrame frame = new JFrame(); JpaneI paneI = new Jpanel(); panel.setBackground(Color.darkGray);

2eyout para ~~~ seja n o va inscência de
B o;,,;-Jjay out
~

~~a

lné':'>;;"

Observe como o painel está estreito novamente}' porque não preci.sa ;:rjustar os doi. botões "

panel.setLayout(new BoxLayout(panel,

BoxLayout . Y_AXIS));

~

JButton button = new JButton("shock me·'); JButton buttonTwo = new JButton ("bliss") ; panel . add(butt on) ; panel.add(buttonTwo) ; frame . getCon t entPane () . a dd (BorderLayout . EAST, frame.setSize(250,200); frame. s etVi s j bl e (true ) ;

~

"

horizonta,l.menr.e.. Portanto, ele informou à mold~ra ~~e precisava de espaço sufi.óiente E'cmep.te par e. o
botá:;) principeJ.~
~sb.ock

me T ..

conhecer c
C'

-"',,\
~

mpOL8zote

q-Uê

eiS':;,f

ãisponde

e
pane 1);

que €:ixo :L5ú.r

r USê_r.:,",:>s Y_AXIS para um

288

usando

Não

existem

perguntas Idiotas
Por que você não pode adicionar algo diretamente a uma moldura como podemos fazer em um painel ?
Um JFrame é especial porque é onde a ação realmente ocorre quando queremos fazer com que algo apareça na tela. Embora todos os componentes do Swing . sejam Java puro, um JFrame tem que se conectar ao sistema operacional subjacente para acessar a exibição. Considere o painel de conteúdo como uma camada com 100% de Java puro que fica acima do JFrame. Ou considere como se o JFrame fosse a moldura da janela e o painel de conteúdo fosse a .. . Vidraça . Você sabe, a vidraça da janela . E você pode até trocar o painel de conteúdo pelo seu próprio JPanel , para tornar seu JPanel o painel de conteúdo da moldura , usando :
myFrame . setContentPane (myPanel ) ;

P:

DISCRIMINAÇÃO DOS PONTOS

R:

- Os gerenciadores de layout controlam o tamanho e o local de componentes aninhados dentro de o utros componentes.
- Quando você adicionar um componente a outro componente (às vezes chamado de componente de plano de fundo, mas essa não é uma classificação técnica), o componente adicionado será controlado pelo gerenciador de layo ut do componente de plano de fundo. - Um gerenciador de layout pergunta aos componentes seu tamanho preferido, antes de tomar uma decisão sobre o layout. Dependendo das po líticas do gerenciador de layo ut, ele pode respeitar todas, algumas ou nenhuma das preferências do componente. - O gerenciador BoderLayout permitirá que você adicione um componente a uma das cinco regiões. Você deve especificar a região quando adicionar o componente, usando a sintaxe a seguir:
add(BorderLayout. EAST, panel);

Posso alterar o gerenciador de layout da moldura? E se eu quiser que a moldura use o gerenciador de fluxo em vez do gerenciador de limite?
A maneira mais fácil de fazer isso é criar um painel, construir a GUI como você quiser no painel e, em seguida , tornar esse painel o painel de conteúdo da moldura usando o código da resposta anterior (em vez de usar o painel de conteúdo padrão) .

P:

R:

- Com BorderLayout, os componentes das regiões nOIte e sul ficam com sua altura preferida, mas não com a largura. Os componentes das regiões leste e oeste ficam com sua larg ura preferida. mas não a altura. O componente do centro ficará com o que sobrar [a menos que você use packOJ. - O método packO é como se disséssemos 'embalado e lacrado ' com relação aos componentes; ele usa o tamanho preferido total do componente central e, em seguida, determina o tamanho da moldura. usando o centro como ponto inicial, constmindo o resto com base no que houver nas ou tras regiões. - FlowLayout insere os componentes da esquerda para a direita, de cima para baixo, na ordem que foram adicionados, passando para um nova linha de componentes somente quando eles não cabem horizontalmente. - FlowLayout dá aos componentes seu tamanho preferido nas duas dimensões . - BoxLayout permitirá que você alinhe os componentes empilhados verticalmente, mesmo se eles couberem lado a lado. Como FlowLayo llt , BoxLayout lisa o tamanho preferido do componente nas duas dimensões. - BorderLayout é o gerenciaclor de layo ut padrão para uma moldura: FlowLayout é o padrão para um painel. - Se você quise r que um pain el use algo diferente do fluxo , terá que chamar setLayout( ) no pain el.

Há um método setSizeO para componentes?

P: E se eu quiser um tamanho preferido diferente?

Sim , há um setSizeO, mas os gerenciadores de layout o ignorarão. Há uma diferença entre o tamanho preferido do componente e o tamanho que você quer que ele tenha. O tamanho preferido é baseado no tamanho que o componente realmente precisa ter (o componente toma essa decisão sozinho). O gerenciador de layout chamará o método getPreferredSizeO do componente .e esse método não se importará se antes você chamou setSizeO no componente.

R:

Não posso simplesmente inserir os eleme ntos onde quiser? Posso desativar os gere nciadores de layout?
Sim. Em cada componente isoladamente, você Pode chamar setLayout(null), e assim ficará sob sua _r~sponsabilidade embutir em cód igo os locais e dimensões exatos da tel a. No fina l das contas, no entanto, quase sempre é mais fácil usar os gerenciadores de layoüt.

P:

R:

--y".................

289

gerenciadores
._~
·,,-;;.~r~

Testando os cOrl]ponentes do Swing
Você aprendeu os aspectos básicos dos gerenciadores de layout, portanto agora testaremos alguns dos componentes mais comuns: um campo de texto , a área de texto de rol agem, a caixa de seleção e a lista. Não mostraremos o APl inteiro de cada um , apenas alguns destaques como introdução.

JTextArea

<I ;Á.;t

--1.'~

~:

JTextField

Ir"

1
I
.:rLabel
J'l'e~!tFielã

Díferente de JTextFielà ,l JTextAz"ea pode te:: mais de uma l i nha àe texto. É preciso al~Jm es forço de configuração em sua criação p orque ele não vem com barras de rolagem ou q"iJ ebra de l inba. Para fa.zer run JTextArea rolar; v o c ê terá que íLserí-lo em um Scrol1Pane~ Um Scrol lPane é um obieto que aprecia ~uito r oler e se encarregará das necessida.des de rolage..1"[1 da á rea. de texto.
l

Co n struto res:
10 significa la liILlJas (conngura a altura preferida) .

Construtores:
JTextArea text JTextField field new JTextField(20);
20 significa 20 colur..ias
(configura a

new JTextArea(lO,20);

l

le.:g-..zra preferida).

20 si gni fica 20 col unas e não 20 pixels.

Isso defi!l€

a.

largura preferida do campo ds t.exto ..

Como usá-lo
Faça com que ele tenha s o mente urna barra de rolagern vertical. JScrollPane scroller = new JScrollPane ( text ) ;

JTextField field

new JTextField ("Your name");

Como usá-lo
([) Capture o texto que se enc o ntra nele . System.out.println(field.ge tText());

para a qual

e~e

rola=é.

text . setLineWrap(true) ; scroller.setVerticalScro ll BarPolicy (Scro llPaneConstants. VERTICAL_SCROLLBAR..ALWAYS) ; scroller . setHorizontalScro llBarPolicy (ScrollPaneConstants . HOR IZONTAL_SCROLLBAR_NEVER); Informa ao painel de rolagem para usar somente uma b arre de rol a gem ~~~3:..~_~_~~J., p ane l . add(scroller ) ;
ImpC.!"tai.tte j 1roei fornecerá & erGa de t exco ao p ainel de 1."o.legem fa tre,Té.s cio cons'trt:tor de paine::' de ro"fagem) €o,,.- e.lD seçr;;:ids r adicíonc:..ré c painel de rolag-srr. ao pai.n,s·1. geraI ~ v-ocê nâo adicioners". ii área

~ Insira texto nele.
field. setText ("whatever") ; field . setText( 1r) ;

Issc limpa o campo.

~ Capture um ActionEvent quando o usuário
pressionar return ou enter . field.addActionListener (myAct i onL istener ) ;
v6cê também pode se reg",istrar pa:a ouv:Lr.

e"'entosq""JE'

c1:6.'rre- ...

se quiser Te:almen!::e ser in:tormaác sempre
~ecle

o usuaric pressionar umç;

..

~

de tarte; :iiretanlente ao pa..:ne.1 qeral t
Selecione/realce o texto do campo . field.selectAll () ; Substitua o texto existente . ~ text. settext ("Not alI who are lost are wandering"); " Acrescente algo ao texto existente. text .appenà("buLlon clicked"); Selecione/realce o texto do campo. text.selectA ll() ;

~ posicione o cursor no campo (para que o
usuário possa começar a digitar).
field . reque s tFn~us()

;

®

Posicione o cursor no campo (para que o usuário possa começar a digitar). text . requestFocus() ;

'.
s4

usando

Exemplo de JTextArea
import javax . swing . * ; impor t j ava . awt . -k ; import java . aw t . e vent. * ; public class TextAreal implements ActionListener ( JTextArea t e xt; public static void main (String[J args) TextArea1 gui = new TextAreal() ; gui . go ( ) ;
button c i lcked

button

é ll ~k ed

bu ttun cl Lckeá

publ ic vo i d go ( ) JFrame frame = new JFrame(); Jpanel paneI = new Jpanel ( ); JButton button = new JButton" ("Just Click l t"); b ut ton . addAct ionLi st ener (th i s) ; text = new JTextAr ea(10,20) ; text . setLineWrap (true ) ;

I~----------------------------------~~, .., Ju st Cli ck II .

JScrollPane sc r oller = new JScrol l Pa ne(text) ; sc r oll e r . s etVertica I ScrollBa rPo l icy(ScroIIPaneConstants . VERT I CAL_ SCROLLBAR_ALWAYS); scroller . setHorizontaIScrolIBarPolicy ( ScroIIPaneConstants . HORIZONTAL_SCROLLBAR_ NEVER); panel . add(scroller) ; frdffie . getContentpane() . add (BorderLayout . CENTER, paneI) ; frarne.getC on t entPane () . add (BorderLayout . SOUTH , button ) ; fr ame. s etS i z e ( 3 50,300) ; frame . setVisible(true);
button clt ckedbutton cllckedb utton cltc~ edbutton cl lckedbutton cll ckedbutton cl ilff ckedbutton cllckedbutton cl l ckedbutton c r 11 ckedb utton cll ckeobutton cl i ckedbutton " . cllckedbutton cllckedbutton cllckedbutt o ! ; on clLckedbutton c llckedbutton cl L ckedbu tton cl i. ckedbutton cl i ckedbutton cl i. cked :. , edbutton chckedbut ton cllekedbutton eh ... ckedbutton cllckedbutton cl l ckedbutt crl c.-;-

l/1'
publ ic vo i d a c tio n Per f o rmed(Ac ti onEven t text . append("button clicked \n " );
ev)

Ins e re uma nova linha par a que as pa l avras sejam inseridas em uma linha sepa rada sempre ~Je o botão for clicado. Caso contrário, ficará tudo junco.

JUS! Clfek It

JCheck80x

Construtores:
JCheckBox check new JCheckBox("Goes to 11");

Go es t o 11
Como usá-lo
Escute o e v ento de um item (quando ele for selecionado ou desmarcado). check . addltemListener(this ) ;

®
-r+-.'
j;

Manipule o e vento (e descubra se ele foi ou não selecionado ) . public void itemStateChanged ( ItemEvent e v) String o nOrOff = "off"; if (check . isS e lected()) onOr.Off = " on" ; System. o ut . println ( "Check b o x is • + on Or Off);

®

Sele c ione ou de smarque - o e m c ó d igo . check . set Se lect ed (t rue) ; check . setSelected(Ealse} ;

291

gerenciadores :::,G ,";y,),

JList

alpha

f:1. "

,beta
gamma

~J

Não existem

d el t a ' "

Perguntas I diotas
Os gerenciadores de layout não causam mais problemas do que ajudam? Se eu tiver que passar por toda essa confusão, prefiro embutir em código o tamanho e as coordenadas de onde os elementos devem ser inseridos.
Obter o layout exato que você deseja de um gerenciador de layout pode ser um desafio. Mas pense no que o gerenciador de layout está rea lmente fazendo para você. Mesmo a tarefa aparentemente simples de saber onde os elementos devem ser inseridos na tela pode ser complexa. Por exemplo, o gerenciador de layout se encarregará de evitar que seus componentes se sobreponham. Em outras pálavras , ele sabe como gerenciar o espaçamento entre os componentes (e entre a borda da moldura). É claro que você pode fazer isso sozinho, mas o que acontecerá se quiser que os componentes sejam inseridos bem próximos. Você pode conseguir inseri-los . da maneira correta, manualmente , mas isso só será bom para sua JVM! Por quê? Porque os componentes podem ser um pouco diferentes de uma plataforma para outra, principalmente se usarem a 'aparência' nativa da plataforma subjacente . Coisas sutis como o contorno dos botões podem ser tão diferentes que os componentes que ficam alinhados corretamente em uma plataforma repentinamente se amontoam em outra. E ainda não chegamos ao que os gerenciadores fazem de realmente importante . Pense no que acontecer? quando o usuário redimensionar a janela! Ou se sua GUI for dinâmica, onde componentes surgfim e desaparecem'. Se você tivesse que controlar a reorganização de todos os componentes sempre que houvesse uma alteração no tamanho ou no conteúdo de um componente de plano de fundo ... É bom nem pensa r!

P:

Construtores :
String [] listEntries = {"alpha", "be ta", "gamma " , "delta", "epsilon", "zeta", "eta", "theta"}

list = new JList(listEntries);

R:

o construtor de JList usa lli~Q wztriz de qua2 quer tipo de objeto. Eles não têm que ser Strings r mas ~ represen tação de uma String aparec erá na lista.

Como usá-lo
Faça com que ele tenha uma barra de rolagem vertical. JScrollPane scroller = new JScrollPane(list); sc ro ll e r . setVerticalScrollBarPolicy (Scro ll PaneConstants . VERTICAL_ SCROLLBAR_ALWAYS); scroller . setHorizontalScrollBar Policy (Scro l lPaneConstants . HORIZONTAL_SCRO LLBAR_NEVER); panel . add(scroller) ;
I sso é o mesmo q ue ocorre com "" Tf:x:tAr ea - você criara um. .... JScr:;;11Pane ( e o fo:::necera a. l:l.sta; para Sr! $egl1. 'ci~ adic::'O!lar ~ painel de ro2agem le l~O a lista) ao painel geral~

~ Configure a quantidade de linhas a serem exibidas
antes da rolagem • list . s etVisibleRowCount(4) ;

~ Restrinja o usuário à seleção de somente UMA coisa de
cada vez . list.setSelectionMode(ListSelectionModel . SINGLE SELECTION); Registre-se para ouvir eventos de seleção na lista. list . addListSelectionListener ( this ) ;

®

Manipule eventos (descubra o que foi selecionado na lista) . public void valueChanged(ListSelectionEvent lse)

if(!lse . getValueIsAdjusting()) String se l €ct ion = (String) list . ge tS elec t edValue() ; System . out . println(selection ) ;
I

7

i

i

292

usando

Receita de código

J
00

J
Cyber Beat13Qx

J

Crasn Cymb al
Hand Clap

Hígh Tom Hi Bongo
Maracas
;~ ~~ . _. --t ~!-I
~
~

_ _ _ .....""."..

-

- - - , _

= =n---:= ;': -'~
_ _______

~

ri

~ ~ ~
. - i.

~

-~", _ ---> _ _ - < r-

"":1

Whí<Stle

lm.v Longa Cowbell
VibrasJap
l OW-,11i d

Tom
:::::: i~ ~
.~

HighAgogo

='.

!V1' ~

=:.!

Operr Hi Conga.......! -

,_ . .' ~ -. '_ ,-'

==:= =! C C := -,
r AA : ' '--l n

.\
.,~

Essa parte é opcional. Estamos criando a BeatBox completa, com a GUI e todo o resto. No capítulo Salvando Objetos, aprenderemos como salvar e restaurar padrões de bateria. Para concluir, no capítulo sobre rede (Crie uma Conexão), converteremos a BeatBox em um cliente de bate-papo funcional.

Criando a BeatBox
Essa é a listagem completa do código dessa ve rsão da BeatBox, com botões para a inicialização, a interrupção e a alteração do ritmo . A listagem do código está completa, e totalmente comentada, mas aí vai uma visão geral:
Construa uma GUI com 256 caixas de seleção (JCheckBox) inicialmente d esmarcadas, para os nomes dos instrumentos e quatro botões. 16 rótulos

®

Registre um ActionListener para cada um dos quatro botões . Não precisamos de ouvintes ' para cada caixa' de sel eç ã o. porque não estamos tentando altera r o padrão de: som ciina~icamente (isto é. . quando o usuário marcar uma ' caixa) . Em vez disso, esperaremos até que o üsuário pressione o botão 'start' e, em seguida, percorreremos todas as 256 caixas de seleção para capturar seu estado e gerar uma Eaixa MIDI.

~ Conf i gure o sistema MIDI (voce já fez isso antes) incluindo a captura de um seqüenciador, a criação
de uma seqüencia e de uma faixa . Estamos usando um método do seqüenciador que é novo na Java 5 . 0, setLoopCount( ) . Esse método permitirá que você especifique quantas vezes ~Jer que uma seqüência seja
_roo,· ,.

293

~--- --

cód igo
repeti d a . Também e s tamos us a ndo o f a t or de r itmo da s eqü ê ncia par a diminuir ou ac e lerá -la, e man t er o

Será quando o usuári o p res s i onar 'start ' qu e a açã o real começará. O métod o d e manipulação de e v entos d o b o tão 'start' chamará o mét o d o buildTrackandStart () . Nesse mét o do, perc o rreremo s todas as 256 caixas de seleção (uma linha de cada vez, todas as 16 batidas de um único instrumento) para capturar seu estado e, em seguida, usaremos as informações para construir uma faixa MI DI [empregando o prático mét o d o makeEvent ( ) que usamos n o cap ítu l o an t eri o r) . Quando a faixa estiver construída, iniciaremos o seqüenciador, que c o ntinuará a reprodução (porque ela estará sendo repetida) até o usuário pressionar 'stop' .

,r",

import import import import import

java.awt . *; javax . swing . *; javax.sound.midi.*; java.util.*; java . awt.event.*;

public class BeatBox {

Jpanel mainpanel; ArrayLis t<JCheckBox> checkboxList; Sequencer sequencer; Sequence sequence; Track track; J Frame theFrame;

@( ~------------------­

Armazenaremos as caixas de seleção em uma ArrayList.

Esses são os

na~es

dos

instrument o s , c omo uma a rray de Strings; para a

construção dos rótulos da GUI (em cada lir~~a). String[ ) instrumentNames = {"Bass Drum", "Closed Hi -Hat", "Open Hi-Hat", "Acoustic Snare", "Crash Cymbal", "Hand Clap", "High Tom", "Hi Bongo" , "Maracas", "Whistle", "Low Conga" '- "Cowbell" , "Vibraslap", "Low-mid Tom", "High Agogo", "Open Hi Conga"}; int [) instruments = (35,42,46,38,49,39,50,60,7 0,72,64, 56,58,47, 67,63) ; Esses números representam as'
'teclas~

reais da batezia. O

public static void main (String[) args) new BeatBox2() .buildGUI();

canal da bateria é como um piano.. Gl~ceto pele fato d e
caria ";::eC.L.â ,- cio p~, al'lO ser um
ba~eria

eLemento óe

public v oid buildGUI () theFrame = new JF rame ("Cyber BeatBox"); theFrame. s etDefaultCloseOperation(JFrame . EXIT_ON_CLOSE) ; BorderLayou t lay out = new BorderLayout () ; JPanel background = new JPanel ( layout ) ; background.setBorder(BorderFactory.createEmptyBorder(l0,10,10,10)); checkboxLis t = new ArrayLis t <JCheckBox> () ; Box buttonBo x new Box (BoxLayout . Y_AXIS ) ; JButton start = new JButton ("Start " ) ; start . addActionListener(new MyStartListener ( ) ) ; butt onBo x . a d d ( start ) ; JBu tt on stop = new JButton("Stop") ; stop.addActionListener (new MyStopListener () ); buttonBox.ad d ( s top ) ; JButton upTempo = new JButton ("Tempo Up"); upTempo . addActi onListener(new M UpTempoL i stener( ) ); y but ton Box . a dd( u p Tempo) ; JButton downTempo
=

o número '35' e a tecla do btL"nbo {basa drtm!) , 42 Iii o Ri-Chapéu Cl~seã (Closed Hi HatJ,

di=e~e~te.

Portanto~

ecc.

Oma.·

~ borda

vazia

~

nos

fornecera uma margem entre as bordas do paíne1. e onde os componentes estão ,Pos:' cionados· ..
PUzament~

estétíco.

l~ada

de especie..l .aqui, apenas CÓdlgO de GUL. Grande

pe.:::'!;e :rbcé )'É. "t~it1 ..

new JButton ( "Tempo Down" ) ;

down Temp o . addAc ti onL ist ener (n e w MyDownTemp o Li s tene r ()); bu ttonBox . add ( d ownTe mpo) ; Box name Box = n e w Box(BoxLayout.Y_AXIS) ; f or ( i nt i = O; i < 1 6; i++ ) nameBox . add(nEow Label(instrumentNames[i]))

i

294

usando o swing

background . add(BorderLayout.EAST, background. add (BorderLayout . \illEST,

buttonBox) ; nameBox) ;

il..i.nda é código de con.fi.guração da GUI. Nada de especi a l.

theFrame.getContentPane() . add(background); GridLayout grid = new GridLayout(16,16j; grid.setVgap(1) ; grid.setHgap (2); mainpanel = new Jpanel(grid); background . add (BorderLayout.CENTER, mainpanel); for (int i = O; i < 256; i++ ) JCheckBox c = new JCheckBox() ; c.setSelected ( false ) ; checkboxList.add (c) ; mainpanel.add(c); II fim do loop Cria as caixas de seleção, configura - as com '.false' (para que não estejam marcadas ) e as adiciona à ArrayList E ao painel da GUI.

setUpMidi() ; theFrame.setBounds(50,50,300,300); theFrame.pack() ; theFrame.setVisible(true); II fecha o método

public void ~e:tU~Miq:L,{)J {
try { " >4"
..

~,;~

" ""-,,,I"

:.~

sequencer MidiSys tem. getSequencer(); sequencer.open() ; sequence = new Sequence(Sequence .PPQ,4) track = sequence.createTrack(); sequencer.setTempolnBPM(120); catch ( Exception e) II fecha o método (e .printStackTrace();}

costumeiro trecbo de configuração MIDI para a captura do seqüenciador, da seqüência e da faixa . Novamente, nada de especial. Criaremos uma matriz de 16 elementos para armazenar os valores de um instrumentoi com todas as 16 batidas. Se O instrumento tiver que ser
reproduzido nessa batida, o valor desse elemento será a

o

É aqui que tudo acontece! É o local em que convertermos o estado da caixa de seleção em eventos MIDI e os adicionamos à faixa.
public void.j~l&~Tra:~~S.s:f.Y]j ( int [] trackList = null; ( - - - -- - - - -- -- - - - - - - - - - sequence.deleteTrack(track); ~ track = sequence. createTrack ();

tecla. Se esse instrumento
NÃo tiver que ser

reproduzido nessa batida,
insira um zero.

:> (1.(=--- -- - - - - - - - - - - - - --

-

Elimina a faixa antiga, cria uma nova. Fará isso para cada uma das 16 LINHAS (isto é, Bass , Congo, etc .) . Configura a 't ecla' que represen tará qual é esse instrumento (bumbo , bichapéu, etc. A matriz de instrumentos contém os números MIDI reais de cada instru.."nento J ~
Fará isso para cada uma das BATIDAS dessa linha.

for

(int i = O; i < 16; i++) trackL ist = new int[ 16];

(~---------------------

in t

key

instruments [i];

~(~----------------------

for

(in t

j

O;

<

16;

j++

~~h~C~~~:s~~lec~:~~~~kBOX~)checkboxList.get(j
= O; i II fecha o loop interno

+ ( 16*i»;

A caixa

de

sel$ção dessa batida

está selecionada? Se estiver,

trackLis t [j] else ( trackList[j]

key ;

t?-----------------(

insira o valor da tecla nessa
posição da matriz (a posição que representa essa batida ). Caso concrá.rio, o instrtilnento
,:-!$rJ .,~ve reprodu zi r ~ssa

batida, portanto, configur",-a
cam

zero.

continuação

:1,] ;:-;":';::'::9':.

makeTracks(trackList) ; track . add(makeEve nt (176, II fecha o loop externo

.::"" =~ =

t..:; ..-::'~2

;:;.;;; :;, C J.?~t,i~Ii:;. ::j";--'~

,127, 0,16)) ;

::r.í3.eV"entos e os. ad:iciona.
aI

;1
.""'"

fa~r.:a.

Queremos. nos certificar

track .add (makeEvent(192,9,1,O,15)) ; try {

~~~

________________ ._______________

sempre d€- que Ivi event o ne batida 16 (eLa vai de O a 15). Caso contrário, a
BeatBcx pode nâo percorrer

=

todas as 16 batidas antes de começar novamente.
Permite
que

v-ocê

sequencer . setSequence(sequence); sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY); ~-----------sequencer.start() ; ~ sequencer.setTempolnBPM(120); catch(Exception e) {e.printStackTrace();} ~--------------------II fecha o método buildTrackAndStart

espe cifique a Q".lantidade de iterações do loop ou, nesse casO r um Ioop con tinuo.
AG01Ui. REPRODUZA!!

public class ~yStar~Listener implements ActionListener public void actionPerfórmed(ActionEvent a) ( buildTrackAndStart() ;
/1

fecha a classe interna
r1';'t(T"'~

primeira ãa s c1.asses interna.s são os ouvintes dos botões. Nade de especial aQ".li .
A

public class .'JI1YStopList.ene:ç implements ActionListener public voi2tâ'ctlonp'êrfü"";med (ActionEvent a) sequencer.stop();
}

II fecha a classe interna

pub1ic cla ss MyUpTempoLi'stener imp1ements ActionListener ( pub1ic void actionPerformed (ActionEvent a) { ~( float tempoFactor = sequencer.getTempoFactor(); sequencer.setTempoFactor (( float) (tempoFactor * 1.03));
II fecha a classe interna

Os ouvintes das outras
classes
inter~as

dos botões

public class MyDownTempoListener impl ements ActionLi stener ( public void actionperf õrmed(ActionEvent a) float tempoFactor = sequen cer.getTempoFactor( ) ; sequencer.setTempoFactor( ( f1oat) (tempoFacto r * . 97));
II fecha a classe interna

, ) ~~

TampoFac=o: dLmensionará o ri tmo da. seqüência pelo fator ·forn ecid~~ O padrão é
1, {]"
pDrtanto, esca.,i110S

a j ustand o para cerca de 3% por clic;:ue ..

Isso criará sv"entos para um instrumento de cada ~€2~ par a tedas as 16 batidas. Portan to,
pode capturar u.7J2 int [} para " bumbo e cada índice da ma triz

public void makeTracks(int[] for (int i int key

list )

O; i < 16; i++) 1ist [i] ;
~,

if (key '= O) track .add(makeEvent(144,9,key, track .add(makeEvent (128,9,key,

100, 100,

i) ) ;

(

con~erá a tecla ãesse ínstrumento ou um zero~ Se ti ""'$z" um zero~ {j i nst::.~umento nPio de ..:·e ser. reproduzido nessa ba.t i da ~ Caso contrá.!niCl r um e'F-an:-o se.:::a criado e adi.e ion.s.õo i fai:1cE. ~

i+1) ) ;

S ~
Cria os eventos NOTE O!~ e NOTE

OFF e os adicioLa à

f~ixa~

pub1ic MidiEvent makeEvent(int comd, int chan, MidiEvent event nu11 ; try ( Shor tMessag e a = new ShortMessage(); a . setMessag e(comd , chan, one , two); event = new MidiEvent(a, tick) ; } catch(Exception e)
r et UI."11 event ;

int one,

int two,

int tick )

( e . pri n t: Sr.a ckTra ce() ;

J

í,

f.;:-clld

c:.1

C.1.i"'1~ :-it::'

296

usando

J

,'JV.

J

Que código está relacionado a que layout?
C inco das se is telas abaixo foram criadas a partir de um dos trechos de código ao lado. Ligue cada um dos cinco trechos de cód igo ao layout que ele prod uziria.

eoo

---,Trechos de código

o o

JFrame frame = new JFrame(); Jpanel paneI = new Jpanel(); panel . s e tBackground(Color . darkGray) ; JButton button = new JButton("tesuji"); JButton buttonTwo = new JButton("watari") ; frame . g e tContentPa ne() . add(BorderLayout . NORTH,panel); panel.add(buttonTwo); frame . getCont ent Pane() . add(Borde r Layout . CENTER ,button) ;

JFrame trame = new JFrame () ; JP~~el paneI = new Jpanel(); panel .se tBac kground(Co l or.darkGray) ; JButton button = new JButton("tesuji"); JBu tton buttonTwo = new JButton( "watari"); panel.add(buttonTwo); frame. g e tContentPane() . addIBo r derLayout . CENTER,bu tt on) ; frame.getContentPane() . add(BorderLayout .EAST, paneI);

JFrame frame = new JFrame(); JPanel paneI = new Jpanel(); panel.setBackground (Co lor.darkGray ) ; JButton button = new JButton ( "tesuji"); JButton buttonTwo = new JButton("watari"); panel . add(buttonTwo) ; trame.getContentPane() . add(Bo rde r Layout . CENTER,button);

..'

o

o

JFrame frame = new JFrame(); Jpanel p aneI = new Jpanel(); panel . setBackground(Color . darkGray) ; JButton button = new JButton("tesuji"); .JButton buttonTwo = new JButton("watari"); panel. add(but to n); frame.getContentPane() . add(BorderLayout.NORTH,but t onTwo); frame . getContentPane() . add(BorderLayout . EAST, paneI);

JFrame trame = new JFrame(); Jpanel paneI = new Jpanel(); panel . setBackground(Colo r.da rkGray) ; _.B,:::.= J",Bo-u-,-tc-ton button = new JButton("tesuji"); _ ::-_
~
JButton

buttõ n~= - new JEuLLulJ.\ "iN"ô.t:.ai:i" ) ; -

frame .ge tContentPane() . add(BorderLayout . SOUTH,panel); panel . add(buttonTwo) ; f rame . getContentPane (i . add (BorderL a yout . NORTH , ~ " ltton) ;

quebra-cabeças: palavras cruzadas
-'<!

.'

Cruzadas GUI 7.0

---1
4i

;:~.

Você consegue. Horizontais Verticais
2. Pai do Swing

1. O playground do artista
4. Local para o que restar do gerenciador de limite 5. Aparência Java

3. Jurisdição da moldura
6. Casa da ajuda

7. Mais diversão do que texto
8. Gíria para componente 9. Comando de Romulin 10. Disposição

11. Objeto genérico de espera
12. Um acontecimento 13. Aplicar um elemento gráfico

15. Padrão de JPanel
17. Teste polimórfico 18. Mova-se 21. Muito a dizer 23. Selecione váriâs 25. Companheiro do botão 26. Casa de actionPerformed
298 capítulo 13

16. Regras do gerenciador 14. Comportamento da origem
19. Usa o geienciador de limite por padião 20. Comportamento do usuário 24. Lado direito do gerenciador de limite

usando ')

:,W!f1r:;

~oo
JFrame frame = new JFrame(); JPanel paneI = new Jpanel(); paneI. setBackground(Color . darkGray) ; JButton button = new JButton("tesuji"); JButton buttonTwo = new JButton ("watari" ) ; panel . add(buttonTwo); frame.getC on tentPane () .add (BorderLayout.CENTER,button );

JFrame frame = new JFrame(); Jpanel paneI = new Jpanel(); panel.setBackground(Color.darkGray); JButton button = new JButton("tesuji"); JButton buttonTwo = new JButton ( "watari" ); frame.getContentPane( ) .add(BorderLayout.NORTH,panel ) ; panel. add(buttonTwo) ; frame.getContentPane() .add(Borde rLayou t.CENTER,button) ;

JFrame frame = new JFrame(); JPanel paneI = new Jpanel(); panel.setBackground (Co l or .darkGray) ; JButton button = new JButton ( "tesu ji"); JBu t ton buttonTwo = new JButt on( "watari" ) ; frame . getContentPane() .add(BorderLayout.SOUTH,panel ) ; panel . add(buttonTwo) ; frame . getConten tPane() .add(BorderLayout . NORTH,button);

o
"
-

"

JFrame frame = new JFrame(); Jpanel paneI = new Jpanel(); panel.setBackground (Color.darkGray); JButton button = new JButton (" tesuji"); JButt on buttonTwo = new JButton("watar i "); ·panel .add(button) ; f rame.getC ontentPane() . add(BorderLayout.NORTH ,bu ttonTwo ); frame.getContentPane() . add(BorderLayo ut . EAST, pane I );

~

JFrame frame = new JFrame(); Jpanel paneI = new Jpanel(); p anel.setBackgr ound(Co l or . darkGray) ; JButton button = new JButton("tesuji"); JButton buttonTwo = new JButton("watari");
------~~ªª+l?'-'tt9R-'!'.\J9-';

h.

frame . getContentPane() . add(BorderLayout . CENTER , button); f rame.getC ont entPane() . add(Border Layout .EAST, paneI);

h
)~
você está aquI
~

+i

299

resposta oe

r .. ~r-..... b \...... . eJ ......

____ ___

__ _ _._ __ _ _ _

~ Respostas

do Quebra-Cabeças

Cruzadas GUI 7.0

1
j

!

!

!

" \;~

J

.,I

I

300
-----

14 serialização

EIS de arquivo

Salvando Objetos

Se eu tiver que ler mais um arquivo cheio de dados, acho que te rei que matá-lo. Ele sabe que posso salvar objetos inteiros, mas deixa que o faça? NÃO, isso seria muito fácil. Bem , veremos como ele se sente depois que eu ...

Os objetos podem ser achatados e reconstituídos. Os
objetos possuem estado e comportamento. O comportamento reside na classe, mas o estado reside dentro de cada objeto individual. Portanto, o que acontecerá quando for hora de salvar o estado de um objeto? Se você estiver êriando um jogo, precisará de um recurso Salvar/Restaurar Jogo. Se estiver criando um aplicativo que gere gráficos, precisará de um recurso Salvar/Abrir Arquivo. Se seu programa tiver que salvar o estado, você poderá fazê-lo da maneira mais difícil, examinando cada objeto e gravando meticulosamente o valor de cada variável de instância, no formato que criar. Ou, da

maneira mais fácil, orientada a objetos -

simplesmente congele/

achate/faça persistir/desidrate o próprio objeto e o reconstitua/ desachate/restaure/reidrate para que volte ao que era. Mas você ainda terá que fazê-lo da maneira difícil em algumas situações, principalmente quando o arquivo que seu aplicativo salvar tiver que -~- L;~"-_a.lrll ,= o, otrCL<:>.~ti.ucL.n3m A"cr it o p-m J::lV::l 1000 PI' ..... '-"' ... V...., .........
\.A1t1 ...... 111 'J'-""',V .......

~CIIIUUtJVI

_-::O- ...... _ ;..

_ . ... ~ -

_o ;

-..J

;

examinaremos as duas maneiras neste capítulo.
". :;-.;:;' :: ',n
GCn'"

capitulo

301

salvando objetos

Capture a batida
Você criou o padrão perfeito. Deseja salvá-lo. Poderia pegar um pedaço de papel e começar a rascunhá-l o, mas em vez disso pressionou o botão Salvar (ou selecionou Salvar no menu Arquivo). Em seguida, forneceu um nome, selecionou um diretório e respirou aliviado sabendo que sua obra-prima não será eliminada pela mortal tela azul. Você tem várias opções de como salvar o estado de seu programa Java e a que escolher provavelmente vai depender de como planeja usar o estado salvo. Aqui estão as opções que examinaremos neste capítulo.

I
~.

Salvando o estado
Suponhamos que você tivesse um programa, digamos, um j ogo com uma aventura fictícia, que precisasse de mais de uma sessão para ser concluído. Conforme o jogo progride, os personagens ficam mais fortes, fracos , inteligentes, etc. e coletam e usam Ce perdem) armas. Você não quer começar do zero sempre que iniciar o jogo - seria necessária uma eternidade para colocar seus personagens em forma para uma batalha espetacular. Portanto, precisa de uma maneira de salvar o estado dos personagens e uma maneira de restaurá-lo quando voltar ao jogo. E já que você também é o programador do jogo, quer que o recurso de salvar e restaurar seja tão simples Ce à prova de falhas) quanto possível.

@

Opção um

Grave os três objetos serializados dos personagens em um arquivo
Crie um arquivo e grave três objetos serializados com os personagens. O arquivo não terá sentido se você tentar lê-lo como texto: IsrGameCharacter %gê8MÜlpowerLjava/l ang / String; [weaponst[Lj ava /lang/ String;xp2tlfur[Ljava.lang. String; '''''VÁE{Gxptbowtsword tdustsq-»tTrolluq-tbare handstbig axsq-xtMagicianuq -tspellstinvisibility

Se seus dados forem usados somente pelo programa Java que os gerou:

é9 Use

a serialização

Grave um arquivo que contenha ob jetos achatados (s e rial i zado s l . Em seguida, faça seu programa ler os ob jetos serializados no arquivo e converta-os novamente em objetos ativos, r esi dent es no heap.

Se seus dados forem usados por outros programas:
~ Grave um arquivo de texto simples
Grave um arquivo, com delimitadores que outros programas consigam analisar. Por exemplo, um arquivo delimitado por tabulação que um aplicativo de banco de dados ou planilha possa usar .

® Opção

dois

Grave um arquivo de texto simples
crie um arquivo e grave três linhas de texto, uma por personagem, separando as informações do estado com vírgulas:
50, .Elfo, flecha, espada, pó

É claro que essas não são as únicas opções. Você pode salvar dados no formato que quiser. Em vez de gravar caracteres, por exemplo, você pode gravar seus dados como bytes. Ou gravar qualquer tipo primitivo Java como um tipo primitivo Java - há métodos para a gravação de inteiros, longos, booleanos, etc . .Mas inoependentemente do método que você usar, as técnicas básicas de EIS serão muito parecidas: gravar alguns dados em algo, e geralmente esse algo é um arquivo em disco ou um fluxo sendo recebido de um a conexão de rede. Ler os dados é o mesmo processo invertido: ler algun s dados em um arquivo do di sco ou de uma conexão de rede. E é lógico que tudo que abordaremos nessa parte estará relacionado às situações em qu e você não estiver usando um banco de dados real. 302

200, Troll, mãos, grande machado 120, Mago, encantamentos, invisibilidade

ca pítulo 1t-;

serialização --" EIS de arquivo

Gravando um objeto serializado em um arquivo
Aqui estão as etapas para serializarmos (salvarmos) um obj eto. Não se preocupe em memorizar tudo isso : examinaremos com maiores detalhes posteriormente neste capítulo.

SupoIlÍlamos ~Je você tivesse que salvar três personagens de um j',gu •. •

Se o argui vo

\lMyGame .. ser'"

não existir/ ele será criado automaticaJuen te .

GameCharacter
int power String type Weapon[ 1 weapons getWeapon ( ) useWeapon ( ) increasePower () II outro s métodos

G)

Crie um objeto FileOutputStream
FileOutputStream fileStream = new FileOutputStream ( "MyGame. ser" ) ;

Cria um objeto FileOutputStream . FileOutputStream sabe como Se conectar c om (e c r iar ) um arquivo.

I

QD

Crie um ObjectOutputStream
ObjectOutputStream os

=

new ObjectOutputStream(fi l eStrearn);

ObjectOutputStream permitirá que você grave 'objetos, mas
não poderá se conectar

I

diretamente cam um arquivo . Ele precisa de um objeto lauxiliarr~ Isso se cbama ' encadear' um fluxo a outro.

®

Grave o objeto
os . writeObject(characte rOne ); ~ oS . writeObjec t (characterTwo); ~ oS .writeObject(characterThree ); ~

Serializa os objetos referenciados por characterOne, characterTWo e characterThree e grava no a rqui vo l\myGame .. ser'" ..

~ Feche ObjectOutputStream
o a rquivo seriaLizado será
mui to mais difícil para as pessoas lerem, porém sera muito mais fácil (e se~Jro) par a s eu programa restaurar o s tres objetos serializa dcs do que através da leitura do vaIar das variáve.is dos obj etos salvos em um arquivo d e texto. Por exemplo, i magine de quancas maneiras os valores poderiam ser acidentalmente lidos na Ordem erradal O tipo pode se t ornar UPÓ"'f em vez de
uEl.fú ll "
U1Uêt

os . close( ) ; ( -------------------------

Fechar o fluxo mais abrangente r echará os fluxos de nível inferior, portanto o objeto FileOutputStream ( e o arquivo) será fachado
automaticamente~

e.rlqua.nto c) El fo :;er.a

a .z."::'11a ..

voes está aqui>

303

objetos senaHzados

Transferências de dados dos flu~os de 1,.1_11]_ local parª outro

""Ii'#ifi1-'". :J.~,

,.
~

.~,

,;.

,......,

Fluxos de conexão representam uma conexão com uma origem ou destino (arquivo, soquete, etc.) enquanto fluxos de cadeia não podem se conectar por sua própria conta e devem ser encadeados a um fluxo de conexão.

o APl de EIS Java tem fluxos de conexão que representam conexões com destinos e origens como arquivos ou soquetes de rede, e flu xos de cadeia que só fun cionam quando encadeados a outros fluxos.
Geralmente, são necessários pelo menos doi s flu xos vinculados para que algo útil possa ser feito - um para representar a conexão e outro para chamar métodos. Por que dois? Porque os fluxos de conexão costumam estar em um nível muito baixo. FileOutputStream (um fluxo de conexão), por exemplo, tem métodos para a gravação de bytes. Mas não queremos gravar bytes! Queremos gravar o~ietos, portanto, precisamos de um fluxo de cadeia de nível mais alto. Certo, mas por que não ter apenas um fluxo que faça exatamente o que você quer? Um fluxo que lhe permita gravar objetos, mas em um nível inferior os converta em bytes? Pense na vantagem da 00. Cada classe faz bem apenas uma coisa. FileOutputStreams gravam bytes em um arquivo. ObjectOutputStreams convertem objetos em dados que podem ser gravados em um fluxo. Portantó, criaremos um FileOutputStream que nos permita gravar em um arquivo e vincularemos um ObjectOutputStream (um fluxo de cadeia) ao final dele. Quando chamarmos writeObjectO em ObjectOutputStream, o objeto será inselido no fluxo e, em seguida, será transferido para FileOutputStream, onde finalmente será gravado na forma de bytes em um arquivo. O recurso de criar diferentes combinações de t1uxos de conexão e de cadeia lhe proporcionará uma enorme t1exibilidade! Se fôssemos forçados a usar somente uma classe de fluxo, estaríamos à mercê dos projetistas do APl, esperando que eles pensassem em tudo que gostaríamos de fazer. Mas com o encadeamento, você pode criar suas próprias cadeias personalizadas.

destino

objeto é acha t ado ( s erializado) __________ é en c a deado a

obje t o é gravado na fo r ma de bytes n o ______ 011010 0 1 011 01 1 J. 001

~

-4~1 01 101 0010110111 001~

~

Obje t o

Obj e ctOutputS t r eam (um fluxo de cadeia)

Fil e OutputStream (um fluxo de ~onexã o) Arquivo

304

""''-.y ,.',
~,

...

~

serialização ; EIS de arquivo

o que acontece rea lmente a um objeto quando ele é serializado?

o Objeto no heap

e Objeto serial izado

Os objetos no heap têm estado - o valor das variáveis de instância do objeto. Esses valores tornam a instância de uma classe diferente de outra instância da mesma classe.
objeto com duas variáveis de inst:êncLa prilniti"l"as

Os objetos serializados salvam os valores das variáveis de instância, para que uma instância (objeto) idêntica possa ser reconstituída no heap.

011 010 0101101 11 001
capturados
,i nseridos
B
120

vEi ,lores das va..riáveis d$ .._._-"---instância de largura 8 altura fOT2-"'n .sal vos no -StYÇf'.l.1. vo nroo, Ee'!:~? ". junto COln mai$ algumas infoJ..'7rtaçõ(~$ de que a J'j11 precisa.rã para r'i!!staur:Jl':: c objet:c (como qual á c Os

i:luxo

seu

tipo

de

ç,lasse).

foo.ser FileOutputStream fs = new FileOutputStream( "foo. ser") ; ObjectOutputStream os = new ObjectOutputStream(fs); os.writeObject(myFoo); cria um F:i.leOutputStream que se con$ctar3 ccrn
foc " ser s , em seguida ;
encade~ia.

Foo myFoo = new Foo(); myFoo.setWidth(37); myFoo.setHeight(70) ;

i'

,arq~i,.l-i 170

wn Object:out:putStream e

solicita que ele grave o

objeto~

Mas o que É exatamente o estado de um objeto? _ O que precisa ser salvo?
Agora vai começar a ficar interessante. É muito fácil salvar os valores primitivos 37 e 70. Mas e se o objeto tiver uma variável de instância que for uma referência de objeto? E quanto a um objeto que tiver cinco variáveis de instância que forem referências de objeto? E se essas variáveis de instância do objeto tiverem elas próprias variáveis de instância? Pense no assunto. Que parte de um objeto é potencialmente única? Pense no que precisa ser restaurado para obtermos um objeto que seja idêntico ao que foi salvo. É claro que ele terá um local diferente na memória, mas não precisamos nos preocupar com isso. Só temos que nos preocupar em termos no heap um objeto com o mesmo estado que ele tinha quando foi salvo.

o que precisa acontecer para o objeto Car ser salvo de tal forma que possa ser restaurado a seu estado original?
.

o objeto Car tem duas variáveis de instância referenciam dois outros objetos.

~t.~.,......_
.

" +-

~.

Pense no que o objeto Caro

e como -

você pode precisar para salvar

-E o que acontecerá se um objeto Englnetiver ur~- referência de um objeto Carburator? O que existe dentro do objeto Tire[ )?

COr

oble,c-"

O que é necessário para salvar um objeto Car?
'jOCÔ

305

Quando um objeto é serializado, todos ps objetos qu_ ele _ e referencia nas variáyeis de - . --'-JjjJ :-instância também são serializados. E todos os objetos que esses objetos referenciam são serializados. E, por sua vez, todos os objetos que esses objetos referenciam são serializados ... E a melhor parte é que isso acontece automaticamente!
Esse objeto Kernel tem uma referência a um objeto de matri z Dog[]. O objeto Dog[] contém referências de dois objeto Dog. Cada objeto Dog contém uma referência de um objeto String e um objeto CoJlal'. Os objetos String têm um conjunto de caracteres e os objetos ColJar têm um int.

Quando você salvar o objeto Kernel, tudo isso será salvo!
./'

A serialização s al ,,"'a. a. ramificação

i.ntei.ra do
abjeto . Todos os objetos são referenciados pelas var i á veis ins tância , a. partir do abjeto que está

T o d os os

obje tos cêm que

ser salvos na ordem pars que o objeto Kernel possa ser restaurado cam esse estado.

sen do
serializado.

Se você quiser que sua classe possa ser serializada, implemente Serializable
A intelface Serializable é considerada como uma interface marcadora ou de tag, porque não tem nenhum método a implementar. Sua única finalidade é anunciar que a classe que está imp~ementando pode ser serializada. Ern_outraUJal él~ ras, os-objetos desse tipo poderão ser sal vos através do mecanismo de-seriaJização. -Se qualquer 'superclasse de uma classe puder ser seriali zaaa;' automaticamente a subclasse poderá ser serializada mesmo se não declarar explicitamente que implementa Serializable. (É assim que as interfaces fun.cionam sempre. Se sua superclasse "FOR-UM" tipo Serializable, você também será.) objectOutputStrearn.writeObject(myBox) i
~(-------

() qtl e q'.::.er q ue 8.ntre aqui IJE V'F i.mp l e.mentar Sêris. ; izeb':6 C~: fa~bara De campo de
eJ.~& ~;J.çã.o

imp o rt java , i o . *;

~
éJ "",,1[;;:-- e.ment~r ,;.:-~ _ ímp 2 e>.mel'ltS' Ser:;.E:.," ... á. ... .

,<

pub lic c la ss Box imp lement s Se ri a l i zable ( ~<-------------- !V"ecf...:.'!rr Ji"etoéc:
i nse:: i ~~
t

Q'lUi.!1ão
h~$.

você

es t á..rá

c:izél'::,,60 ii J1~1 ,
deSFe :.. ir
0'-;' ..

t~J;;O(l ~

S(.;,t~ ,i E

~ :_;:~ '

oh.ietos

priva t e i nt wid th ; priva te i n t h ei ght ; ~~--------------------------------publ i c v oi c1 s etWic1 th (in t w ) "Jic1th = w ; {

306

seria!ização
public void setHeight(int h) he ight ~ h;

EIS de arquivo

public static void ma in (String[] args) Box myBox = ne'N Box ( ) ; myBox . setWidth(50 ) ; myBox .s etHeight(20) ; try (

(

I~~~;~:'~ ::.;qC; .::.~,.:;~
t
~

_______________ ')'Ç'arat;õe.s sxceçoes FileOutputStream f s ~ ne'N FileOu tputStr eam ("foo . ser" ) ; ObjectOutputStream os = new ObjectOutputStream(fs); os . writeObject(myBox) ; os . close( ) ; Cria :1.m Obj"ctOutputSc.;;:sa.'ll encadli?ado ao } catch(Exception ex) fluxo de cone1e30. ex.printStackT rac e ( ) ; Solicita a ele que grave o objeto. __________________________________________
4 < ~

íI

A serialização é tudo ou nada.
Consegue imaginar o que aconteceria se algum estado do objeto não fosse salvo corretamente?

~

A ramificação inteira do objeto tem que ser serializada corretamente ou a serialização falhará. Você não pode serializar um objeto Pond se sua variável de instância Duck se recusar a ser serializada (não implementando Serializable).
import java . io . *;

os objetos p o nd podem ser public class Pond implements Ser i a lizab le ( ~----------------------------- sez·.ializados
private Duck duck

=

new Duck() ;

A c lasse .Pond t$m uma variáve l

de inst ância,

um objeto Du c k.

public stati c void main (String[] args) Pond mypond = ne'N Pond(); try { FileOutputStream fs = ne'N FileOutputStream ("Pond . ser" ) ; ObjectOutputStream os new ObjectOutputStream(fs); os.'NriteObject(myPond ) ; os . close () ; catch(Exception ex) ( ex.printStackTrace () ;
~<~

_______________________________________

Quando você s eri31izar Brxpond (um objeto Pon e), sua v ariável de instância Duck será serializada a u tornat2camente.

. do main na classe pond: Quando você tentar executar o meto
Nossa!! Duck não pode ser serializadaI Ela não implementa Serielizable, po=tan t o, ~~ando troe:? tenta.::- 5e;'~alízaZ' um obj~~o Fond? não conseguir~~ çorque a variáv>:?l ãe íI:3táacia
'DdC}l;:
<:::'~1. ~ra

:j~sse.
&

ob,ieto .não pode

Sé::::

~u~lic

clct~ b

DULk

{"

II o código de duck entra aqui

você està

<-)qUf lo-

307

,""-

Marque uma variável de instância como transiente se ela não puder (ou não for recomendável) ser salva.
Se você quiser que uma variável de instância seja ignorada pelo processo de serialização, marque-a com a pal avra-chave transient.
import java. n et . *; class Chat implements Serializable transient String currentID; ___________________
~(

transient: significa ~'não s alve essa variável durante a serialízação, ignore-a"

String use r Name; / / mais código

~(~---------------------------

a variável userName será salva como parte do es~ado do objeto durante a serialização .

Se você tiver uma variável de instância que não puder ser salva porque não pode ser serializada, marque-a com a palavra-chave transient e o processo de serialização a deixará de lado . Mas por que uma variável não poderia ser serializada? Talvez porque o projetista da classe simplesmente esqueceu de fazê-la impJementar Serializable. Ou porque o objeto dependa de informações específicas do tempo de execução que não podem ser salvas . Embora quase tudo nas bibliotecas de classe Java possa ser serializado, você não pode salvar coisas como conexões de rede, segmentos ou objetos de arquivo. Todos dependem (e são específicos) de alguma 'ocorrência' no tempo de execução. Em outras palavras, são instanciados de uma maneira que é exclusiva de uma execução específica de seu programa, em uma determinada platafonna e JVM. Quando o programa for encerrado, não haverá como reconstituir essas coisas de uma maneira significati va; elas sempre terão que ser criadas do zero.

Não existem

Perguntas Idiotas
Se a serialização é tão importante, por que ela não é o padrão para todas as classes? Por que a classe Object não pode implementar Serializable para que todas as subclasses sejam serializadas automaticamente? Ainda que a maioria das classes deva, e possa, implementar Serializable, você sempre poderá optar. E você deve tomar uma decisão consciente para 'ativar' a serialização implementando Serializable com base em cada classe que projetar. Em primeiro lugar, se a serialização fosse o padrão, como você a desativaria? As interfaces indicam funcionalidade e não falta de funcionalidade , portanto, o modelo do polimorfismo não funcionaria corretamente se fosse preciso dizer "implemente NonSerializable" oara informar para todo mundo que você não pode ser salvo. Por que eu criaria uma classe que não possa ser serializada? Há bem poucas razões , mas você pode, por

P:

exemplo, ter uma situação de segurança em que não queira um objeto de senha armazenado. Ou ter um objeto que não faça sentido salvar, porque suas principais variáveis de instância não podem ser serializadas, portanto não há uma maneira útil de fazer com que sua classe possa ser serializada . Se a classe que eu estiver usando não puder ser serializada, mas não houver uma boa razão para isso (exceto o fato de o projetista ter se esquecido ou então ser um estúpido), posso criar uma subclasse da classe 'incompleta' e fazer com que essa subclasse possa ser serializada? Sim! Se a própria classe for extensível (isto é, não for final), você poderá criar uma subclasse que possa ser serializada e simplesmente inserir essa subclasse em todos os locais onde seu código estiver esperando o tipo da superclasse. (Lembre-se de que ü poiirnorfisrno permite isso.) O que traz à tona outra questão interessante: o que significa a superclasse não poder ser serializada? Você é que levantou a questão - o que significa ter uma subclasse que pode ser serializada

P:

R:

R:

P: R:

P:

308

seria!ização

~

EI S de arqu ivo

em uma superclasse que não pode usar esse recurso?
Primeiro temos que examinar o que acontece quando uma classe é desserializada (falaremos sobre isso nas próximas páginas) . Resumindo, quando um objeto é desserializado e sua superclasse não pode ser serializada, o construtor da superclasse é executado como se um novo objeto desse tipo estivesse sendo criado. Se não houver uma razão vál ida para uma classe não poder ser serializada, criar uma subclasse que possa ser é uma boa solução.

R:

Uau! Acabei de perceber algo interessante ... Se você tornar uma variável 'transiente', isso significa que seu valor será ignorado durante a serialização. Mas o que acontecerá com ela? Resolvemos o problema de ter uma variável de instância que não pode ser serializada tornando-a transiente, mas não PRECISAREMOS dela quando o objeto for reconstituído? Em outras palavras, a finalidade da serialização não é preservar o estado de um objeto?
Sim , esse é um problema, mas felizmente há uma solução. Se você serializar um objeto, a variável de instância transiente será reconstituída como nula, independentemente do valor que tinha no momento em que foi salva. Isso significa que a ramificação inteira do objeto conectado a essa variável de instância específica não será salva. É claro que isso pode ser ruim , porque é provável que você precise de um valor que não seja

P:

nulo pa ra essa variável. Você tem duas opções : 1) Quando o objeto for reconstituído, reinicia lize essa variável de instância nula com algum estado padrão. Isso funcionará se o seu objeto desserializado não depender de um valor específico para essa variável transiente. Em outras palavras, pode ser importante que o objeto Oog tenha um objeto Coi lar, mas talvez todos os objetos Coliar sejam iguais, portanto não terá importância se você fornecer ao objeto Oog reconstituído um novo objeto Coliar; ninguém notará a diferença. 2 ) Se o valor da variável transiente for importante (digamos, se a cor e o modelo da variável transiente Coliar forem exclusivos para cada objeto Oog) , você terá que salvar os valores-chave do objeto Coliar e usá-los quando o objeto Oog for reconstituído para essencialmente recriar um novo objeto Collar que seja idêntico ao original.

R:

O que aconteceria se dois objetos da ramificação fossem iguais? Se você tiver dois objetos Cat diferentes no objeto Kennel, mas os dois referenciarem o mesmo objeto Owner. O objeto Owner será salvo duas vezes? Espero que não.
Excelente pergunta! O processo de serialização é suficientemente inteligente para saber quando dois objetos da ramificação são iguais. Nesse caso, só um dos objetos é salvo e durante a desserialização, e qualquer referência a esse objeto será restaurada . .

P:

R:

Desserialização: restaurando um objeto
A finalidade da serialização de um objeto é podermos restaurálo a seu estado original em algum momento posterior, em uma 'execução' diferente da JVM (que pode até não ser a mesma JVM que estava sendo executada no momento em que o objeto foi serializado). A desserialização é muito parecida com a serialização ao contrário.

desserializado serializado

i

j
Se o arquivo UMyGa.rne .. ser " - - - não existi r ; você capturará uma exceção.

~ Crie um FileInputStream
FilelnputSt ream " '" fileStre a m new F i le l n pu t Stream ("MyG a me . s e r") ; "t-- --

cria um objeto File I nputStream. Esse objeto sabe

\

~

como se conectax com um arquivo

exi.s-tente~

Crie um ObjectInputStream Ob j ectlnpu t St r eam os = new Ob j ect l nputStream ( fileStream);

_ _ _ _ _ __

-..YOb.:JJ~çt

1_
J

~ pld.. Strf?.~!

b·qz:m~-.fJ..r.a

.. ,

que

você _leia

()bjetos~

mas nãc poderá se c.:)!'lt;?ctar di.rst.â1t1.el1te com um
\...:~).Clexclc:~"

,,,rquivo .. Terá que ser enc" ds3.do ii W!l flu xo de :r:..$~;;S9 caso u.m FlleI.nputStrea.m~

você esta arlU'

ll>

309

(\

desserializando otljel\Js

leia os objetos vbj ec cone = os . r eadObj ec t ( ) ; - - - - - ~­ Object two = os.readObject(); Object th r ee = os . readObject() ;

\r-.?cê
{;JS

C~D!::.r~a'1.=

(

l'rà:~!':imc,

~bj~t0

rin

-F1~:.::~,;;

~ ~

cadô lztEtoáo reê..dObj€':::t () qt.!~ : i,re::: ~

P:JY't:a.71 to

'C

o

1.era na. mesma ordem em qIJ.e rora.."7l gravadoE ~ 'v"ocê câptura.l:~á U1ri8. eJcceção se tenter ler mais abjetos do que criot~.

~
.~~ ..
..;0.: ...... ,

Converta os objetos GameCharacter el f = (GameCharacter) one; Game Character troll (GameCharacter) two; GameCharacter magician = (GameCharacter) three;

o valor de retorno de readObject() é de tipo Object (como ocorre com ArrayLíst), portanto yocê terá que .qÇ?!"?:.~~~:r:..t...~. =.~ '?. para aqt!ele qtJe

.

sabe ser seu tipo

real~

~ Feche ObjectlnputStream
os . c los e();
~(~----------------------------------------

Fechar o fluxo mais abrangente fechará os de nív'el mais baixo , portan to .Filel'npu tS b :eam (e o ar~~ivo) será fechado aucomaticament e.

o que acontece durante a desserialização?
Quando um objeto é desserializado, a JVM tenta reconstituí-lo criando um novo objeto no heap que tenha o mesmo estado que o objeto serializado tinha na hora em que foi serializado. Bem, exceto pelas variáveis transientes , que são reconstituídas com nul o (para as referências de objeto) ou com valores primitivos padrão.

Essa etapa Lançará uma exceçâo se a JVT~ não conse~Jir encontrar ou carregar a classe !

w

i

I

I}
011010 0101101 11001

ob je to é lido em bytes

a classe é encontrada e carregada, as variáveis de instância salvas são reatribuídas

I~
----------~. .1 0ll010010110111001 t-é--e-n-c-- e- o-a d- a-d- a~~c: ~----__~-é lido por
i"
FileInputStream (um fluxo de conexão) ObjectInputStream (um fluxo de cadeia) Objeto

'.

~"

. S'

~,'

Arquivo

o o

o objeto é lido no fluxo .
(através das informações armazenadas com o objeto serializado) o tipo de classe

A fi do JVM determina objeto .

A JVM t enta encontrar e carregar a classe do ob jeto . Se n ão conseguir en con trar e/ou carregar a classe, a JVM lançará uma exceção e a desserialização falhará. Espaço é atribuído para um novo objeto no heap, mas o construtor do objeto serializado NÃO é executado! É claro que, se o construtor fo s se executado, ele restaur aria o objeto com o seu estado 'novo' original, e não é isso que queremos . Queremos que o objeto seja restaurado ao estado que tinha quando foi serializado e não quando f o i criado.

~ Se o objeto tiver uma classe que não possa ser serializada em algum local mais para cima em sua
árvore de herança, o construtor dessa classe sem serialização será executado junto com qualquer construtor que houver acima dele (mesmo se puderem ser serial i zados ) . Quando o encadeamento de construtores começar, você não podp.r~ i . nt:e r romp~. -lo, o que s i gn if ica que todas as superclasses, a partir da primei.ra que não puder ser serializada, reinicializarão seu estado.

~ As variáveis de instância do objeto recebem os valores do estado serializado. As variáveis
transient.es recebem um valo r tipos primitivos . nulo para referÊncias de objeto e padrões
(O,

falso,

etc . ) para

seria lização . EIS de arquivo mecanismo onde o objeto serializado pode ser 'carimbado ' com um URL que demonstre onde sua classe pode ser encontrada . Isso é usado no Remote Method Invocation (RMI) da Java para podermos enviar um objeto serializado como parte, digamos, do argumento de um método, e se a JVM que receber a chamada não tiver a classe , poderá usar o URL para buscá-Ia na rede e carregá-Ia , tudo automaticamente. (Falaremos sobre o RMI no Capitulo 17.)

Não existem

Perguntas Idiotas
Por que a classe não é salva como parte do objeto? Dessa forma você não teria o problema de saber se a classe pode ser encontrada.
Claro, a serialização poderia ter sido criada para funcionar dessa forma . Mas teríamos um desperdício e uma sobrecarga tremendos. E embora isso possa não parecer tão problemático em uma situação onde estivéssemos usando a serialização para gravar objetos no arquivo de uma unidade de disco rígido local, a serialização também é usada para enviar objetos através de uma conexão de rede. Se uma classe fosse empacotada com cada objeto serializado (que pudesse ser enviado) , a largura de banda seria um problema muito maior do que já é. No entanto, para que objetos serializados sejam enviados através de uma rede , na verdade há um

P:

R:

E quanto às variáveis estáticas? Elas são serializadas?
Não. Lembre-se de que estático significa "uma por classe" e não "uma por objeto". As variáveis estáticas não são salvas, e quando um objeto for desserializado, ele terá qualquer variável estática que sua classe tiver atualmente. Moral da história: não deixe que objetos que possam ser serializados dependam de uma variável estática que seja alterada dinamicamente! Ela pode não ser a mesma quando o objeto for reconstituído.

P: R:

Salvando e restaurando os personagens do jogo
impor t java . io . * ; public clas s GameSaverTest Cria algun s personagens . .• public s ta tic void main(String[] args) ( GameCharacter one = new GameCharacter(50, "Elf", new String[] ("bow", "sword", "dust"} ) ; GameCharacter two = new GameCharac ter (200, "Troll", new String [] ("bare hands", "big ax"}); GameCharacter three new GameCharacter ( 120, "Magician", new String[] ("spells", "invisibility"} ) ;
II imagine um código que faça coisas com os personagens que possam alterar os valores de seu estado

try ObjectOutputStream os os.writeObject(one); os.writeObject(two); os.writeObject(three); os.close(); catch(IOException ex) ( ex.printStackTrace(); one = null; two = null; three = null;

new ObjectOutputStream(new FileOutputStream("Game.ser"»;

~

Configuramos com nulo para não podermos acessar os
objet:.os
~~o

h e ap .

try ( ObjectInputStrearn is = new GarneCharacter oneRestore = GameCharacter twoRestore = GameCharacter threeRestore

ObjectInputStrearn(new FileInputStream("Garne . ser"»; (GarneCharacter) is.readObject() ; (GarneCharacter) is.readObject(); = (GameCharacter) is . readObject();

System. ·out.println("One's type : " + oneRestore . getType(»; System.out.println("Two's type : " + twoRest o re.getType(»; ~__ Sys tem . out . println ( "Three' s type : " + t~.reeRes tore . getType ( ) ) ; catch(Exce~tion e x ) ( ex.p r intStac~Trace() ;

t'-e r i:ii,.,·s para s.--.l-=>,; «e
func.-i.o.:::ou

311

exemplo de seria'lzação

A classe GameCharacter
import java .i o . * ·

_ ___ _ _ Grªvando um objeto String em um arquivo de texto
Salvar objetos, através da serialização, é a maneira mais fácil de salvar e restaurar dados entre as execuções de um programa Java. Mas em algumas situações você terá que salvar dados em um arquivo de texto simples. Suponhamos que seu programa Java tivesse que gravar dados em um arquivo de texto simples que algum outro programa (que pode não ser Java) tivesse que ler. Você poderia, por exemplo, ter um servlet (código Java executado dentro de seu .,' servidor Web) que pegasse dados de formulário que o usuário digitou em um navegador e os gravasse em um arquivo de texto que outra pessoa carregasse em uma planilha para análise. Gravar dados de texto (uma String, na verdade) é semelhante a gravar um objeto, exceto por gravarmos uma String em vez de um objeto e por usarmos um FileWriter em vez de um FileOutputStream (e você não terá que encadeá-lo a um ObjectOutputStream).
A aparência que os dados dos p ersonagens

public class GameCharacter implements Serializable { int power; String type; String[] weapons; public GameCharacter(int p, power = p; type = t; weapons = w ' String t, String[] w) {

public int getPower() return power;

{

public String getType () return type;

{

Essa é uma classe básica apenas para testarmos ii/. seri alização e, apesar de .não temos um jogO real, deixaremos ísso p ara você testar .
{

public String getweapons() String weaponList = for
}

(int i = O; i < weapons .l ength; i++ ) { weaponList += weapons[i] + o o .

teriam se você os gravasse como um arquivo

te~to ~üe

return weaponList;

pudesse ser íicio por pessoas.

50,Elf,bow,sword,dust 200,TroJl,bare hands, big ax 120,Magician,spells,invisibility

Serialização de objetos
r-

DISCRIMINAÇÃO DOS PONTOS
também o será. Isso significa que qualquer objeto referenciado pelas variáveis de instância do objeto serializado poderá ser serializado, assim como qualquer objeto referenciado por esse outro objeto ... E assim por diante. - Se algum objeto da ramificação não puder ser serializado, uma exceção será lançada no tempo de execução, a menos que a v3J.iável de instância que referencia o objeto seja ignorada. - Marque uma variável de instância com a palavra-chave transient se quiser que a selialização a ignore. Ela será restaurada com nulo (para referências de objeto) ou valores padrão (para tipos primitivos). - Durante a desserialização, a classe de todos os objetos da ramificação deve estar disponível para a JVM. - Você lerá os objetos (usando readObject) na ordem em que eles foram originalmente criados. - O tipo de retorno de readObject() é Object, portanto objetos desseriaii zados devem ser convertidos para seu tipo real. - As variáveis estáticas não são serializadas' Não tem sentido salvar o valor de uma variável estáti ca como parte do estado de um objeto específico, já que todos os objetos desse tipo compartilharão um único valor - () da classe.

- Você pode salvar o estado de um objeto serializando esse objeto. - Para serializar um objeto, você precisará de um ObjectOutputStream (do pacote java.io). - Os fluxos podem ser de conexão ou de cadeia. - Os fluxos de conexão podem representar uma conexão estabelecida com uma origem ou destino, normalmente um arquivo, uma conexão de soquete de rede ou o console. - Os fluxos de cadeia não podem se conectar com uma origem ou destino e devem ser encadeados a um fluxo de conexão (ou outro). - Para serializar um objeto em um arquivo, crie um FileOutputStream e encadeie-o a um ObjectOutputStream. - Para serializar um objeto, chame writeObject(theObject) em ObjectOutputStream. Você não precisará chamar métodos em FileOutputStream. - Para ser serializado, um objeto deve implem entar a interface Serializable. Se uma superclasse da classe implementar Serializable, automaticamente a subclasse poderá ser serializada, mesmo se não declarar especificamente que implementa Seriali::.able . - Quando um objelo for serializado, toda sua ramificação

serialização

'2

EIS de arquivo

Para gravar um objeto serializado: objectOutputStream.writeObject(someObject) ; Para gravar uma String: fileWriter.write("My first import java.io.*; class WriteAFile { public static void main (String[] try FileWriter writer = new FileWriter ( "Foo.txt"); writer.write("hello foo'"); writer.close(l;
~

'String to save"); Precísamos do pacote
pOI'
java~io

causa de PLler~fJ:.·_iter

argsl

(
Se o arq:.li vo aFoo ~ t:xt: U
O

.não

exis-cLrl' Fíleffriter

criará ..

o método ,,,.ri te () usa U.'lla String
Feche-o quando tiver termina.do!

_______________________________________________

catch(IOException ex) ex.printStackTrace(l;

~

TUDO que estiver relacionado à EIS deve ficar em rnn bloco try/ c a tch. Todas essas instruções poderã o lançar uma IOExcaption!! Antigas fichas pedagógicas 3 x 5

Exemplo de arquivo de texto: cartões pedagógicos eletrônicos
Lembra daqueles cartões pedagógicos que você usava na escola? Aqueles em que havia uma pergunta em um lado e a resposta atrás? Eles não serão de grande ajuda quando você estiver tentando entender algo, mas não há nada melhor para simples exercícios práticos e memorização mecânica. Quando você tiver que gravar um/ato . E eles também são ótimos em jogos comuns.

Criaremos uma versão eletrônica que terá três classes:
1) QuizCardBuilder, uma ferramenta de autoria simples para a criação e gravação de um conjunto de cartões pedagógicos eletrônicos.
QuizCard
QuizCard(q, question answer getQuestion (I getAnswer ( I aI

2) QuickCardPlayer, um motor de reprodução que pode carregar um conjunto de cartões pedagógicos e reproduzi-los para o usuário. 3) QuizCard, uma classe simples representando os dados do cartão. Percorreremos o código das classes criadora e reprodutora e você mesmo criará a classe QuizCard, usando essas informações. ------------------~

Whi<h university is featured j'n the
film 'Good Will Hunting"?

Vou
EjBObject.getPrimaryKeyO on a Session bean 's remote reference? M.I.T

-7""'\-

QuizCardBuilder
Terá um menu File com uma opção "Save" para a g r avação do conjunto de cartões atual em um arquivo de texto.

QuizCardPlayer
Terá um menu File com uma opção "Load" que carreg ará o conjunto de cartões de um arquivo de texto.

você está

313

gravando um ;;:'r] , lIVü ôe te.,jo

Quiz Card Builder (resumo do códioo)
, -- - -- ...., T

pubIic cIass QuizCardBuiIder p ubIic void go() /1 constrói e exibe a GUI
C~a5$ E i n t e r na private cIass NextCardListener impIements ActionListener ( public void ac t ionPerformed(ActionEvent ev) ii adiciona o cartão atual à lista e limpa as áreas de texto

Acionado quando o usu ário prés si onar o botão ~N$xt Card; ; significa que o usuári o quer armazenar esse certão na lista iniciar um novo cartão.

=

Classe interna private class SaveMenuListener implements ActionListener public vo id actionPerformed(ActionEvent ev) II abre a caixa de di álogo de um arquivo II permite que o usuário nomeie e sa l ve o conjunto

Acíonado quando o usuári o selecionar lSave' no menu File; significa ~Je o usuário quer salvar todos os cartões da lis t a atu al como um t conjunto; (por exemplo: Conjunto de Mec ânica Quântica, Tri vi a l idades de Hollywood, Regras J ava. et c .).
Acionado p e la seleçâo de
usuário q"Je1." inicial." um
'l!tleTJ! '
nOiro

Classe interna

pri vate class NewMenuListener implements ActionListener public void ac ti onPerformed(ActionEvent ev) II limpa a lis t a de cartões e as áreas d e texto

no menu FiLe; significa que o
c o njun to {portanto ,. limparemos a lista de cartões e as á reas de texto ) .

Chamado p or SaveMen uListenez ; executa a private void saveFile(File file} ç r a:n"ç.!l:o ·real do arquivo. I! iter a pela lista de cartões e grava cada um em um arquivo de texto II de uma maneira analisável (em outras palavras, com separações claras entre as par t es )

impor t import import import import

java . util . *; java .awt .event . * ; javax . swing . *; java.awt.*; java .i o . * ;

public class QuizCardBuilder { private private private private JTextArea question; J TextArea answer; ArrayList<QuizCard> cardList; JF rame frame;

public static void main (String[] args) Qu i zCardBuilder builder = new QuizCardBuilder(); builder . go( ) ;

public void go () II constrói a gui frame = new JFrame ("Quiz Card Builder" ) ; JPanel mainpanel = new Jpanel(); Font bigFont = new Font("sanserif", Fon t.BOLD, question = new JTextArea(6,20}; question . setLineil'lrap (true) ; question . setWrapSty leWord(t r ue) question . setFont (b igFont) ;

24) ;

~l'odQ es se c ódi g o é refE:ren te ii. GUI_ Nada de especi al, porém '\.-ocê pode ~erer e xam i 12e.r o codigo de Men u Bar . Menu

JS croll Pane qScroller = new JScroIIPane(question}; qScroller .se tVerticaISc r oIIBarPolicy(ScroI IPan eConstan ts . VERTICAL_ SCROLLBAR_ALWAYS); qScroller . setHo :ci z ontalScrollBar Pol icy (ScrolIPan e Constants. HORIZONTAL_ SCROLLBAR_NEVER) ; answer = ne'" JTextArea ( 6 , 2 O) ; answer . se tL ineWrap (t rue) ;

serialização . EIS de arqu ivo

answer . setWrapSty l e Wo rd(true) ; answer . setFont (bigFont) ; JScrollPane aScroller = new JScrollPane(answer); aScroller . setVerticalScrollBarPolicy(ScrollPaneConstants . VERTICAL_SCROLLBAR_ALWAYS); aScroller . setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ NEVERI JButton nextButton cardList

=

new JButton ("Next Card");

=

new ArrayList<QuizCard>(I ; new JLabel("Ques t ion:"I; new JLabel ("Answer: ,, ) ;

JLabel qLabel JLabel aLabel

mainPanel.add(qLabel) ; mainPanel.add(qScroller) ; mainPan e l . add(aLabel) ; mainPanel.add(aScroller) ; mainPanel.add(nex tButton); nextButton.addActionListene r(ne w NextCar d Li stener()) ; JMenuBar menuBar = new JMenuBa r (l; JMenu fileMenu = new JMenu("File"); JMenultem newMenultem = new JMen ul t em ( "Ne w" ) ; JMenuI tem s aveMenuI tem = new JMenuI tem ( "Save" ) ; n e wMe nult e m. addAc t ionL i st e ner(new NewMenuLis t ener()); saveMenultem. addActionLi s t e ner(new SaveMe nuListener()); fileMenu . add (newMenultem) ; fileMenu.add(saveMenu lt em) ; me nuBar . add(fileMe nu) ; frame . setJMenu Bar (me nuBar) ; frame . getConten tPane() . add(BorderLayout . CENTER, mainPanel); frame.setSize(SOO,600) ; frame. setVisible(true ) ;
Criamos uma barra de menus e um menu File a, em seguiãa; inserimos os itens de menu
.Adicionamos o menu à barra. de

menus e

solicit~~os

à moldura
de
Jt1êX1U

que ~ uS<a ~

Os

i

teJ1S

podem aciona r

um Action Even;t"

pub l ic class NextCardListener implements ActionListener publ i c void actionPerforme d(ActionEvent evl ( QuizCard card = new Qu i zCard(question . getText(), ca r dL i st . add(card) ; c l earCard() ; answe r. getText() I;

,
'4

p u blic class SaveMenuListener implements ActionListener { public void actionPerformed(Act i onEvent evl ( QuizCard card = new Qu izCard(qu estion . getText(), answer . getText()); cardLi s t . add (c a rd) ; Abre a caixa da diálogo de -um arquivo €i aguarda nessa l,;Ln.t~a até o usuário se l ecion ar
-. Save".
~:roda

li '

a

navega.ção peJa

caixa de diá l ogo a a Gelação de
um arqu,ivoJ' etc ~ , s erá .feita .para você pcr JFileCbooseJ: 1 É realmente muito fácil~

public class NewMenuListener implements ActionListener public void actionPerformed(Ac t ionEvent evl { cardLi s t .. clear ( ) clearCard() ;

o método que executa
. eal r do arquivo

iS

gravaçf!io
pelo

(ç~~a..mf1do

A
A
~.

manipulador de eventos de Savel"'lenuListene1:~). O argume. :tto l é o cbj,;:to \ F'ile / que c- usu:'ário

A

private void clearCard() question . setText("") ; answer . setText("") ; question . requestFocus() ;

está

sal vando ~

Exa..:minare.:;"Uos

a.
u

cla sse 2i l e n.a próxima

~;:ni,git1â

--k--.
~

LU-1l .DenTO J.~ L l a'Nri ter '

paJ..-a c o :r.nZl,. : 1

,?

h

private void saveFile(File file) try Buffe r ed,'!riter ",rit e r = new Bu fferedlrlriterlnew Fil e \'Jr it e rlfil e));

a g ra v açã o :mais efi.ciBnt t;?, ( Fala;cBIr1o s s ob.re w o {;t~l gulnd~ lss
pl1go1. na s fre.l.'1 L: € " )

,b-,
.

\loce está

315

continuação do código
for(QuizCard card:cardList)

':,Y::-itC:r- . ~,iv·:;:-itE{Ca:Ld.~·get.Que-scioíl()
writer.write(card . getAnswer() writer . close() ;

+

7 ");

t------ ------..
) ou t ") ;

Percorremos a Arra)rList de cartôés e os g:raVêt1üaS I um carcão por linha~ com a pergunta e a resposta separadas pelo símbolo n/I" e., em seguida , adicionamos um caractere de nova linha ("\n").

+ " \n " ) ;

catch(IOException ex ) System . out . prin tl n("couldn't write the cardLi s t ex. p ri nt S ta c k Trac e () ;

A classe java.io.File
A classe java.io.File representa um arquivo existente em disco, mas não o conteúdo do arquivo. Como assim? Considere o objeto File como algo mai s próximo a um nome de arquivo (ou até mesmo um diretório) em vez de ser o arquivo real propriamente dito. A classe File não tem, por exemplo, métodos de leitura e gravação. Algo MUITO útil com relação a um objeto File é que ele oferece uma maneira muito mais segura de representar um arquivo do que apenas através do uso de um nome de arquivo de tipo String. Por exemplo, a maioria das classes que usa um nome de arquivo de tipo String em seu .construtor (como FileWriter ou FilelnputStream) pode usar um objeto File em seu lugar. Você pode . construir um objeto File, verificar se tem um caminho válido, etc. e fornecer esse objeto a FileWriter ou FiJelnputStream.
Um obje to File represento. o nome e o ca:minhú d(~ um arqui.vo Ol] diretório existente em disco, por exemplo:

fUs2rs/Kathy/Data/GameFile.txt Mas NÃO representa ou concede acesso aos dados existentes
D,O a.:rql.J.i "\TO!

Algumas coisas que você pode fazer com um objeto File: .

(!) Crie
~ Crie

um objeto File que represente um arquivo existente. F i l e f = new File ( "MyCode . txt" ) ;

j~"

~

um novo diretório. File dir = new F i le("Chapter7"); di r . mkdir () ; um diretório. (dir . isDirectory ()) { St r ing[] d i rCon t ent s = dir . l i s t () ; for ( i n t i = O; i < d i rContents . length; i++ ) ( System. out.print l n (dirContents[i]);

Um endereço NÃO é o mesmo que o local propriamente dito! Um objeto File é como um endereço .. . Ele representa o nome e o local de wn arqu í vo específico, mas não é o arquivo real.

~ Liste o conteúdo de
if

o objeto File representa o nome do arqui1ro \\GameFile. txt'T

GameFile.txt
50, Elfo, fl e cha , espa da, pó 200 , Tr ol l, mão s, g rande machado 12 0, Mago, encan t amentos, inv i sibilidad e

~ Capture o caminho absoluto de

um arquivo ou diretório.

Sys tem.out . println(di r .ge tAbsolutePath());

~ Exclua

um arquivo ou diretório (retornará verdadeiro se for bem-sucedido) . boolean isDeleted = f . delete();

T
Ele NÃO representa (ou con cede aceso direto) os dados existentes no arquivo!

serialização e EIS de arquivo

A beleza dos buffers
Se não houvesse buffers, seria como fazer compras se m um carrinho. Você teria que carregar cada co isa até seu carro, uma lata de sopa ou um rol o de papel higiênico de cada vez.

Os buff$zS lhe farnece r ãc Um l ocal :ampo= áric ce ar.maz~nament o para que você ~grJpe coisa s até o c ontêí n e r (como o ca r r i nho) "f.ica r cheio . Va c a t e rá qu e fazer
b em menos vi agen s quando usar um b uf fer.

destino

a St r ing é ins erida em um b u ff er com o utras Str i ngs

Qu ando o buf f er f icar c he io, a s Strings se r ão todas gr avadas no

"
Aspe n

\\Boulder"
S t ring

é g r a vad a em

~

\\Boulder" "Aspen" "Denver"

é encadeado a

.... .

"Aspen Denv er Boulder"

---... .

Denver Boul d er

Bu fferedW rite r (um f l uxo d e cadeia que f uncl ona com carac t e r e s )

( um

FileW te r ri f l uxo de c on exão qu e grava c aractere s e nao byte s )

Arquivo

~:

~~.
Buf f eredW riter writer new Buff e redWriter (ne w F il e W t er (a F ile )); ri

Obsez-ve ~Je não precisa remos n em ter uma refe renci a do ob j eto Fil e Writer . A única coisa com a qual nos ~ preocuparemos é BufferedWr iter, por~Je esse é o objeto em que chamaremos mét odos, e quando f e charmos Euferr eàWri t er , ele s e encarreg ará do resto d a cadei a.

o interessante nos buffers é que eles são muito mais eficientes do que o trabalho sem sua utilização. Você pode gravar em um
arquivo usando somente FileWriter, ao chamar write(someString), mas FileWriter gravará cada item que for passado para o arquivo sempre que eles forem passados. Isso será uma sobrecarga desnecessária e indesejada, já que cada acesso ao disco é uma tarefa difícil se comparada com a manipulação de dados na memória. Ao encadearmos um BufferedWriter a um FileWriter, BufferedWriter armazenará tudo que você gravar até ficar cheio. Só quando o buffer ficar cheio é que o objeto FileWriter será realmente solicitado a gravar no arquivo existente em disco. Se você quiser enviar os dados antes do buffer ficar cheio, estará realmente no controle. Simplesmente descarregue-os . As chamadas a writer.flushO dirão "envie tudo que estiver no buffer, agora!"

Lendo um arquivo de texto
Ler texto em um arquivo é simples, mas dessa vez usaremos um objeto File para representar o arquivo, um FileReader para executar realmente a gravação e um BufferedReader para tornar a leitura mais eficiente. A leitura ocorrerá ao percorrermos as linhas em um loop while, terminando o loop quando o resultado do método readLineO for nulo. Esse é o estilo mais comum de leitura de dados (quase tudo que não for um objeto Serialized): ler o conteúdo em um loop whil e (na verdade o teste de um loop while) e terminar quando não houver mais nada a ser lido (o que saberemos, uma vez que o resultado do método de leitura que estivermos - -- usando se rá nulo).
Um a r qu ivo com d uas l inhas de t e ;l'!to

Quanto é 2 + 2? / 4 Quanto é 20 + 22? / 42

MyText.txt
você esta aqui
~

317

lendo
import java . io . * ;
~--------------_._----

class ReadAFile { public static void main (String[] args)
try

F ile myFile = new File ("MyTex t . txt") ; FileReader fileReader new FileReader(myFile); BufferedReader reader
cria tI.ma variá"tr~l de String
~ara

new

-E-----Buffe r edReader (fileReader); 'E- -'

Um FileReaãer é um =luxo de conexâo p~ra cer&ct eres, que se conecta com lli~ ar~Ji~o de texto.
g~~caó.ei. a (> Fil.eReade:1." a um 3ufreredReader para uma leitura mais eficiente. Ele voltará ao a rqu ivo para ler somente quando o buffer est:iv·er "razio (porque

armazenar cada linha

q-,zando ror lida

1

o prOftremél já terá lido tudo).

String l ine = nul l; while « line = reader . readLine()) != null) System.out . println(line); ( - - - - - - - - - -- - - -- -- reader.close (); catch(Exception ex) ex.printS t ackTrac e( );

Essa i nstrução está dizendo " Leia Ul"..a linha de texto e atri.bu ~- a à "\T ariável d e St rin.g 'l i ne '., ,Enq'liaZ1ta es sa ,,\rariável
não r::)r nÜ"i a' - (por HAVER algo a

ser lião) exiba a linha que acabou de ser lida". Também há outra mane ira de di zer isso, HEnq'..1anto e:inda

bouver lei a e

~ inhas

a serem lidas,

exiba. -a s"~

Quiz Card Player (resumo do cód igo)
public class QuizCardPlayer public void go() II constrói e exibe a gui

cla ss Nex tCar dListener implements ActionListener ( public void ac tionPe rf ormed (Ac ti onEvent e v) ( II se essa for uma pergunta , mostre a resposta, caso contrário exiba a próxima pergunta II c onfigura um flag que indicará se estamos vi sualizando uma pergunta ou r e sposta

class OpenMenuListener i mplements ActionListener public void act i onPe rf ormed (Ac ti onEvent ev) ( II abre a ca ixa de diálogo de um arquivo II p ermite que o usuário navegue e selecione um conjunto de cartões a ser aberto

private vo i d loadFile(Fi l e file) II deve construir uma ArrayList de ca rtõ es, len do -os em um arquivo de t ex t o II c hama do pelo man ipulador de eventos de OpenMenuL i stener, lê O ar quivo uma linha de cada vez II e s olicita ao método makeCard () que crie um novo cartão a part ir da linha II (uma linha do campo conterá tanto a p e rgunta quanto a resposta, separada s por um símbolo " l U)

private v oid makeCard(String lineToParse) II chamado pelo método loadFile, pega uma linha do arqu i vo de texto, cria um novo QuizCa r d II a divide em duas partes - pergunta e respo sta II e o adi ciona à ArrayL ist chamada CardList

import java.util . *; import java . awt . event . *;
import java:>: . s wing.*

impore java . awt . *; import java . i o . * ·

318

-.< "

serialização e EIS de arquivo
public class QuizCardPlayer { private private private private priva te pr i vate private private JT e xtArea display; JTextArea answer; ArrayList< Qu izCard> cardList; QuizCard currentCard; int currentCardlndex; JFrame frame; JButton nextButton; boolean isShowAnswer;

Apenas código de GUX; Nada de especial

public static void main (S tring [] args) QuizCardPlayer reader = new QuizCardPlayer(); reader.go() ;

public void

go()

II constrói a gui
frame = new JFrame ("Quiz Card Player"); JPanel mainpanel = new Jpanel( ) ; Font bigFont = new Font ( "sanserif", Font.BOLD, display = new JTextArea(lO,20); display.set Font(b igFont) ; display.setLineWrap(true); display.setEditable ( false); JScrollPane qScroller = new JScrollPane(disp lay); qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_ SCROLLBAR_ ALWAYS); qScroller . setHorizontalScrollBarPolicy(ScrollPaneConstants . HORIZONTAL_ SCROLLBAR_NEVER); nex t Button = new JButton ("Show Question"); mainPanel.add(qScroller); mainPane l .add (n extButton); nextButton.addActionListener(new NextCardListener(»; JMenuBar menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("File"); JMenultem loadMenultem = new JMenultem ( "Load card set"); loadMenultem.addActionListener (new OpenMenuListener (»; fileMenu.add(loadMenultem); menuBar.add ( fileMenu ) ; frame.setJMenuBar(menuBar) ; fr ame . getContentPane() .add(BorderLayout.CENTER, mainPanel); frame.setSize (640, 500 ); frame.setVisible(true);

24);

II fecha go
public c lass NextCardListener impl ements ActionListener public void actionPerformed(ActionEvent ev ) { if (isShowAnswer) ( II exibe a resposta porque a pergunta Ja foi vista display.setText(currentCard . getAnswer(»; nextButton. setTe xt ("Next Card"); isShowAnswer = false; else { II exibe a próxima pergunta if (cu rrentCardlndex < cardList.size (» showNextCard () ; else ( II não há mais cartões! display.setText("That was last card"); nextButton . setEnabled(false) ;

Verifica o flag booleano isShowA."swer para saber se atualmente está sendo exibida uma per~Jnta ou uma reposta e faz o ~Je for apropriado

dependendo do que for retornado.

você esta aqUi

lo-

319

dividindo strings _

public class OpenMe nuL i stene r implements ActionL i stener puolic voio actionPerformed (Ac tlonEven C ev ) ( JFileChooser fil eOp en = new JFileCh oo ser( ) ; fileOpen _showOpenDialog(frame) ; loadFile(fileOpen _getSelectedFile()) ;
/

private void loadFile ( File file ) cardList = new ArrayList<QuizCard>(); try { BufferedReader reader = new BufferedReader (new FileReader (file) ); Str i ng line = nu ll; whi l e « lin e = reader _rea dL in e ( )) ! = null) makeCard (I ine ) ; reader _close(); catch(Exception ex) System _o ut. pr i nt l n("cou l dn't read t he card f ile"); ex _pr intStackTrace();

I

F..bT€.!: a

caixa de

é.ii:.~ogo

dos

arq-üivos e permite que o u$uári o xtavegue e selecio:rl8 o arqJivo e ser aberto.

Cria

um EufEereãReader
a um no'p"o

encadeado

Fi LeReader r

fornecendo ao

Fi1.eReader o abjeto File ~~e o usuário se~ecíonou na caixa de diá~ogo Abrir. Lê uma linha de cada ve z r makeCerd ( )
rea~meI1t:e

passando-a para o método r Cl'.le a analísará €: con.'Terterá
em um QuizCard

adicior,;.ando-o

ii .ArrayList:.

II agora é h o r a de i niciar exib i ndo a primeira carta showNex tCa rd () ;

private void makeCard(String lineToParse) String[] resul t = l i neT oPars e _split(" I "); ~._-----------­ QuizCa r d card = new QuizCard(result[O) , result[l)J; cardList_add(card); System. out _println ( "made a ca r d");

Cada linha de texto corresponde a um único
ca.rtão pedagógico", mas
~J~

anal iser a

per~unt~

e a

privat e void showNex tCard ( ) currentCard = cardList _get(currentCa r dlndex); currentCardl ndex++; display . setText{currentCard . getQuestion()) ; nextButton . se t'T' ext ("Show Answer"); isShowAnswer = true;
II fecha class

:espo5ta como partes sep~radas. Usamos o método split () deStrí ng para d i vidir a Ii~~a em duas fichas (uma para a pergunta e outra para a resposta). EY~~naramos o método sp~it() na próxima página.

Dividindo com o método split( ) da classe String
Suponhamos que você tivesse um cartão pedagógico como este:
Salvo em um arquivo de perguntas como esse:
1:'

o que resulta de azul + amarelo? /verde
O que resulta de vermelho + azul? / roxO ,~

Como você separaria a pergunta e a resposta?
Q uando você le r () arqu ivo , a pergunta e <I respos ta estarão agrupadas na mesma linha. separadas pe la harra diagonal "/" (porque fo i assim que g ravamos o arq ui vo no cód igo de Qui zCardB uilder) _

320

serialização

EIS de arqu ivo

o método split( ) da classe String

permitirá que você divida uma String em pedaços.

" Usar o método splitO é o mesmo q ue d izer "me dê um separador e dividire i todos os trechos dessa String para você inserindo-os e m Llma m atri z de Strings" .

ficha1

separador
~\TCJ

ficha2
apl_icati t-1ue U.ffk{
d4~ 2t:.izC';~LdPlay~er~
BL?ê_r9-t.:}(2

e

S t ring toTest

"O que resulta de azul

T

amarelo? j verde ";

5.s,.;.:':m

~<.L{.t..fl,2

<.[udl1do

.1. LCki

no

~.cqniyo,

o
String[] result

método :rpLit

(2

peg2L1::',8 2

~i/"

.t.iJ

a
{nt7~s s e

UEL:srA pa.::::a di v_1.di.I

Strin;J em

=

toTest . split("j");

C/fi$O} de:':! pedaços,. [l\'cta: split() yod-e ..s.er usado para MUTTJ1S outras

COi32S

for

(String token : result) ( System . out . println(tokenl ;

pa~',n

a1.ém da utilização -que demos 6_1$ a<~-u i Pod,,'-)! executar d.iv.i sões
ccmpla:t:!.2. $ com f.il
t1.~OS.l

2xtr-eJtl.rurif:":?l1t.B

CUr:l.flqas"

etc j

P'2r7':0,rr~~rn:acri

z

<f+

,~!'t'i_b<$

cad<'3.

ficl~a.
.,,?)-

(pe-daço! ..

Nas::>",?

eÃ~plo.f

bá apenas

re.sunl t;,ri d!if azotLI -+

Não existem

Perguntas Idiotas

.;4~~.

-1;

Certo, examinei o APl e há cerca de cinco milhões de classes no pacote j ava.io. . \:.. Como saber quais usar?

P: R

E quanto às novas classes nio de EIS adicionadas na versão 1.4? As classes java .nio trazem um grande aumento no desempenho e se beneficiarão mais dos recursos nativos da máquina em que seu programa estiver sendo executado. Um dos novos recursos-chave do pacote nio é que você terá controle direto sobre os buffers . Outro recurso novo é a EIS sem bloqueio, o que significa que seu código de EIS não ficará parado esperando se não houver nada a ser lido ou gravado . Algumas das classes existentes (inclusive FilelnputSteam e FileOutputStream) se beneficiam de alguns dos novos recursos , indiretamente. Mas as classes nio são mais complicadas de usar, portanto, a menos que precise realmente dos novos recursos, talvez seja melhor você usar as versões mais simples que empregamos aqui. Além disso, se não tiver cuidado, o pacote nio pode levar a uma perda no desempenho. A EIS sem uso do pacote nio costuma ser adequada para 90% do que fazemos normalmente, prin cipalmente se você for iniciante em Java . Mas você pode facilitar sua introdução às clélsses nio, usando FilelnputStrea m e acessando seu canal através do m étodo -getChannel O (adi cionado FilelnputStream a partir da versão 1.4).

P: R:

---!4--

• ..:' : O APl de EIS usa o conceito de _==- ~_ 'encadeamento' modular para que você possa ~ vincular fluxos de conexão e fluxos de cadeia ~ (também c~amados de fluxos de 'filtro') em uma '.",l grande variedade de combinações para obter . praticamente o que quiser. As cadeias não têm que parar em apenas .J!i. dois ~íveis; você pode vincular vários fluxos de "1 cadela uns aos outros para obter o volume . correto de processamento que precisa . .~... Quase sempre, no entanto, você usará as " , mesmas classes. Se estiver criando arquivos de !. texto, provavelmente só vai precisar de ~ BufferedReader e BufferedWriter (encadeados a FileReader e FileWriter). Se estiver criando ~ objetos serializados, poderá usar {f ObjectOutputStream e ObjectlnputStream ~ (encadeados a FilelnputStream e ,. FileOutputStream). Em outras pa!a\/ ras, 90 % do qu@v C)çê___ _ _ ___ fará com a EIS Java pode usar o que já abordamos .

. rlté

1

mi

a

321

(\

salvando objGtos

-- - -OISCRTMfNA-çAO DOS PONTOS - - - - Para gravar um arquivo de texto, comece com um t1uxo de conexão File Writer. - Encadeie o FileWriter a um B ufferedWri ter para obter mai s eficiência.
A Java

- Um obj eto Fi le representa o arquivo de um caminho específico, mas não o seu conteúdo real. - Com um objeto File você pode criar, percorrer e excluir diretórios. - A maioria dos flu xos que pode usar um nome de arquivo de tipo String também pode usar um objeto Fil e e pode ser mais seguro empregar esse objeto. - Para ler um arquivo de texto, comece com um fluxo de conexão FileReader. - Encadeie o FileReader a um BufferedReader para obter mais eficiência.

. . violetas são bissextas. As rosas vêm pnmelro,

. ravação são apenas para texto. As classes de leItura e g

l ==::===::::=====:""":!=:::::====~:::"==r -Para analisar um arquivo de texto , você precisa se certificar se ele foi
~

gravado com alguma maneira de reconhecermos os diferentes elementos. Uma abordagem comum é o uso de algum tipo de caractere que separe as partes individuais.

- Use o método splitO da classe String para dividir uma String em fichas individuais. Uma String com um separador terá duas fichas. uma em cada lado do separador. O separador não é considerado uma fich.a .

Identificação da versão: um grande problema da serial ização
Agora você sabe que na verdade a EIS Java é muito simples, principalmente se usarmos as combinações mais comuns de conexão/cadeia. Mas há um problema com o qual você deve realmente se preocupar.

o controle

da versão é crucial! Alterações em uma classe que não costumam gerar problemas:
Adicionar novas variáveis de instância à classe (os objetos existentes serão clesserializaclos com valores padrão para as variáveis de instância que eles não tinham quando foram serializados). Adicionar classes à árvore de herança. Remover classes da árvore de heranaça. Alterar o nível de acesso de uma variável de in stância não impedirá que a desserialização atribua um valor à variável. Alterar um a variável de in stância de transiente para não-transiente (objeto S já serializados simplesmente terão um valor padrão para as vari áve is que eram lran :,; ienles).

Se você serializar um objeto, precisará da classe para desserializar e usar o objeto. Certo, isso é óbvio. Mas o que talvez não seja tão óbvio é o que acontecerá se você alterar a classe nesse ínterim. Imagine tentar reconstituir um objeto Dog quando uma de suas variáveis de instância (nãotransiente) tiver sido alterada de um tipo double para um a String. Isso violará enormemente as regras Java de segurança de tipos. Mas essa não é a única alteração que pode atingir a compatibilidade. Pense nos iten s a seguir:

Alterações em uma classe que podem afetar a desserialização:
Excluir uma variável de instância. Alterar o tipo declarado de um a variável de instância. Alterar uma variá,;el de instância não-transiente para transiente. Mover uma classe para Cima ou para baixo na hierarquia de herança. Alterar uma classe (de qualquer loca l da ramificação do objeto) que pode ser serializada para não-serializada (removendo ' implements Serializable' de uma declaração de classe) . A Iterar uma varicível de instância para esléÍtica.

serialização e EIS de arquivo

(!)

Você cria uma classe Dog

Usando serialVersionUID
Sempre que é serializado , o objeto (e todos os outros objetos de sua ramificação) é 'carimbado ' com um número identificador da versão de sua classe. A identificação é chamada de serialVersionUID e é calculada com base nas informações sobre a estrutura da classe. Quando um objeto está sendo desserializado, se a classe tiver sido alterada desde a serialização, ela poderá ter uma serial VersionUID diferente e a desserialização falhará! Mas você pode controlar isso.

iddntifica qào
da v lE.rsão da

cla. sse
#343

Dog.class

~ Você serializa um objeto Dog usando
essa classe

Se você acha que há ALGUMA possibilidade de sua classe evoluir, insira uma identificação de versão seqüencial nela.
o ebjeto é
carimbaão com a versão #343

você altera a classe Dog
ltrllbl.
l~:nO!.

lt .• Õ

lúlOH'C"U.l>:l .e \l

identificação
da versão da

Quando a Java tenta desserializar um objeto, ela compara a serialVersionUID do objeto serializado com a da classe que a JVM está usando para desserializá-lo. Por exemplo, se uma instância de Dog tiver sido serializada com uma identificação igual a, digamos, 23 (na verdade uma serialVersionUID é muito mais longa), quando a JVM desserializar o objeto Dog primeiro ela comparará sua serialVersionUID com a serialVersionUID da classe Dog. Se os dois números não coincidirem, a JVM assumirá que a classe não é compatível com o objeto serializado e você capturará uma exceção durante a desserialização. Portanto, a solução é inserir uma serialVersionUID em sua classe e, assim, quando a classe evoluir, a serialVersionUID permanecerá a mesma e a JVM pensará "ótimo, a classe é compatível com esse objeto serializado" ainda que na verdade a classe tenha sido alterada. Isso só funcionará se você tiver cuidado com as alterações feitas em sua classe! Em outras palavras, você está se responsabilizando por qualquer problema que possa surgir quando um objeto mais antigo for reconstituído com uma classe mais nova. Para obter uma serialVersionUID para uma classe, use a ferramenta serialver que veio com seu kit de desenvolvimento Java.

classe

Dõg.class Você desserializa um objeto Dog usando a classe alterada

lillOUllHJ1}l l'l

ltlU

.1} ~

,nm,r; .:
~O~Ó!!;t!

~"lOln-c