Apostila de java na pratica

432

Click here to load reader

description

Teste apresentacao

Transcript of Apostila de java na pratica

Page 1: Apostila de java na pratica

UNIVERSIDADE FEDERAL DE VIÇOSA

DEPARTAMENTO DE INFORMÁTICA

JAVA NA PRÁTICA

Alcione de Paiva OliveiraVinícius Valente Maciel

2002

Page 2: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

1

SumárioCapítulo I - Introdução ....................................... 6

CONVENÇÕES........................................................................................................................... 10Capítulo II - Programação Orientada a Objetos .................. 11

CLASSES E OBJETOS E LINGUAGENS DE PROGRAMAÇÃO ......................................................... 12Ocultando de Informação................................................................................................... 16Especialização e Herança .................................................................................................. 17Sobrescrita, Sobrecarga e Polimorfismo............................................................................ 18

INTRODUÇÃO À DIAGRAMA DE CLASSES ................................................................................. 20Diagrama de Classes.......................................................................................................... 20

Capítulo III - Introdução à Linguagem Java ..................... 27PALAVRAS RESERVADAS ......................................................................................................... 30LITERAIS .................................................................................................................................. 31SEPARADORES.......................................................................................................................... 34TIPOS DE DADOS....................................................................................................................... 35

Tipos de dados simples....................................................................................................... 35Tipos de dados compostos .................................................................................................. 37

CONVERSÃO DE TIPOS.............................................................................................................. 41OPERADORES ........................................................................................................................... 42

Expressões e Precedência entre Operadores ..................................................................... 50COMENTÁRIOS ......................................................................................................................... 51BLOCOS E ESCOPO ................................................................................................................... 52ESTRUTURAS DE CONTROLE .................................................................................................... 53

Seleção ............................................................................................................................... 53Repetição............................................................................................................................ 57break e continue ......................................................................................................... 60

ARGUMENTOS DA LINHA DE COMANDO.................................................................................... 61ASSERT (ASSERTIVAS) ............................................................................................................. 63

Sintaxe e semântica ............................................................................................................ 63Habilitando e Desabilitando Assertivas ............................................................................. 64

Capítulo IV Classes, Packages e Interfaces ................... 66CLASSES .................................................................................................................................. 66

Construtores ....................................................................................................................... 68Valor de Retorno ................................................................................................................ 68

OBJETOS .................................................................................................................................. 69MODIFICADORES DE ACESSO.................................................................................................... 72

Outros Modificadores......................................................................................................... 74REFERÊNCIAS COMPARTILHADAS ............................................................................................ 78COPIANDO OBJETOS................................................................................................................. 81

O objeto this ................................................................................................................... 81PACKAGES ............................................................................................................................... 83

Usando Packages ............................................................................................................... 83Criando Packages .............................................................................................................. 84O Mecanismo de Extensão ................................................................................................. 86

DERIVANDO CLASSES............................................................................................................... 88super ................................................................................................................................... 90

Page 3: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

2

A classe Object ............................................................................................................... 91Sobrescrita e Polimorfismo ................................................................................................ 92

CLASSES E MÉTODOS ABSTRATOS ........................................................................................... 95INTERFACES ............................................................................................................................. 96CLASSES INTERNAS.................................................................................................................. 99

Classes Internas Anônimas............................................................................................... 101CONVERSÃO........................................................................................................................... 103EXCEÇÕES.............................................................................................................................. 103

A hierarquia de Exceções................................................................................................. 105Capturando mais de uma exceção.................................................................................... 106Lançando exceções........................................................................................................... 107Comportamento do Sistema diante das Exceções ............................................................ 109Criando suas próprias exceções....................................................................................... 110A cláusula finally ....................................................................................................... 111

DOCUMENTANDO O CÓDIGO................................................................................................... 112Rótulos.............................................................................................................................. 113HTML embutida ............................................................................................................... 115

AGENDA ELETRÔNICA VERSÃO CONSOLE 1.0 ........................................................................ 115Capítulo V – Entrada e Saída (java.io) ...................... 122

ACESSO SEQUENCIAL............................................................................................................. 122ACESSO DIRETO..................................................................................................................... 127

Capítulo VI – java.util ..................................... 131LIDANDO COM COLEÇÕES...................................................................................................... 131

As Interfaces Iterator e Enumeration ................................................................... 131Vector ........................................................................................................................... 133Stack .............................................................................................................................. 136Hashtable .................................................................................................................... 138

MISCELÂNEA DE CLASSES DO PACOTE JAVA.UTIL................................................................. 141Arrays ........................................................................................................................... 141Date ................................................................................................................................ 144Observable .................................................................................................................. 146StringTokenizer ...................................................................................................... 150

AGENDA ELETRÔNICA VERSÃO CONSOLE 2.0 ........................................................................ 152Capítulo VII - Serialização e Persistência .................... 159

AGENDA ELETRÔNICA VERSÃO CONSOLE 2.1 ........................................................................ 161Capítulo VIII – AWT (Abstract Window Toolkit) ............... 164

A HIERARQUIA DE COMPONENTES ......................................................................................... 164OLÁ MUNDO AWT ................................................................................................................ 166TRATAMENTO DE EVENTOS ................................................................................................... 167

Modelo de Eventos 1.1 ..................................................................................................... 167Tratamento de Eventos com classes Internas................................................................... 171

EXEMPLO BÁSICO .................................................................................................................. 176ACRESCENTANDO CORES....................................................................................................... 180GERENCIANDO O LAYOUT...................................................................................................... 181

Exemplo com BorderLayout....................................................................................... 182Exemplo com FlowLayout ........................................................................................... 183Exemplo com CardLayout ........................................................................................... 184Exemplo com GridLayout ........................................................................................... 186

Page 4: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

3

Exemplo com GridBagLayout .................................................................................... 187UTILIZANDO LISTAS............................................................................................................... 189TRABALHANDO COM MENUS E DIÁLOGOS............................................................................. 192CAPTURANDO EVENTOS DO TECLADO ................................................................................... 196PRINCIPAIS CLASSES.............................................................................................................. 196

Color .............................................................................................................................. 196Component .................................................................................................................... 198Button ........................................................................................................................... 200Label .............................................................................................................................. 201List ................................................................................................................................ 202TextField .................................................................................................................... 203TextArea....................................................................................................................... 204

CONTAINERS.......................................................................................................................... 205Panel .............................................................................................................................. 207Frame .............................................................................................................................. 208

AGENDA ELETRÔNICA VERSÃO GRÁFICA 1.0......................................................................... 211Capítulo IX - Applets ....................................... 217

DESCRIÇÃO DO CÓDIGO HTML ............................................................................................. 221MÉTODOS DA CLASSE APPLET............................................................................................... 222EXIBINDO UMA IMAGEM ........................................................................................................ 226ÁUDIO.................................................................................................................................... 229OBTENDO PARÂMETROS......................................................................................................... 230EXECUTANDO UM APPLET COMO APLICAÇÃO ........................................................................ 232PREPARANDO APPLETS PARA PRODUÇÃO E ARQUIVOS JARS ................................................. 232CRIANDO OS PRÓPRIOS ARQUIVOS MANIFEST......................................................................... 235AGENDA ELETRÔNICA VERSÃO APPLET 1.0 ........................................................................... 236

Capítulo X JavaBean ......................................... 237O QUE É UM JAVABEAN? ....................................................................................................... 237JAVABEANS E FERRAMENTAS RAD ....................................................................................... 237PROPRIEDADES ...................................................................................................................... 238

Simples ............................................................................................................................. 238Indexada ........................................................................................................................... 239Ligada (Bound)................................................................................................................. 240Restringidas(Constrained) ............................................................................................... 241

EVENTOS................................................................................................................................ 243DESENVOLVIMENTO DO EXEMPLO ......................................................................................... 244

TimerEventListener .......................................................................................................... 244TimerEvent ....................................................................................................................... 245TimerBean ........................................................................................................................ 245

INSTALANDO O BEANS DEVELOPMENT KIT (BDK)................................................................ 249TESTANDO EXEMPLO NO BDK............................................................................................... 249

Capítulo XI - Concorrência .................................... 255CRIANDO THREADS EM JAVA ................................................................................................. 257

Criando threads por meio da interface Runnable ........................................................ 259A CLASSE THREAD................................................................................................................. 259

Hierarquia........................................................................................................................ 259Construtores ..................................................................................................................... 259Métodos ............................................................................................................................ 259

Page 5: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

4Variáveis públicas ............................................................................................................ 259

CICLO DE VIDA DOS THREADS ............................................................................................... 259sleep(), yield(), join(), destroy(), stop(), suspend() e resume(). .............. 259

DAEMON THREADS ................................................................................................................ 259INFLUÊNCIA DO SISTEMA OPERACIONAL NO COMPORTAMENTO DOS THREADS..................... 259

Forma de escalonamento de threads................................................................................ 259Relacionamento entre os níveis de prioridades definidas na linguagem Java e os níveis deprioridades definidas nos Sistemas Operacionais............................................................ 259

COMPARTILHAMENTO DE MEMÓRIA E SINCRONIZAÇÃO ........................................................ 259Atomicidade de Instruções e Sincronização do Acesso à Sessões Críticas ...................... 259Comunicação entre Threads: wait() e notify() ................................................................. 259

Capítulo XII - Animação ....................................... 259Capítulo XIII - Programação em rede ......................... 259

CONCEITOS SOBRE PROTOCOLOS USADOS NA INTERNET....................................................... 259TCP................................................................................................................................... 259UDP.................................................................................................................................. 259IDENTIFICAÇÃO DE HOSTS (Número IP).................................................................... 259Identificação de Processos (Portas)................................................................................. 259

PROGRAMAÇÃO EM REDE COM JAVA..................................................................................... 259Comunicação Básica Entre Aplicações............................................................................ 259Comunicação Sem Conexão (UDP) ................................................................................. 259Comunicação por meio de URL ....................................................................................... 259

Capítulo XIV – Computação Distribuída (RMI) ................. 259CRIANDO NOSSA AGENDA DISTRIBUÍDA ................................................................................. 259

Implementar interface do objeto remoto .......................................................................... 259Capítulo XV - Acesso a Banco de Dados ....................... 259

MODELOS DE ACESSO A SERVIDORES .................................................................................... 259TIPOS DE DRIVERS JDBC....................................................................................................... 259

Obtendo os Drivers JDBC................................................................................................ 259PREPARANDO UM BANCO DE DADOS ..................................................................................... 259

Configurando o ODBC..................................................................................................... 259EXEMPLO INICIAL .................................................................................................................. 259

Carregando o Driver........................................................................................................ 259Estabelecendo a conexão ................................................................................................. 259Criando e Executando Comandos .................................................................................... 259

RECUPERANDO VALORES....................................................................................................... 259TRANSAÇÕES E NÍVEL DE ISOLAMENTO................................................................................. 259

Transação......................................................................................................................... 259Níveis de isolamento......................................................................................................... 259

PREPARED STATEMENTS ........................................................................................................ 259PROCEDIMENTOS ARMAZENADOS (STORED PROCEDURES).................................................... 259AGENDA ELETRÔNICA VERSÃO JDBC ................................................................................... 259

Capítulo XVI Servlets e JSP ................................. 259SERVLETS .............................................................................................................................. 259

Applets X Servlets ............................................................................................................. 259CGI X Servlets .................................................................................................................. 259

A API SERVLET..................................................................................................................... 259Exemplo de Servlet ........................................................................................................... 259

COMPILANDO O SERVLET....................................................................................................... 259

Page 6: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

5Instalando o Tomcat......................................................................................................... 259

PREPARANDO PARA EXECUTAR O SERVLET............................................................................ 259Compilando o Servlet ....................................................................................................... 259Criando uma aplicação no Tomcat .................................................................................. 259

EXECUTANDO O SERVLET ...................................................................................................... 259Invocando diretamente pelo Navegador........................................................................... 259Invocando em uma página HTML.................................................................................... 259Diferenças entre as requisições GET e POST.................................................................. 259

CONCORRÊNCIA..................................................................................................................... 259OBTENDO INFORMAÇÕES SOBRE A REQUISIÇÃO .................................................................... 259LIDANDO COM FORMULÁRIOS................................................................................................ 259LIDANDO COM COOKIES......................................................................................................... 259LIDANDO COM SESSÕES ......................................................................................................... 259JSP......................................................................................................................................... 259

PHP X JSP ....................................................................................................................... 259ASP X JSP ........................................................................................................................ 259Primeiro exemplo em JSP ................................................................................................ 259Executando o arquivo JSP................................................................................................ 259Objetos implícitos............................................................................................................. 259Tags JSP........................................................................................................................... 259Comentários ..................................................................................................................... 259Diretivas ........................................................................................................................... 259Extraindo Valores de Formulários................................................................................... 259Criando e Modificando Cookies....................................................................................... 259Lidando com sessões ........................................................................................................ 259O Uso de JavaBeans......................................................................................................... 259

REENCAMINHANDO OU REDIRECIONANDO REQUISIÇÕES ....................................................... 259UMA ARQUITETURA PARA COMÉRCIO ELETRÔNICO ............................................................... 259

Tipos de aplicações na WEB ............................................................................................ 259Arquitetura MVC para a Web .......................................................................................... 259Agenda Web: Um Exemplo de uma aplicação Web usando a arquitetura MVC.............. 259

Capítulo XVII Perguntas Frequentes .......................... 259Bibliografia ................................................ 259Links ....................................................... 259Índice ...................................................... 259

Page 7: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

6

Capítulo I - IntroduçãoJava é uma linguagem de programação desenvolvida pela Sun

Microsystems e lançada em versão beta em 1995. O seu desenvolvimento foiiniciado em 1991 pela equipe liderada por James Gosling visando o mercado debens eletrônicos de consumo. Por isso foi projetada desde o início para serindependente de hardware, uma vez que as características dos equipamentosvariam amplamente neste nicho de desenvolvimento. Outro objetivoestabelecido desde sua concepção foi o de ser uma linguagem segura. Seguratanto no sentido de evitar algumas falhas comuns que os programadorescostumam cometer durante o desenvolvimento, como no sentido de evitarataques externos. Isto é importante no mercado de bens eletrônicos de consumopor que ninguém gostaria de adquirir um produto que necessitasse desligar ereligar para que voltasse a funcionar corretamente. Estas característicasdespertaram o interesse para utilização de Java em outro ambiente que tambémnecessitava de uma linguagem com este perfil: a Internet. A Internet também éum ambiente constituído por equipamentos de diferentes arquiteturas e necessitamuito de uma linguagem que permita a construção de aplicativos seguros.Muitas pessoas argumentarão que estas características podem ser encontradasem outras linguagens e portanto isto não explica o súbito sucesso da linguagem.Podemos arriscar alguns palpites apesar de este ser um terreno um poucopantanoso para se aventurar, até por que as linguagens de programação tendemassumir um caráter quase religioso. Uma das razões que na nossa opiniãofavoreceram a rápida adoção da linguagem foi a sintaxe. Java é sintaticamentemuito semelhante à linguagem C/C++, apesar de existirem diferençasfundamentais na filosofia de implementação entre as duas linguagens. Istofacilitou a migração de uma legião imensa de programadores C/C++ para a novalinguagem. Outra razão que não pode ser desprezada é o momento atual onde osdesenvolvedores estão ansiosos para se libertarem de sistemas proprietários.Portanto, apesar de não serem novas as idéias embutidas na linguagem Java, areunião delas em uma só linguagem, juntamente com a facilidade migração dosprogramadores e o momento atual, contribuíram para o rápido sucesso dalinguagem.

Hoje, segundo a International Data Corp. (IDC), existem mais de 2milhões de programadores Java no mundo e a estimativa é que o número dedesenvolvedores ultrapasse os 5 milhões em 2004. O número de programadoresJava deve ultrapassar o de programadores C++ ainda este ano (2002), segundo aconsultoria americana Evans Data. Os profissionais que dominam a linguagem

Page 8: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

7

estão entre os mais bem pagos da área de Tecnologia da Informação (TI), comsalários variando de 3 a 10 mil reais, podendo em alguns casos chegar à 16 milreais, segundo a revista Info Exame (dezembro de 2001).

A lista abaixo apresenta as principais características de Java de modo queo leitor tenha uma visão geral da linguagem:

• Orientação a objetos. Java não é uma linguagem totalmente orientada aobjetos como Smalltalk, onde tudo é objeto ou métodos de objetos. Porquestões de eficiência foram mantidos alguns tipos primitivos e suasoperações. No entanto, Java possui um grau de orientação a objetos bemmaior que C/C++, o que a torna bem mais harmoniosa e fácil de assimilar,uma vez que o programador tenha compreendido esta forma dedesenvolvimento.

• Compilação do código fonte para código de uma máquina virtual(Bytecodes). Esta característica visa tornar a linguagem independente deplataforma de Hardware e Sistema Operacional. Obviamente é necessárioque exista um programa capaz de interpretar o código em Bytecodes paracada Sistema Operacional, denominado de Máquina Virtual. No entanto,nada impede que o código fonte seja traduzido diretamente para o códigoexecutável na máquina de destino. Já existem ambientes de desenvolvimentoque apresentam este tipo de opção. Alternativamente, é possível projetarequipamentos que processem em hardware os Bytecodes. A Sundesenvolveu um processador que executa operações em Bytecodes,denominado de JavaChip. O diagrama abaixo ilustra as etapas envolvidas naexecução de um código Java.

Figura I-1. Fases para execução de um programa fonte em Java

• Ausência de manipulação explícita de ponteiros. Em linguagens comoC/C++ e Pascal existe o tipo ponteiro como tipo primitivo da linguagem. Aespecificação original de Pascal é restritiva no uso de ponteiros, permitindoque sejam usados apenas para referenciar memória obtida na área dealocação dinâmica (heap) e não permite que o programador examine o valor

Page 9: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

8

da variável do tipo ponteiro, nem que realize operações aritméticas componteiros. Já a linguagem C/C++ permite que o valor armazenado navariável do tipo ponteiro faça referência a qualquer área de memória,inclusive à área estática e automática (pilha), além de permitir aritmética deponteiros e o exame direto do valor armazenado. A manipulação do tipoponteiro exige uma grande dose de atenção por parte do programador emesmo programadores experientes frequentemente cometem erros no seuuso. Além disso, o uso de ponteiros é uma fonte de insegurança nalinguagem, uma vez que permite que o usuário faça acesso a memória quepode pertencer a outros processos, abrindo a possibilidade paradesenvolvimento de programas hostis ao sistema. A linguagem Java nãopossui o tipo ponteiro. Isto não que dizer que não seja possível realizaralocação dinâmica de memória. Todo objeto criado é alocado na área deheap, mas o usuário não pode manipular a referência ao objetoexplicitamente.

• Recuperação automática de memória não utilizada (Coleta de Lixo –Garbage Collection). Nas linguagens onde existe alocação dinâmica dememória, o programador é responsável pela liberação de memóriapreviamente obtida na área de alocação dinâmica e que não está sendo maisutilizada. Se houver falhas na execução desta responsabilidade ocorrerá oproblema que é conhecido sob a denominação de “vazamento de memória”.Este problema faz com que a partir de certo ponto o programa não consigaobter memória para criação de novos objetos, apesar de existir área que nãoestá sendo mais usada mas que não foi devolvida ao gerente de memória.Outro erro comum é a tentativa de acesso á áreas de memória já liberadas.Todos os programadores que trabalham com linguagens que permitemalocação dinâmica conhecem bem estes problemas e sabem o quanto é difícilimplementar programas que não possuam estes tipos de erros. A maior partedos erros que ocorrem no uso destas linguagens é devido a problemas naalocação/liberação de memória. Visando o desenvolvimento de aplicaçõesrobustas, livres deste tipo de falha, os projetistas de Java incorporaram umprocedimento de coleta automática de lixo à máquina virtual. Deste modo, osobjetos que não estão sendo mais usados são identificados peloprocedimento, que libera a memória para ser utilizada na criação de novosobjetos.

• Segurança. As pessoas costumam dizer que Java é uma linguagem segura.Mas o que é ser uma linguagem de programação segura? Segurança possuisignificados distintos para pessoas diferentes. No caso da linguagem Java na

Page 10: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

9

versão 1.0 segurança significa impedir que programas hostis que possamcausar danos ao ambiente computacional, ou que busquem informaçõessigilosas em computadores remotos para uso não autorizado. Na versão 1.1foi adicionada a capacidade de permitir a verificação da identidade dosprogramas (autenticação) e na versão 1.2 os dados que os programas enviame recebem podem ser criptografados por meio do uso de um pacote adicional.Na versão 1.4 o pacote de criptografia JCE (JavaTM Cryptography Extension)foi incorporado ao J2SDK.

• Suporte à Concorrência. A construção de servidores, a criação deprogramas com interfaces gráficas, e programas semelhantes que tem emcomum a necessidade de que o atendimento de uma solicitação nãoincapacite o sistema de responder a outras solicitações concorrentemente,demandam o uso de uma linguagem que facilite o desenvolvimento destetipo de programa. As linguagens projetadas antes do surgimento destasnecessidades, como C/C++, não previam facilidades para este tipo deprogramação, o que obrigou a incorporação destes recursos posteriormente,por meio de funções adicionais. Como a programação concorrente é umaforma de programação que difere bastante da programação sequencialconvencional, a simples adição de novas funções para tentar adaptar alinguagem a esta forma de codificação, não cria um ajuste perfeito com alinguagem subjacente. Por outro lado, Java foi projetada visando facilitar aprogramação concorrente. Isto faz com que a criação linhas de execução(threads) seja bem mais natural dos que nas linguagenstradicionais.Programação em rede. Java possui em seu núcleo básicoclasses para comunicação em rede por meio dos protocolos pertencentes àpilha de protocolos TCP/IP. A pilha de protocolos TCP/IP é a utilizada pelaInternet e tornou-se o padrão de fato para comunicação entre computadoresem uma rede heterogênea. Isto torna Java particularmente atrativa para odesenvolvimento de aplicações na Internet. Além disso Java está incorporaum amplo de conjunto de soluções para computação distribuída, comoCORBA (Common Object Request Broker Architecture), RMI (RemoteMethod Invocation) e Servlets/JSP (aplicações Java que são executadas porservidores Web).

Após o lançamento da versão beta da linguagem em 1995, a Sun temliberado diversas evoluções da linguagem na forma de versões e releases de umconjunto de ferramentas denominado de Java Development Kit (JDK) até aversão 1.2, quando se passou a denominar Java 2 SDK (Standard DevelopmentKit). Isto ocorreu porque outros kits de desenvolvimento com propósitos

Page 11: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

10

específicos foram lançados, como o J2EE (Java 2 Enterprise Edition), voltadopara aplicações distribuídas escaláveis e o J2ME (Java 2 Micro Edition), voltadopara aplicações embutidas em dispositivos eletrônicos (Celulares, handheld,etc.). Durante a elaboração deste livro, a última versão estável do SDK era a denúmero 1.3.1 que pode ser obtida gratuitamente no site http://java.sun.com/.

Convenções

As seguintes convenções são usadas neste livro.

1. Fontes com larguras constantes são usadas em:

• exemplos de código

public class Ponto {private int x,y;

}

• nomes de métodos, classes e variáveis mencionadas no texto.

2. Fontes com larguras constantes em negrito são usadas dentro de exemplos decódigos para destacar palavras chave.

3. Fontes em itálico são usadas:

• em termos estrangeiros;• na primeira vez que for usado um termo cujo significado não for

conhecimento generalizado.

Page 12: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

11

Capítulo II - Programação Orientadaa Objetos

O mundo pode ser visto como um conjunto de objetos que se relacionam.Por exemplo, uma pessoa, uma casa, uma cadeira da casa, etc. Os objetos nãosão necessariamente físicos. Podem possuir uma natureza abstrata, como umevento (uma partida de futebol) ou algo inexistente no mundo real (elefante cor-de-rosa). Na verdade, o conceito de objeto atua no nível lógico e não no real. Seiremos representar algo como objeto ou não depende apenas de uma decisão anível lógico que pode facilitar a simulação de determinado aspecto da realidade.

Os objetos se agrupam em classes, segundo propriedades ou atributoscomuns. Por exemplo, a classe dos retângulos agrupa todas as formasgeométricas com a propriedade de possuir quatro lados formando ângulos de90o. A relação entre um objeto e uma classe é de pertinência. Dizemos que umobjeto pertence a uma classe ou, mais comumente, que é uma instância de umaclasse. O Figura abaixo ilustra exemplos de classes.

Figura II-1. Classe dos (a) retângulos e dos (b) dos triângulos.

As classes podem ser relacionar com outra classe no sentido que umaclasse pode conter outra. Por exemplo, a classe de retângulos está inserida emuma classe mais genérica, a classe dos polígonos. A classe mais genérica édenominada de Superclasse e as classes mais específicas são denominadas de

Page 13: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

12

Subclasses. As subclasses herdam as propriedades das superclasses. No nossoexemplo, os polígonos possuem as propriedades de ter uma área, uma posição noplano, um número n de vértices e n-1 ângulos. Todas essas propriedades sãoherdadas tanto pela classe dos retângulos como pela classe do triângulos.Podemos desta forma organizar os objetos em uma hierarquia onde as classesmais específicas herdam as propriedades das classes mais genéricas.

Figura II-2. Classe dos polígonos.

Os objetos de uma classe possuem comportamentos que podem alterar ovalor de suas propriedades. Por exemplo, um carro pode sofrer uma aceleraçãoou ser freado e com isso alterar a sua velocidade. Um objeto qualquer pode serdeslocado, alterando assim as suas coordenadas no espaço.

Classes e Objetos e Linguagens de Programação

As linguagens de programação são utilizadas para construir simulaçõesde aspectos da realidade no computador. Quanto mais facilmente pudermosexpressar os conceitos capturados da realidade, mais facilmente construiremos asimulação. Seguindo este raciocínio podemos concluir que as linguagens quepossuem facilidades para representação de objetos permitem uma modelagemmais fácil dos conceitos do mundo real. No entanto, podemos utilizar umalinguagem de programação convencional para modelar as classes e objetosabstraídos da realidade. Por exemplo, podemos modelar a classe dos retângulospor meio de um registro (record) em Pascal.

Page 14: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

13

type Classe_Retangulo = recordX1,Y1,X2,Y2: integer;

end;

Exemplo II-1. Representação da Classe Retângulo em Pascal.

No Exemplo II-1 o retângulo é definido por dois pontos, sendo X1 e Y1 oponto superior esquerdo e X2 e Y2 o ponto inferior direito. Os objetos podemser representados por meio de variáveis do tipo definido:

type Classe_Retangulo = recordX1,Y1,X2,Y2: integer;

end;

var Retangulo1 : Classe_Retangulo;

Exemplo II-2. Criação de objetos em Pascal.

procedure intRetangulo(XA,YA,XB,YB: integer; var R:Classe_Retangulo);

beginR.X1 := XA;R.Y1 := YA;R.X2 := XB;R.Y2 := YB;

end;

procedure MudaPos(X,Y: integer; var R: Classe_Retangulo);begin

R.X2 := X+(R.X2-R.X1);R.Y2 = Y+(R.Y2-R.Y1);R.X1 = X;R.Y1 = Y;

end;

Exemplo II-3. Definição das operações em Pascal.

Page 15: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

14

As propriedades dos objetos podem ser manipuladas através de funções eprocedimentos. Por exemplo, podemos ter uma operação para inicializar osvalores da estrutura e outra para alterar a posição do retângulo. O Exemplo II-3mostra essas duas operações.

Contudo, existem algumas limitações das linguagens convencionais que astornam inadequadas para a modelagem de objetos:

• Não existem recursos para ocultar a estrutura de dados de procedimentosque não foram projetados para a sua manipulação. É muito importanteque a linguagem forneça recursos para se implementar este tipo deisolamento. Se acessarmos uma estrutura apenas por meio dosprocedimentos projetados para este fim, quando a estrutura for alteradaapenas os procedimentos que manipulam a estrutura sofreriammodificações. No entanto, se não agirmos desta forma será necessárioprocurar em todo o programa os acessos diretos à estrutura. Claro queeste comportamento pode ser adotado em qualquer linguagem, mas émais seguro se a linguagem fornece meios para o programador forçareste tipo de comportamento. A capacidade de “esconder” a estrutura dedados de acessos diretos é chamada de ocultação de informação.

• Não existem recursos para herança de propriedades entre classes esubclasses. Se precisarmos implementar uma estrutura que é umaespecialização de outra já implementada, será preciso codificarnovamente todas as propriedades, mesmo as comuns, e todos osprocedimentos de acesso. Isto dificulta o reaproveitamento de código, oque, consequentemente aumenta o tempo de desenvolvimento e apossibilidade de erros.

• Não existe uma forma de relacionar explicitamente as estruturas de dadoscom os procedimentos que as manipulam. O relacionamento entre osprocedimentos que manipulam uma estrutura de dados e a estrutura éestabelecido implicitamente, por meio de alguma convenção definidapelo programador. É importante que a linguagem obrigue o programadorrelacionar explicitamente os procedimentos com a estrutura de dados, demodo que fique claro qual é a interface de acesso ao objeto.

A adoção de uma linguagem programação orientada a objetos resolve todosesses problemas. Existem várias linguagens comerciais com esta característica:Smalltalk, Eiffel, C++, etc. Algumas com elementos não orientados a objetoscomo C++, outras puramente orientadas a objetos como Smalltalk, onde tudo é

Page 16: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

15

objeto. Java é uma linguagem orientada a objetos mais “pura” do que C++,fugindo desta orientação apenas em alguns pontos bem definidos, em nome daeficiência de execução. Em Java podemos representar diretamente as classes eobjetos. Por exemplo, a classe retângulo seria declarada da seguinte forma:

class Retangulo{

int X1,Y1,X2,Y2;public Retangulo(int XA, int YA, int XB, int YB){

X1 = XA;Y1 = YA;X2 = XB;Y2 = YB;

}

void MudaPos(int X, int Y){

X2 = X+(X2-X1);Y2 = Y+(Y2-Y1);X1 = X;Y1 = Y;

};}

Exemplo II-4.Representação da Classe Retângulo em Java.

No Exemplo II-4 mudamos o nome do procedimento iniRetangulo paraRetangulo, que é o mesmo nome da classe. No momento não é importanteentendermos a razão desta mudança, que será esclarecida no próximo capítulo.Note que os procedimentos são declarados dentro do corpo da classe, tornandoexplícito relacionamento entre a classe e os procedimento. As funçõesdeclaradas nas classes são chamadas de métodos e a partir de agora nosreferenciaremos a eles como tal. Note também que diferentemente do exemploem Pascal, não é preciso passar o objeto como parâmetro, uma vez que asvariáveis que estão sendo modificadas pertencem ao objeto corrente, ao qual estáassociado o método. É como se para cada objeto de uma classe fossem criadasversões de todos os métodos da classe, de modo que cada método só opera sobreas variáveis do objeto a quem pertencem. Para declarar uma variável do tipo daclasse basta preceder a variável com o nome da classe.

Retangulo ret;

Page 17: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

16

Até esse momento nenhum objeto foi criado. Para criar um objeto(instância) é usado o operador new.

ret = new Retangulo(10,10,20,30);

Note que o operador new é seguido de uma chamada ao método com omesmo nome da classe. O métodos com esta característica são chamados deconstrutores e só podem ser invocados durante a criação de um objeto. Comoveremos mais tarde, uma classe pode ter mais de um construtor. Após a criaçãodo objeto é possível acessar os outros métodos do objeto através do operador “.”.Por exemplo, podemos mudar a posição do objeto por meio do método MudaPos.

ret.MudaPos(40,40);

Como já dissemos, não é preciso passar o objeto como argumento, já queé criada uma cópia do método para cada objeto. A grosso modo podemos dizerque cada instância da classe recebe uma cópia da variáveis e dos métodos daclasse.

Ocultando de Informação

O projetista cuidadoso deve ocultar a representação interna da classe,permitindo o acesso aos atributos da classe via métodos predefinidos. Destaforma a representação interna fica isolada do restante do programa e fica maisfácil alterá-la sem que seja preciso alterar outras partes do código. A ocultaçãode informação é obtida por meio de qualificadores, como o private, queimpede o acesso à variáveis via métodos definidos em outras classes. O nível deocultação depende do qualificador utilizado. Todos os qualificadores serãoabordados com detalhes no Capítulo IV. O exemplo II-5 mostra como impedirque as variáveis declaradas na classe Retangulo sejam acessadas diretamente.

class Retangulo{

private int X1,Y1,X2,Y2;

public Retangulo(int XA, int YA, int XB, int YB){

X1 = XA;Y1 = YA;

Page 18: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

17X2 = XB;Y2 = YB;

}

void MudaPos(int X, int Y){

X2 = X+(X2-X1);Y2 = Y+(Y2-Y1);X1 = X;Y1 = Y;

};}

Exemplo II-5. Ocultando informação em Java.

Especialização e Herança

Para criar uma subclasse de uma classe pré-existente utilizamos ooperador extends. Por exemplo, podemos definir uma subclasse da classeRetangulo, chamada de RetanguloColorido, que possui, além das variáveis emétodos herdados da superclasse, uma variável para armazenar a cor doretângulo, juntamente com um método para alterar o valor.

class RetanguloColorido extends Retangulo{

private Color Cor;

void AtribuiCor(Color C){

Cor = C;};

}

Exemplo II-6. Declarando subclasses em Java.

A princípio, subclasse pode acessar todos os métodos e variáveis dasuperclasse. No entanto, isto também pode ser alterado via qualificadores.

Page 19: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

18

Sobrescrita, Sobrecarga e Polimorfismo

Podemos definir mais de um método com o mesmo nome na mesmaclasse ou subclasses. Caso o método possua a mesma assinatura (número e tiposde argumentos e tipo de retorno) que outro método, então o método não podepertencer à mesma classe do anterior. Se ambos os métodos estiverem na mesmalinha hierárquica (classe/subclasse), dizemos que o método da subclassesobrescreve o método da superclasse. O método que será executado dependeráda classe do objeto.

class Empregado{

protected float salario;public float getSalario() {return salario;}

}

class Vendedor extends Empregado{

protected float comissao;public float getSalario() {return salario+comissao;}

}

Exemplo II-7. Sobrescrita do método getSalario().

No exemplo II-7 o método getSalario() da classe Vendedorsobrescreve o método do mesmo nome da classe Empregado.

Se a assinatura do método for diferente de outro método com o mesmonome definido anteriormente na mesma classe ou em outra classe da mesmalinha hierárquica, então estamos realizando uma sobrecarga sobre oidentificador do método. Quando for usado o identificador dentro do código deum programa o método invocado será determinado pela classe a que pertence oobjeto do método e pelo número e tipos dos argumentos passados para o método.O termo sobrecarga advém do fato de um mesmo identificador denotar mais demétodo.

class Empregado{

protected float salario;public void aumento() {salario= salario*10.0;}public void aumento(float porcent)

Page 20: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

19{

salario= salario*porcent;}

}

Exemplo II-8. Sobrecarga do método aumento().

No exemplo II-8 o identificador aumento pode referenciar dois métodosdistintos. Um aumenta o salário em 10% e no outro o aumento depende do valorda porcentagem passado como parâmetro. Note que as assinaturas do métodosdiferem entre si.

Alguns autores chamam sobrecarga de polimorfismo, que é a habilidadede um determinado objeto se comportar ou ser visto de diferentes formas,quando na verdade a sobrecarga é um tipo particular de polimorfismo, chamadode polimorfismo ad hoc . Na sobrecarga um identificador representa váriosmétodos com computações distintas. Existe também o polimorfismoparamétrico, onde um método pode realizar a mesma computação sobre objetosde tipos distintos. Isso pode ser implementado em Java definindo um métodoque recebe e retorna objetos da classe Object. Como a classe Object é a “mãede todas as classes” o método pode operar da mesma forma independente daclasse a qual o objeto realmente pertence, desde que a computação sejaindependente da classe.

class Poli{

public Object identidade(Object objeto){

return Object;}

}

Exemplo II-9. Polimorfismo paramétrico.

No Exemplo II-9 o método identidade() retorna o objeto passadocomo parâmetro. Este método realiza a mesma computação, independentementeda classe do objeto. Obviamente é um exemplo muito simples e sem utilidadeprática mas serve para ilustrar o conceito de polimorfismo paramétrico.

Page 21: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

20

Introdução à Diagrama de Classes

É possível registrar diretamente em uma linguagem de programação osobjetos percebidos em uma determinada realidade. No entanto, é melhorutilizarmos uma notação gráfica intermediária para melhor visualizarmos osobjetos e as relações entre objetos, e ir alterando esta representação até estarmosseguros que possuímos um entendimento razoável do problema, e ai sim,partirmos para a codificação da solução. Muitas vezes é preciso recorrer a maisde uma notação gráfica, de modo a expressar várias facetas da realidade que estásendo modelada. Neste livro, recorreremos ao uso de notação gráfica em algunsexemplos para ilustrarmos a arquitetura dos programas antes de apresentarmos ocódigo. Acreditamos que desta forma o leitor compreenderá melhor osexemplos.

A notação gráfica que adotamos mostra as relações estáticas entre classesde objetos. Ela faz parte do conjunto de notações da UML (Unified ModelingLanguage ou Linguagem de Modelagem Unificada) proposta por Grady Booch,James Rumbaugh e Ivar Jacobson em 1995. A UML é um conjunto de notaçõesque tem por objetivo modelar diversos aspectos de um sistema em diferentesníveis de abstração. Ou seja, pode ser utilizado para a captura de requisitos deum sistema assim como em projeto de programas. É voltada para análise eprojeto de sistemas orientados a objetos. A área de análise e projeto orientados aobjetos ainda não possui uma notação “vencedora” como existe para a análise eprojeto estruturado. Contudo, a UML vem se popularizando rapidamente, e éencontrada com facilidade em textos de programação, sobretudo em se tratandode Java. Portanto, um conhecimento sobre as principais notações que constituema UML é importante para qualquer um que deseja ingressar na área deprogramação orientada a objetos. Este livro utiliza uma das linguagens, oudiagramas, que compõem a UML: o diagrama de classes.

Diagrama de Classes

O Diagrama de Classes representa graficamente as classes do sistema e orelacionamento estático entre as classes, isto é, o relacionamento que não mudacom o tempo. Por exemplo, em um sistema acadêmico, um aluno cursa váriasdisciplinas. O número de disciplinas e a disciplina que efetivamente está sendocursada pode alterar, mas o vínculo aluno-cursa-displinas permanece. Parailustrar o nosso estudo dos diagramas da UML utilizaremos exemplos sobremodelagem de aspectos realidade acadêmica.

Page 22: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

21

Uma classe é representada no diagrama de classes por meio de umretângulo, que pode ser dividido em até três seções horizontais, como mostradona figura abaixo:

Figura II-3. Forma geral para representação de uma classe.

A seção superior é usada para registrar o nome da classe. A seçãointermediária é reservada para registro das propriedades da classe, caso existam,e na seção inferior é registrado a assinatura dos métodos que pertencem à classe,caso existam. Por assinatura do método queremos dizer o nome do método,juntamente com seus argumentos e valor de retorno. A figura abaixo mostra umarepresentação da classe das disciplinas.

Figura II-4. Representação da classe das disciplinas

De modo geral, por razões de simplicidade, não se representam osmétodos que tratam da alteração dos atributos e construtores. Se Assumi quetoda classe possui estes métodos. Portanto, podemos simplificar a representaçãoacima, omitindo a seção do métodos.

Page 23: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

22

Figura II-5. Representação simplificada da classe das disciplinas.

Podemos indicar tanto nos atributos quanto nas classes a visibilidadedeles em relação a outras classes. As visibilidades possíveis, juntamente com ossímbolos adotados estão listados na tabela abaixo:

Visibilidade Símbolo DescriçãoPública + Sem restrição de acesso.Protegida # Pode ser acessado apenas na própria classe e

por subclasses.Privada - Pode ser acessado apenas na própria classe.

Tabela II-1. Visibilidades possíveis para atributos e métodos.

A visibilidade é atribuída a um atributo ou método precedendo adeclaração do método com o símbolo adequado, como na figura abaixo:

Figura II-6. Representação com visibilidade.

Page 24: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

23

As classes podem se relacionar de diversas formas: por associaçãocomum, por agregação e generalização. Abaixo é apresentada cada forma derelacionamento, juntamente com suas as notações.

Associação comum

A notação utilizada para associar duas classes é simplesmente uma linhaunindo as classes. A figura II.7 mostra a associação entre a classe dos alunos e aclasse das disciplinas.

Figura II-7. Associação entre Aluno e Disciplina.

A figura acima expressa que alunos se associam com disciplinas mas nãoindica se um aluno se relaciona com várias ou apenas uma disciplina. Estainformação é chamada de cardinalidade da relação e é expressa anotando-se ovalor da cardinalidade na associação junto à classe que está sendo relacionada.Assim, a figura II.8 expressa que um aluno se relaciona com várias disciplinas.

Figura II-8. Associação de um Aluno com várias Disciplinas.

Como uma disciplina se relaciona com vários alunos, o diagramacompleto é o representado na figura II-9.

Figura II-9. Associação de vários Aluno com várias Disciplinas.

A tabela II-2 mostra algumas representações de cardinalidade:

Page 25: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

24

Notação Descrição1 Exatamente um* ou 0..* Zero ou mais0..1 Opcional (zero ou um)n..m Máximo e mínimo

Tabela II-2. Representações de cardinalidade.

Até agora apresentamos apenas associações entre duas classes, mas nadaimpede que mais de duas classes participem de uma associação. Por exemplo, afigura II-10 ilustra uma associação ternária que representa o fato de um alunocursar uma disciplina em um período.

Figura II-10. Associação entre aluno, disciplina e período.

Uma associação pode ter atributos próprios. Ou seja, atributos que nãopertençam a nenhuma das classes envolvidas na associação mas sim à própriaassociação. Na associação entre alunos e disciplina o atributo nota, não pertencea aluno, tampouco à disciplina, uma vez que para saber uma nota é preciso saberquem é o aluno e qual é a disciplina. A representação de atributos da associaçãoé representada por meio de um retângulo ligado à associação por meio de umalinha tracejada.

Page 26: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

25

Figura II-11. Representação de atributos de associação.

Agregação

Alguns objetos são compostos por outros objetos. Por exemplo, um carroé composto por chassi, lataria, pneus e motor, que por sua vez é composto pelocarburador, pistões, bloco, etc. Este tipo de associação é representada por umalinha com um losango na ponta.

Figura II-12. Agregação entre Curso e Disciplina.

Generalização

O último tipo de associação entre classes é o que o ocorre entresuperclasses e subclasses. Uma superclasse é uma generalização das suassubclasses, que herdam os atributos e métodos da primeira. A notação utilizadapara representar a generalização é uma linha com um triângulo na extremidadeda associação no lado da classe mais genérica.

Page 27: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

26

Figura II-13. Representação da generalização.

A figura II-14 procura representar todas associações discutidas em umúnico diagrama.

Figura II-14. Associação entre as classes do domínio acadêmico.

Page 28: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

27

Capítulo III - Introdução àLinguagem Java

Existe uma tradição entre os programadores que estabelece que ao secomeçar a aprender uma nova linguagem de programação, o primeiro programaa ser escrito deve ser um que imprima a frase “Olá mundo” em um dispositivode saída. Dizem que isto atrai a sorte e espanta os bugs. Independente da crençageral, existem algumas razões bastante justificáveis para se começar oaprendizado de uma linguagem executando logo um programa, mesmo sem termuita idéia do que se está fazendo. Primeiramente, existe o fator psicológico.Iniciar o aprendizado executando um programa sem erros, aumenta confiança doaluno e elimina temores de se estar aprendendo algo muito complexo. Existetambém o fato de que apesar de um programa muito simples dar uma visão umpouco limitada da linguagem, já é possível observar alguns elementosimportantes. Afinal trata-se de um programa completo. Portanto, para não fugir atradição, eis o programa OlaMundo em Java:

public class OlaMundo{

public void exibeOla(){ System.out.println(“Ola, Mundo!”);}

public static void main(String args[]){

OlaMundo obj = new OlaMundo(); Obj.exibeOla();

}}

Exemplo III-1. Programa OlaMundo.

O programa acima é composto por uma única classe que possui apenasdois métodos. Isto é importante, porque não é possível fazer um programa Javasem recorrer às classes, uma vez que os procedimentos são definidos comométodos de classes. Isto não é verdade em linguagens como C++, o que diminuio seu “grau” de orientação a objetos.

Page 29: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

28

Os métodos com o nome main são métodos especiais e servem comoponto inicial para execução do programa. Ou seja, a execução do programa seráiniciada a partir da execução de um método main(). A assinatura do métodomain é sempre a mesma e a sua descrição em detalhes será vista na seçãoArgumentos da linha de comando. Podemos adiantar apenas que o qualificadorpublic estabelece que este método pode ser chamado por métodos ouprocedimentos externos à classe. O qualificador static significa que o métodopertence à classe e não às instâncias da classe, e deste modo pode ser invocadomesmo antes de ser criado algum objeto para a classe. void indica que o métodonão retornará valor algum. Já argumento String args[] é um array deStrings contendo os parâmetros passados na linha de comando.

O corpo do método main() possui duas linhas. A primeira instrução criaum objeto da classe OlaMundo e o atribui à variável obj. A segunda linha invocao método exibeOla() do objeto recém criado. O método exibeOla() invoca ométodo println() do objeto out da classe System, que faz parte do pacote declasses fornecido com a linguagem. Este método exibe no dispositivo de saídapadrão a String que é passada como argumento.

Se você olhar os programas “OlaMundo” mostrados em outros livrossobre Java irá notar que o programa apresentado aqui é um pouco maiscomplicado que o exibido nesses livros. Geralmente este programa inicial éapresentado apenas com um método: o método main(). A razão de termos usadouma abordagem diferente é que desejamos desenvolver um hábito saudável naprogramação em Java: procure usar o método main() apenas para criar osobjetos e deixe que os objetos executem a lógica do problema.

Este programa deve ser salvo em um arquivo contendo O MESMONOME DA CLASSE e com as mesmas letras maiúsculas e minúsculas (éimportante frisar, uma vez que esquecer este detalhe é um erro muito comum), ecom a extensão “.java”. Portanto o arquivo contendo o programa acima deveráse chamar OlaMundo.java. Se você instalou o Java 2 development kit (SDK),que pode ser obtido gratuitamente no site http://java.sun.com/products/, entãopara compilar o programa basta digitar o comando:

javac OlaMundo.java

O código Java é traduzido (o termo mais comum é compilado) parainstruções de uma máquina virtual (bytecodes) para que possa ser executado deforma independente da plataforma (sistema operacional e hardware). O códigoem bytecodes é armazenado em um arquivo com o mesmo nome do original ecom a extensão “.class”. Assim após a execução do comando acima será

Page 30: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

29

gerado o arquivo OlaMundo.class. A invocação da máquina virtual paraexecutar o código em bytecodes é efetuada por meio do seguinte comando:

java OlaMundo

Neste ponto nota-se uma desagradável idiossincrasia do SDK. Paracompilar o programa para bytecode foi necessário explicitar a extensão doarquivo, porém, para executar o código é preciso omitir a extensão “.class”.Apesar de ser um detalhe que aparentemente não prejudica o uso do ambiente,confunde o usuário, principalmente o iniciante.

Quando recebe um arquivo de bytecodes para a executar, a máquinavirtual procura o método main() em uma classe com o mesmo nome do arquivo.Uma vez encontrado o método a execução é iniciada com a execução do método.Isto significa que em nosso exemplo será procurado o método main() da classeOlaMundo para servir de ponto de entrada. Podem existir outros métodos main()em outras classes codificadas no mesmo arquivo de bytecodes, mas apenas ométodo main() da classe com o mesmo nome do arquivo servirá de ponto inicialde execução. Portanto, em nosso caso, o programa será executado produzindo asaída:

Ola, Mundo!

Agora que já cumprimos o ritual de iniciação na linguagem, podemos passar adescrever os detalhes da linguagem. Grande parte das descrições que seguemabaixo foram baseadas na especificação da linguagem registrada no livro TheJava Language Specification, segunda edição, por James Gosling e outros.

Identificadores

Todos os identificadores da linguagem devem iniciar com uma letra, ou ocaractere ´_`, ou o caractere ´$`. Deve-se evitar o uso do caractere ´$`, de modoque fique reservado para geração de código automático. Tratamos por letra todocaractere reconhecido pelo método Character.isJavaLetter. Isto inclui umaampla gama de caracteres do conjunto Unicode1, de modo que os programadorespodem usar identificadores adaptados a uma ampla gama de idiomas. Após o

1 O conjunto de caracteres Unicode foi criado para substituir o conjunto ASCII. Ele usa 16 bitspara representar os caracteres, o que resulta em 65536 caracteres possíveis, em oposição aos 7bits do código ASCII (8 para o ASCII estendido), o que resulta em 128 caracteres possíveis (256para 8 bits).

Page 31: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

30

primeiro caractere, também podem ser usados os caracteres que vão de ´0` até´9`. A linguagem Java distingue as letras maiúsculas das minúsculas, portanto oidentificador Aluno é distinto do identificador aluno. A tabela III-1 mostraalguns identificadores válidos e inválidos.

Válido InválidoAluno10 Aluno#10Num_Alunos Num Alunos_disciplina$ !disciplinaProfessor_10 10Professorαβγ &uuuNão Não?

Tabela III-1. Identificadores válidos e inválidos em Java.

Palavras Reservadas

As seguintes sequências de caracteres são reservadas para o uso comopalavras chave e, portanto, não podem ser usadas como identificadores:

abstract continue goto package synchronizedassert2 default if private thisboolean do implements protected throwbreak double import public throwsbyte else instanceof return transientcase extends int short trycatch final interface static voidchar finally long strictfp3 volatileclass float native super whileconst for new switch

Tabela III-2. Palavras reservadas da linguagem Java.

As palavras chave const e goto, apesar de serem reservadas, não estãosendo usadas correntemente na linguagem.

2 Introduzida a partir da versão 1.4 do SDK.3 Introduzida a partir da versão 1.2 do SDK

Page 32: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

31

Literais

Literais são elementos do código que representam um valor de tipoprimitivo, tipo String ou null. Os literais podem ser numéricos, booleanos,caracteres ou cadeias de caracteres (Strings). Literais numéricos inclueminteiros, ponto flutuante.

Literais Inteiros

Um literal inteiro é do tipo primitivo long (longo) se possui o sufixo ´L`ou ´l`, caso contrário é do tipo primitivo int (inteiro). Um numeral hexadecimalé prefixado pelos caracteres ´0x` ou ´0X` seguidos de um ou mais dígitoshexadecimais. Os dígitos hexadecimais com valores entre 10 e 15 sãorepresentados pela letras ´a` até ´f` ou ´A` até ´F`, nessa ordem. Um numeraloctal consiste de um dígito 0 seguido de um ou mais dígitos de 0 até 7.

O maior literal decimal do tipo int é 2147483648. Os literais decimaisde 0 até 2147483647 podem aparecer em qualquer lugar que um literal inteiropode aparecer, mas o literal 2147483648 pode aparecer somente como operandode uma negação unária.

Os maiores literais hexadecimal e octal positivos inteiros são 0x7fffffff e017777777777, respectivamente, que correspondem ao valor decimal2147483647. Os maiores literais hexadecimal e octal negativos inteiros são0x80000000 e 020000000000, respectivamente, que representam o valordecimal -2147483648 (). Os literais hexadecimal e octal 0xffffffff e037777777777, representam o valor decimal -1. Abaixo estão listados algunsexemplos de literais inteiros:

0 -12 0372 0xCafe 1999 0x00FF00FF

O maior literal decimal do tipo longo é o 9223372036854775808L. Osliterais decimais de 0L até 9223372036854775807L podem aparecer emqualquer lugar que um literal inteiro longo pode aparecer, porém o literal9223372036854775808L pode aparecer somente como operando de umanegação unária.

Os maiores literais hexadecimal e octal positivos inteiros longos são0x7fffffffffffffffL e 0777777777777777777777L, respectivamente, quecorrespondem ao valor decimal 9223372036854775807L.Os maiores literais

Page 33: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

32

hexadecimal e octal negativos inteiros longos são 0x8000000000000000L e01000000000000000000000L, respectivamente, que representam o valordecimal -9223372036854775808L. Os literais hexadecimal e octal0xffffffffffffffffL e 01777777777777777777777L, representam o valor decimal -1. Abaixo estão listados alguns exemplos de literais inteiros longos:

0L 0777L 0xC0B0L 0xCafe 1999 0x100000000L

Literais de Ponto Flutuante

Um literal de ponto flutuante é composto por uma parte inteira seguidade um ponto decimal, uma parte fracionária, um expoente e um sufixodeterminando o tipo. O expoente, se presente, é indicado pela letra ‘E’ ou ‘e’,seguido por um inteiro com sinal um opcional. Pelo menos um dígito na parteinteira ou fracionária e o ponto decimal ou o expoente ou o sufixo indicando otipo são exigidos. Todos os outros componentes são opcionais.

Um tipo ponto flutuante é do tipo float se possuir o sufixo ‘F’ ou ‘f’,caso contrário é do tipo double. O tipo double possuir opcionalmente o sufixo‘D’ ou ‘d’.

O tipo float e double de Java obedecem a especificação IEEE 754 parabinários de ponto flutuante de precisão simples (32-bit) e dupla (64-bit).

O maior literal positivo do tipo float é 3.40282347e+38f. O menorliteral positivo do tipo float diferente de zero é 1.40239846e-45f. O maiorliteral positivo do tipo double é 1.79769313486231570e+308. O menor literalpositivo do tipo double diferente de zero é 4.94065645841246544e-324.

Um programa em Java pode representar quantidades infinitas semproduzir erros de compilação por meio da utilização de expressões constantestais como 1f/0f e -1d/0d ou pela utilização das constantes predefinidasPOSITIVE_INFINITY e NEGATIVE_INFINITY das classes Float e Double.Exemplos de literais do tipo float:

1e1f 2.f .3f 0f 3.14f 6.022137e+23f

Exemplos de literais do tipo double:

1e1 2. .3 0.0 3.14 1e-9d 1e137

Page 34: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

33

Literais Booleanos

O tipo boolean possui dois valores, representados pelos literais true efalse.

Literais de Caracteres

Um literal do tipo char é expresso como um caractere ou uma sequênciade escape, envolvida por aspas simples. Os caracteres CR e LF nunca sãocaracteres de entrada, uma vez que são reconhecidos como terminadores delinha. Exemplos de literais do tipo char:

Caractere Descrição'a' o caractere a.'%' o caractere %'\n' line feed'\t' Tab'\\' o caractere \'\'' o caractere '.'\u03a9''\uFFFF''\177'

Tabela III-3. Exemplo de literais do tipo char.

Literais de Cadeia de Caracteres (Strings)

Um literal do tipo String consiste de zero ou mais caracteres envolvidospor aspas duplas. Cada caractere pode ser representado por uma sequência deescapes. O tipo String não é um tipo primitivo e sim uma classe denominadaString. Portanto, um literal é na verdade uma instância da classe String.

Uma String longa pode ser particionada em cadeias menores unidaspelo operador de concatenação ´+’. Exemplos de literais do tipo String:

Literal Descrição"" Cadeia vazia.

Page 35: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

34

"\"" Uma cadeia com apenas o caractere "."esta é uma cadeia" Uma cadeia contendo 17 caracteres."esta é uma "+"cadeia "

Uma cadeia formada por dois literais dotipo String.

Tabela III-4. Exemplo de literais do tipo String.

Sequências de escape

Sequências de escape permitem a representação de alguns caracteres nãográficos, assim como as aspas simples e duplas e a barra invertida. Exemplos desequências de escape:

Sequência Descrição\b \u0008: backspace BS\t \u0009: tab horizontal HT\n \u000a: linefeed LF\f \u000c: form feed FF\r \u000d: carriage return CR\" \u0022: aspas duplas "\' \u0027: aspas simples '\\ \u005c: barra invertida \

Tabela III-5. Exemplo sequências de escape.

O Literal null

O tipo null possui apenas um valor, representado pelo literal null.

Separadores

Java possui nove separadores (caracteres de pontuação), listados abaixo:

( ) { } [ ] ; , .

Page 36: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

35

Tipos de dados

Os tipos de dados definem como devem ser interpretados os dadosarmazenados. São essenciais a toda linguagem de programação e devem sercuidadosamente selecionados para compor a linguagem, de modo a não limitar asua área de atuação. A maioria da linguagens modernas definem um conjunto detipos simples, um conjunto de tipos compostos, formados por tipos maisprimitivos e alguma forma de definição de novos tipos, de modo que possamodelar mais apropriadamente a realidade. A linguagem Java obedece estaregra, fornecendo um conjunto de tipos simples e um conjunto de tiposcompostos. O mecanismo para definição de novos tipos utilizado por Java ésimplesmente a definição de classes.

Java é uma linguagem fortemente tipada. Isto significa que toda variávele expressão possui um tipo determinado em tempo de compilação. Os tiposprimitivos disponíveis em Java não são classes. Esta é uma das razões porqueJava não é uma linguagem 100% orientada a objetos. No entanto, para cada tipoprimitivo existe uma classe correspondente onde são declarados um conjunto demétodos para a manipulação dos valores primitivos, focalizando principalmentena conversão de tipos. Estas classes estão agrupadas no pacote java.lang. Porexemplo, o tipo primitivo int é usado para expressar valores inteiros. A classecorrespondente ao tipo int é a Integer. Nela estão declaradas variáveispúblicas contendo o valor máximo e mínimo que uma variável do tipo inteiropode armazenar e métodos para conversão para outros tipos.

Tipos de dados simples

Tipos de dados simples são aqueles que não podem ser divididos emtipos mais primitivos. Os tipos de dados simples de Java podem ser divididos eminteiros, ponto flutuante, booleano e caractere. Para se definir uma variável deum determinado tipo basta preceder o nome da variável com o nome do tipodesejado, como na forma abaixo:

<nome do tipo> <nome da variável>;

Assim, para se declarar uma variável var1 do tipo inteiro basta a linha decódigo abaixo:

int var1;

Page 37: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

36

Podemos também declarar mais de uma variável em com o mesmo tipo,usando o caractere ‘,’ como separador. Portanto, a declaração

int var1, var2;

é equivalente às declarações

int var1;int var2;

Java também permite que as variáveis sejam inicializadas durante adeclaração. Assim, para inicializarmos a variável var1 com o valor 1 nadeclaração basta a linha de código abaixo:

int var1=1;

Segue abaixo as categorias de tipos de dados simples.

Inteiros

Nome Tamanhobyte 8 bitsshort 16 bitsint 32 bitslong 64 bits

Tabela III-6. Tipos inteiros.

Ponto Flutuante

Nome Tamanhofloat 32 bitsdouble 64 bits

Tabela III-7. Tipos de ponto flutuante.

booleanos

boolean {true,false}

Page 38: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

37

Caractere

char 16 bits

Tipos de dados compostos

Os tipos de dados compostos são constituídos por tipos mais simples.Todos os tipos compostos em Java são Classes. Nesta seção trataremos duasclasses de objetos muito usadas em Java para criação de tipos compostos: osarrays (arranjos) e strings. Posteriormente abordaremos a declaração de objetosno caso geral e no Capítulo VI será apresentado o pacote de classes java.utilque contém várias classes para agrupamento de objetos.

Arrays

Um array é um objeto, e como tal herda todos os métodos da classeObject. Um array contém um certo número de variáveis chamadas decomponentes. Em Java todo objeto é acessado indiretamente, via uma referência.Ou seja, não se cria uma variável do tipo de um objeto e sim uma variável quepode referenciar um objeto. Estamos falando de ponteiros, o que pode parecercontraditório, uma vez que tínhamos mencionado que Java não possui ponteiros.Na verdade Java acessa as instâncias de objeto por meio de ponteiros mas elesnão estão disponíveis como tipo da linguagem e nem é possível que oprogramador os manipule diretamente.

Pode parecer pouco importante para o programador saber que a variávelnão armazena o objeto diretamente e sim uma referência a um objeto, uma vezque ele não pode manipular ponteiros. No entanto, acreditamos que estainformação é importante para que o leitor possa entender as etapas para a criaçãode objetos. A primeira etapa é a declaração da variável para referenciar o objetoe a segunda etapa é a criação do objeto propriamente dito. Para se declarar umavariável para referenciar objetos do tipo array é usada a seguinte sintaxe:

tipo identificador[];tipo[] identificador;

Exemplos

int numeros[];char[] letras;

Page 39: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

38

long grade[][];

Note que não é definido o número de elementos do array. Isto faz partedo objeto. Note também que existem duas formas de declarações de referências aarrays. O número de “[]” indica o número de dimensões do array. A criação doobjeto é realizada por meio do operador new, seguido pelo tipo do array e pelonúmero de componentes de cada dimensão, como nos exemplos abaixo:

numeros = new int[10];char alfabeto[] = new char[26];grade = new long[10][10];

Alternativamente podemos realizar as duas etapas acima e ainda definiros elementos do array em uma única declaração como no exemplo abaixo, ondeé criado um array de três inteiros, referenciados pela variável primos e onde oprimeiro elemento é 7, o segundo é 11 e o terceiro é 13.

int primos = {7, 11, 13};

De agora em diante não faremos distinção entre referência a objeto dotipo array e o objeto array, a não ser que seja necessário explicitar esta distinção.

O acesso aos elementos do array é realizado por meio do nome davariável seguida por um expressão inteira não negativa envolvida peloscaracteres ‘[’ e ‘]’. A expressão inteira é chamada de índice e os valoresadmissíveis para a expressão vai de 0 a n-1, onde n é número de elementos doarray. O índice do primeiro elemento é 0. Abaixo seguem alguns exemplos:

alfabeto[0] = ‘a’;grade[0][5] = 10L;for(int i=0; i<10; i++) numeros[i] = i*2;

É possível descobrir o tamanho de um array em tempo de execuçãoacessando a variável pública length do objeto, onde está armazenada acapacidade do array. Por exemplo:

for(int i=0; i< numeros.length; i++) numeros[i] = i*2;

Strings

Page 40: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

39

O manipulação de cadeias de caracteres (strings) em Java é realizada poruma classe do pacote java.lang denominada String. Ou seja, não existe umtipo primitivo para tratar cadeias de caracteres. Para se declarar uma variável quefaz referencia a um objeto String usa-se a seguinte linha de comando:

String nome;

Para que a variável faça referência a um objeto basta criar um objeto pormeio do operador new ou atribuir a referência de um objeto preexistente.

nome = new String(“Pedro”);String x, y;x= nome;y = “Pedro”;

No primeiro caso a variável nome faz referencia a um objeto recém criadocontendo o valor “Pedro”. Já a variável x faz referencia ao mesmo objetoreferenciado pela variável nome. Ou seja, nenhum novo objeto String é criado,ocorrendo um compartilhamento de objetos. Já a variável y faz referência a umobjeto String contendo o valor “Pedro”, distinto do objeto referenciado por x enome. Podemos também inicializar a variável durante a declaração.

String nome = “Pedro”;

Os objetos do tipo String possuem um conjunto extenso de métodos econstrutores para a manipulação e criação de Strings. A tabela abaixo mostraalguns dos mais utilizados.

Construtor DescriçãoString(byte[] bytes, int offset,int num)

Constrói uma nova String convertendo o subarray debytes especificado

String(StringBuffer buffer) Constrói uma nova String usando a sequência decaracteres contida no StringBuffer.

String(byte[] bytes) Constrói uma nova String convertendo o array debytes especificado

String(String valor) Constrói uma nova String com o mesmo conteúdoda String passada como argumento.

String() Constrói uma nova String contendo zero caracteres.String(char[] valor) Constrói uma nova String convertendo o array de

caracteres especificado.String(char[] valor, int offset,int num)

Constrói uma nova String convertendo o subarray decaracteres especificado.

Page 41: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

40

Tabela III-8. Principais construtores da classe String.

Método DescriçãocharAt(int indice) Retorna o caractere localizado no índice especificado.compareTo(StringoutraString)

Compara duas Strings lexicograficamente.

equals(Object anObject) Verifica se dois objetos são iguais.getChars(int srcBegin,int srcEnd, char[] dst,int dstBegin)

Copia os caracteres da String em um array decaracteres.

indexOf(String str) Retorna o índice da primeira ocorrência do substringno string.

indexOf(String str, intfromIndex)

Retorna o índice da primeira ocorrência do substringno string a partir do índice especificado.

indexOf(int ch, intfromIndex)

Retorna o índice da primeira ocorrência do caractereno string a partir do índice especificado.

indexOf(int ch) Retorna o índice da primeira ocorrência do caractereno string .

length() Retorna o comprimento do string.replace(char oldChar,char newChar)

Retorna uma nova String onde todos os caracteresoldChar foram substituídos pelos caracteresnewChar.

substring(int beginIndex) Retorna uma nova string que é substring da atual.substring(int beginIndex,int endIndex)

Retorna uma nova string que é substring da atual.

toLowerCase() Converte para minúsculas.toUpperCase() Converte para Maiúsculas.trim() Remove os espaços em branco do inicio e do fim do

String.valueOf(Object obj) Retorna a representação em String do argumento

Object.valueOf(char c) Retorna a representação em String do argumento

char.valueOf(boolean b) Retorna a representação em String do argumento

booleano.valueOf(long l) Retorna a representação em String do argumento

long.valueOf(int i) Retorna a representação em String do argumento int..valueOf(char[] data) Retorna a representação em String do argumento

array de caracteresvalueOf(float f) Retorna a representação em String do argumento

float.valueOf(double d) Retorna a representação em String do argumento

double.

Page 42: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

41

Tabela III-9. Principais métodos da classe String.

Os literais de Strings são tratados como instâncias da classe String ecomo tal possuem os métodos de um objeto da classe String. Por exemplo,após a execução da expressão abaixo a variável x conterá o valor 5.

int x = “Pedro”.length();

Conversão de Tipos

De forma geral as conversões entre tipos em Java devem serespecificadas explicitamente. A forma mais comum de se especificar umaconversão é por meio da notação abaixo:

(<tipo destino>) <expressão>

Por exemplo:

int i = 10;char c = (char) i;

Este tipo de conversão é chamada de casting. O programador deve ficarbastante atento no que diz respeito a conversões, uma vez que pode acontecerperda de informação quando convertemos um tipo para outro que ocupa umespaço menor na memória. A tabela abaixo mostra as conversões entre tiposprimitivos que podem causar perda de informação:

do tipo para o tipobyte charshort byte, charchar byte, shortint byte, short, charlong byte, short, char, intfloat byte, short, char, int, longdouble byte, short, char, int, long, float

Tabela III-10. Conversão de tipos que podem causar perda de informação.

Page 43: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

42

Outra forma de converter tipos é usando os métodos fornecidos pelasclasses associadas aos tipos. A tabela abaixo mostra a classe associada a cadatipo primitivo.

Tipo Classeint Integerfloat Floatdouble Doubleboolean Booleanbyte Byteshort Shortlong Long

Tabela III-11. Classes associadas a cada tipo primitivo.

As classes fornecem métodos para conversão mais sofisticados como dotipo primitivo para String e vice-versa. Por exemplo, a classe Integerfornece um método para converter String para int:

int i = Integer.parseInt(“12”);

Para se converter um inteiro para String podemos utilizar o métodotoString():

String s = Integer.toString(12);

Existem métodos semelhantes nas outras classes. Existe também um tipode conversão que somente se aplica aos operandos do operador binário ‘+’quando um dos operandos é um objeto da classe String. Caso o outro operandonão seja um objeto da classe String, então ele será convertido para String e oresultado da operação será a concatenação das duas cadeias. As Conversõesentre objetos de classes distintas serão tratadas no próximo Capítulo.

Operadores

Os operadores atuam sobre valores e variáveis de modo a gerar novosvalores ou modificar os valores das variáveis. Os símbolos abaixo representamos 37 operadores da linguagem Java:

Page 44: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

43

= > < ! ~ ? :== <= >= != && || ++ --+ - * / & | ^ % << >> >>>+= -= *= /= &= |= ^= %= <<= >>= >>>=

Os operadores podem ser divididos nas seguintes classes.

Unários

Descrição SímboloIncremento ++Decremento --Negativo -Complemento de bit ~

Tabela III-12. Operadores unários.

Os operadores de incremento e decremento (++ e --) aumentam edecrementam variáveis de tipo inteiro de uma unidade. Estes operadores podemser usados na forma prefixa ou pósfixa. Na forma prefixa o operador modifica ovalor da variável antes que o valor seja usado na expressão onde está a variável.Na forma pósfixa o operador modifica o valor da variável depois que o valor éusado na expressão onde está a variável. Por exemplo, o valor das variáveis x,y e w após a execução do trecho de código abaixo

int x = 1, y, w;

y = x++;w = --x;

é 1. Isto ocorre porque y recebe o valor de x antes de ser incrementado e wrecebe o valor de x depois de ser decrementado.

O operador de negação unário (-) é usado para mudar o sinal de um valorinteiro. O operador de Complemento de bit (~) inverte cada bit da representaçãobinária de um inteiro. O exemplo abaixo mostra efeito da aplicação desteoperador.

byte x = 10; // valor em binário 00001010

Page 45: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

44x = ~x; // valor em binário 11110101; valor em decimal 245.

O programa abaixo mostra o uso de cada operador unário.

public class Unarios { public static void main (String args[]) { int x = 10, y = 0;

System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("++x = " + ++x); System.out.println("y++ = " + y++); System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("-x = " + -x); System.out.println("~y = " + ~y); }}

Saída:

x = 10y = 0++x = 11y++ = 0x = 11y = 1-x = -11~y = -2

Exemplo III-2. Uso dos operadores unários.

Binários

Descrição SímboloAdição e concatenação de strings +Subtração -Multiplicação *Divisão /Módulo %E de bit &OU de bit |OU exclusivo de bit ^deslocamento de bits a esquerda <<

Page 46: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

45

deslocamento de bits a direita >>des. a direita com preenchimento zero >>>

Tabela III-13. Operadores binários.

Acreditamos que os operadores binários para adição, subtração,multiplicação, divisão e concatenação de Strings não necessitam maioresexplicações. O operador de módulo (%) retorna o resto da divisão entre doisoperandos inteiros. Por exemplo, o valor da variável x após a execução do trechode código

int x = 7 % 4;

é 3.Os operadores &, | e ^ implementam operações orientada para bits, ou

seja, operações que atuam sobre os bits individuais dos operandos. São úteisquando se usa valores como campos de bits. O operador & realiza a operaçãológica E entre cada bit individual dos operandos. Por exemplo, o valor davariável x após a execução do trecho de código

byte y = 3;byte x = Y & 5;

é 1.O operador | realiza a operação lógica OU entre cada bit individual dos

operandos. Por exemplo, o valor da variável x após a execução do trecho decódigo

byte y = 3;byte x = Y | 5;

é 7.O operador ^ realiza a operação lógica XOU (ou exclusivo) entre cada bit

individual dos operandos. Por exemplo, o valor da variável x após a execução dotrecho de código

byte y = 3;byte x = Y & 5;

é 6.

y 000000114 00000101 &1 00000001

y 000000114 00000101 |7 00000111

y 000000114 00000101 ^1 00000110

Page 47: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

46

Os operadores <<, >> e >>> implementam operações de deslocamento debits. Os bits do operando à esquerda serão deslocados o número de posiçõesespecificadas pelo operando à direita. Os bits que saem dos limites do campo sãoperdidos e a variável é preenchida com zeros no lado oposto ao deslocamento. Ooperador << realiza a operação de deslocamento de bits a esquerda. Porexemplo, o valor da variável x após a execução do trecho de código

byte x = 7 << 1;

é 14. Note que o deslocamento de uma unidade para a esquerda tem o mesmoefeito da multiplicação por 2, desde que nenhum bit seja. Os operadores >> e>>> realizam a operação de deslocamento de bits a direita. A diferença entre ooperador >> e o >>> é que o primeiro não desloca o bit de mais alta ordemusado para indicar números negativos. O programa abaixo ilustra o uso dessesoperadores:

public class Deslocamento { public static void main (String args[]) { int x = 7, y =–7;

System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("x << 1= " + (x<<1)); System.out.println("x >> 2= " + (x>>2)); System.out.println("y >> 2= " + (y>>2)); System.out.println("y >>> 31= " + (y>>>31)); }}

Saída:

x = 7y = -7x <<= 14x >> 2= 1y >> 2= -2y >>> 30= 3

Exemplo III-3. Uso dos operadores de deslocamento de bits.

Note que no caso do número positivo o deslocamento à direita teve oefeito de uma divisão inteira por dois. Já quando o número é negativo este efeito

Page 48: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

47

não ocorre, devido ao fato da representação de números inteiros ser feita emcomplemento a dois.

Relacionais

Descrição SímboloMenor que <Maior que >Menor igual <=Maior igual >=Igual ==Diferente !=

Tabela III-14. Operadores relacionais.

Os operadores relacionais são usados para comparar valores. O resultadoda aplicação desses operadores é um valore boolano, ou seja :true ou false. Oprograma abaixo ilustra o uso desses operadores:

public class Relacional { public static void main (String args[]) { int x = 7, y = 8; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("x < y = " + (x < y)); System.out.println("x > 10 = " + (x > 10)); System.out.println("y <= 8 = " + (y <= 8)); System.out.println("y == 5 = " + (y == 5)); System.out.println("x != y = " + (x != y)); }}

Saída:

x = 7y = 8x < y = truex > 10 = falsey <= 8 = truey == 5 = falsex != y = true

Exemplo III-4. Uso dos operadores relacionais.

Page 49: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

48

Booleanos

Descrição SímboloE &OU |OU Exclusivo ^E Curto circuito &&OU Curto circuito ||Negação !Igualdade ==Condicional ?:

Tabela III-15. Operadores booleanos.

Os operadores booleanos atuam sobre valores booleanos e retornam umvalor booleano. A tabela abaixo resume o resultado da aplicação dos operadoresbooleanos, exceto o operador condicional (?:) e o de negação (!):

Operando 1 Operando 2 & | ^ && || ==true true true true false true true truetrue false false true true false true falsefalse true false true true false true falsefalse false false false false false false true

Tabela III-16. Resumo dos operadores booleanos.

O operador de negação muda o valor booleano como mostrado na tabelaabaixo:

Operando !true falsefalse true

Tabela III-17. Operador de negação.

Page 50: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

49

O operador condicional atua sobre três operandos: uma expressãocondicional e duas outras expressões quaisquer. A forma geral do operador é

<condição> ? <expressão 1> : <expressão 2>.

Se <condição> for avaliada como true, então o resultado da aplicaçãodo operador condicional será o retorno da avaliação da <expressão 1>. Casocontrário o resultado da avaliação da <expressão 2> será retornado. Oprograma abaixo ilustra o uso deste operador:

public class Condicional{ public static void main (String args[]) {

int x = 5;

boolean par = (x % 2 == 0) ? true : false;System.out.println("x = " + x);System.out.println("É par = " + par);

}}

Saída:

x = 5É par = false

Exemplo III-5. Uso do operador condicional.

Atribuição

Descrição SímboloSimples =Adição +=Subtração -=Multiplicação *=Divisão /=Modulo %=AND &=OR |=XOR ^=

Page 51: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

50

Tabela III-18. Operadores de atribuição.

Os operadores de atribuição simplesmente atribuem um valor a umavariável. Exceto o operador de atribuição simples (=), todos os outros operadoresna forma

<variável> <op>= <expressão>

funcionam como uma maneira abreviada de se escrever

<variável> = <variável> <op>(<expressão>)

Por exemplo, a atribuição

x += 2;

tem o mesmo significado da atribuição

x = x +2;

Esta forma de escrever facilita a trabalho de digitação, porém torna ocódigo fonte menos legível.

Expressões e Precedência entre Operadores

Expressões são trechos de códigos que geram valores. Portanto, o trechode código 1+2 é uma expressão pois gera o valor 3. Literais também sãoexpressões pois geram o próprio valor que representam. Portanto, o literal 3.14 étambém uma expressão. As variáveis que ocorrem em uma expressão sãotambém expressões, pois representam o valor que armazenam.

As expressões são combinadas por meio dos operadores para formarexpressões maiores. Assim, podemos combinar as expressões 3 e 5*6 por meiode um operador tipo + para formar a expressão

3+5*6

Uma pergunta que pode surgir é: como a expressão é avaliada? Ou seja,que operador é aplicado primeiro: o + ou o *? Dependendo da ordem deaplicação dos operadores o resultado da avaliação da expressão pode serdiferente, como no caso acima. A ordem de aplicação obedece uma prioridade

Page 52: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

51

definida pela precedência relativa entre os operadores. A tabela abaixo define aprecedência entre os operadores. A precedência decresce de cima para baixo. Emse tratando de operadores com a mesma precedência a avaliação em umaexpressão é feita da esquerda para a direita.

. [] ()++ -- ! ~* / %+ -

<< >> >>>< > <= >=

== !=&^

&&||?:=

Tabela III-19. Precedência de operadores.

Comentários

Comentar o código fonte faz parte das regras que definem um bom estilode programação. Java possui três diferentes formas de se comentar o código,ilustradas abaixo:

// comentário de linha/* comentário de bloco *//** comentário de bloco c/ propósito de documentação */

As duas primeiras formas de comentário são familiares para osprogramadores de C++. Na primeira forma, todos os caracteres posicionadosapós “//” e antes do final da linha são ignorados pelo compilador. Na segundaforma todos os caracteres que ocorrem após “/*” são ignorados pelocompilador, até que seja encontrado a sequência “*/”. A terceira forma decomentário é semelhante a segunda, com a diferença de que é usada pelaferramenta de documentação javadoc para gerar uma documentação no formatoHTML (HyperText Markup Language). O uso dessa ferramenta será tratado no

Page 53: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

52

final do próximo capítulo. O exemplo III-6 repete o código do exemplo III-5com a adição de alguns comentários:

public class Condicional{ // classe para teste do operador ?: public static void main (String args[]) {

int x = 5; // variável usada para o teste/* Será impresso true se x for par*/boolean par = (x % 2 == 0) ? true : false;System.out.println("x = " + x);System.out.println("É par = " + par);

}}

Exemplo III-6. Uso de comentários.

Blocos e Escopo

Na linguagem Java, assim como em C/C++ um bloco de comandos édelimitado pelos caracteres ‘{’ e ‘}’. Os blocos são utilizados para agruparcomandos que são relacionados. Um bloco também pode conter blocos,chamados de blocos internos. Todas as variáveis declaradas em um bloco podemser referenciadas apenas dentro do bloco e nos blocos internos ao bloco onde foidefinida, desde que não exista nenhuma variável no bloco mais interno com omesmo nome. As seções onde uma determinada variável pode ser acessadadefinem a escopo da variável. A figura III-1 ilustra a relação entre blocos eescopo.

public class Visivel { public static void main (String args[]){ int x = 5;

int y = 2;...{ int x =2;...}...

}}

escopo do x interno

escopo do x externo

escopo de y{ }

}}

Page 54: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

53

Figura III-1. Visibilidade de variáveis.

Estruturas de Controle

As estruturas de controle definem a sequência de execução dasinstruções. Não é possível implementar um algoritmo que não seja trivial emuma linguagem de programação que não tenha um conjunto mínimo deestruturas de controle. As estruturas de controle podem ser divididas em seleção,repetição e sequência. A sequência é simplesmente definida pela execuçãosequencial dos comandos, de cima para baixo. Falta abordarmos as estruturaspertencentes às outras duas classes.

Seleção

Na seleção o fluxo sequencial de execução é desviado segundo umacondição ou valor. Java apresenta duas formas seleção: o if e o switch.

if

O comando de seleção de if possui duas formas básicas:

if (condição)comando1

if (condição)comando1

elsecomando2

(a) (b)

Na forma (a) o comando1 é executado se condição for avaliada comotrue. Na forma (b) o comando1 é executado se condição for avaliada comotrue senão o comando2 é executado.

if (x==0)y = 5;

elsey+=6;

Exemplo III-7. Comando if.

Page 55: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

54

Se o comando a ser executado for na verdade um conjunto de comandosdevemos então usar os delimitadores de bloco ‘{’ e ‘}’ para agrupar oscomandos em um único bloco.

if (x==0)y = 5;

else{

y+=6;x++;

}

Exemplo III-8. Comando if executando um bloco.

Os comandos if podem combinar em forma aninhada como mostrado noexemplo III-9.

if (x==0) if (y == 1) x= y; else y+=6;

Exemplo III-9. ifs aninhados.

O aninhamento como no exemplo III-9 deixa uma dúvida com que if oelse está relacionado? Com o mais interno ou o mais externo? A regra paraesses casos é: o else se relaciona com o if mais interno. Essa regra pode seralterada, utilizando os delimitadores ‘{’ e ‘}’ para definir os blocos decomandos, como mostrado no exemplo III-10.

if (x==0){ if (y == 1) x= y;}else y+=6;

Page 56: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

55

Exemplo III-10. Uso de blocos para definir o par if-else.

switch

O comando switch é útil quando existem várias ações distintas queprecisam ser realizadas em função do resultado da avaliação de uma expressão.Não é nada que não poderia ser feito com um conjunto de if-else, no entanto ouso do switch facilita codificação e a legibilidade do programa. A forma geraldo comando está definida abaixo:

switch(Expr){

case const1: com1;...case constN: comN;default: comDef

}

O comando switch avalia a expressão Expr e compara o valor resultantecom todas as constantes colocadas após a palavra a chave case. A comparação éfeita na ordem de cima para baixo e a primeira constante que igualar com o valorresultante da expressão faz com que os comandos após o ‘:’ sejam executadosaté o fim ou até que seja encontrado o comando break. A palavra chavedefault é opcional e ela serve como ponto de entrada para os comandos queserão executados caso o valor da expressão não seja igual a nenhuma dasconstantes. O exemplo III-11 ilustra o uso do comando switch.

switch(letra){

case ‘i’: System.out.println(“inserir”);break;

case ‘a’: System.out.println(“alterar”);break;

case ‘e’: System.out.println(“excluir”);break;

default: System.out.println(

“Ação ignorada: ”+letra);}

Page 57: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

56

Exemplo III-11. Uso do comando switch.

O comando break é muito importante na composição do switch. Ele fazcom que a execução sequencial dos comandos seja interrompida para serretomada no primeiro comando após o comando switch. O exemplo III-12mostra as saídas de um programa com um comando switch que não faz uso docomando break. Note que todos os comandos são executados, uma vez que nãoexiste um comando break para interromper a execução.

public class Switch { public static void main (String args[]) { char letra = ‘i’; switch(letra) { case ‘i’: System.out.println(“inserir”); case ‘a’: System.out.println(“alterar”); case ‘e’: System.out.println(“excluir”); default: System.out.println( “Ação ignorada: ”+letra); } }}

Saída:

inseriralterarexcluirAção ignorada:i

Exemplo III-12. Uso do comando switch sem break.

O leitor pode se estar perguntando porque a sequência de comandos nãoé interrompida automaticamente em vez de deixar para o programador a tarefade sinalizar isso por meio do comando break. A verdade é que a omissão docomando break pode ser útil para poupar digitação naqueles casos onde mais deuma opção precisa executar a mesma sequência de comandos. O exemplo III-13mostra um desses casos.

switch (mês) { case 1:

Page 58: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

57 case 3: case 5: case 7: case 8: case 10: case 12: dias = 31; break; case 4: case 6: case 9: case 11: dias = 30; break; case 2: if (((ano % 4==0) && !(ano % 100 == 0)) || (ano % 400 == 0) ) dias = 29; else dias = 28; break;}

Exemplo III-13. Uso útil da omissão do comando break.

Repetição

Os comandos de repetição, ou de iteração, executam um comando ou umbloco de comandos várias vezes. É uma das formas para executar repetidamenteum comando. A outra é a recursão que é a chamada direta ou indireta de ummétodo durante a execução do próprio método. Em Java existem três formas decomandos de repetição: o while; o do-while; e o for.

while

A forma geral do comando while é:

while(condição)Comando;

O comando while executa Comando enquanto condição for avaliadacomo true. Portanto, para encerrar a iteração é necessário que exista apossibilidade da execução de Comando alterar a avaliação de condição. Acondição é testada antes da execução do comando. O exemplo III-14 mostra asoma dos 100 primeiros números inteiros.

int i = 1;

Page 59: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

58int x = 0;while(i<=100)

x +=i++;

Exemplo III-14. Soma dos 100 primeiros números inteiros.

Se for necessário executar mais de um comando deve-se agrupá-los pormeio de delimitadores de bloco, como mostrado no exemplo III-15.

while(i<=100){ x *=y; i++;}

Exemplo III-15. - Uso de while com bloco.

do-while

A forma geral do comando do-while é:

doComando;

while(condição)

O comando do-while executa Comando enquanto condição foravaliada como true. A diferença em relação ao comando while é que acondição é testada após a execução do comando. O exemplo III-16 mostra asoma dos 100 primeiros números inteiros. Os comandos também podem seragrupados em um bloco.

int i = 1;int x = 0;

dox +=i++;

while(i<100);

Exemplo III-16. Soma dos 100 primeiros números inteiros com do-while.

Page 60: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

59

for

A forma geral do comando for é:

for(Cod.Inicialização;condição; Cod.passo)Comando;

No comando for o Cod.Inicialização (código de inicialização) éexecutado uma vez, a condição é avaliada antes de cada iteração e oComando e o Cod.passo é executado a cada iteração. O Cod.passo éexecutado após o Comando. Todas as seções do comando for podem seromitidas. Enquanto condição for avaliada como true é executada mais umaiteração. Em geral, o Cod.Inicialização é utilizado para inicializar avariável que será testada na condição e o Cod.passo é utilizado para alteraro valor da mesma. O exemplo III-17 mostra a soma dos 100 primeiros númerosinteiros.

x = 0;for(int i=1; i<=100; i++)

x +=i;

Exemplo III-17. Soma dos 100 primeiros números inteiros com for.

Tanto o Cod.Inicialização como o Cod.passo podem sercompostos de vários comandos. Cada comando é separado por ‘,’. O exemploIII-18 ilustra esta forma de uso do comando for.

for(int i=1, x = 0; i<=100; i++)x +=i;

Exemplo III-18. Soma dos 100 primeiros números inteiros com for.

Como já foi dito, todas as seções do comando for podem ser omitidas. Oexemplo III-19 mostra uma iteração infinita, definida pela omissão das seções docomando for.

Page 61: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

60

for(;;)System.out.println(“ola mundo”);

Exemplo III-19. Iteração infinita.

break e continue

Já vimos o uso do comando break quando discutimos o comandoswitch. Ele servia para interromper a sequência de execução dos comando e sairdo comando switch. Isto não acontece apenas no comando switch. Toda vezque um break é encontrado, o fluxo de execução “salta” para fora do bloco ondeestá contido o break, sendo retomado no comando após o bloco. A figura III-2ilustra este comportamento.

for (;;){...break;...} fluxo retomado aqui...

Figura III-2. Uso do comando break.

O uso mais comum do comando break ocorre em uma condição de testedentro de uma iteração. O exemplo III-20 é equivalente ao exemplo III-18.

for(int i=1, x = 0;; i++) if (i==101) break; else x +=i;

Exemplo III-20. Soma dos 100 primeiros números inteiros com for e break.

Já o comando continue é usado dentro de uma iteração e faz com queocorra um desvio para a condição de teste da iteração. Ou seja, o comandocontinue força um salto para próxima iteração. A figura III-3 ilustra estecomportamento.

Page 62: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

61

while (Condição){... fluxo retomado aquicontinue;...}...

Figura III-3. Uso do comando continue.

Como no comando break, o uso mais comum do comando continue éem uma condição de teste dentro de uma iteração.

Argumentos da linha de comando

Os argumentos digitados na linha de comando são passados para ométodo main() da classe invocada por meio de um vetor de Strings. Porexemplo, se executarmos a linha de comando abaixo

java teste um dois três

o método main() da classe teste receberá o seguinte vetor de Strings:

[0] um

[1] dois

[2] três

Figura III-4. Vetor com os argumentos da linha de comando.

Para quem está acostumado a programar na linguagem C note o primeiroelemento do vetor não é o nome do programa e sim o primeiro argumento dalinha de comando. O espaço serve como separador de argumentos. Sedesejarmos tratar uma cadeia de caracteres com espaço como um únicoargumento é necessário delimitá-la com aspas duplas. Por exemplo, o comandoabaixo

Page 63: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

62

java teste um “dois três”

resulta no seguinte vetor:

[0] um

[1] dois três

Figura III-5. Vetor com os argumentos da linha de comando com aspas.

O classe do exemplo III-21 mostra um programa que imprime osargumentos recebidos, um em cada linha do dispositivo de saída.

public class ImpLinha{

public static void main(String args[]){

int i;for (i=0;i<args.length;i++)

System.out.println(args[i]);}

}

Exemplo III-21. Imprimindo a linha de comando.

Todos os argumentos são tratados como Strings. Se houver necessidadede tratar os argumentos como pertencendo a um tipo diferente será precisorealizar as conversões necessárias. No exemplo III-22 os argumentos sãoconvertidos para números inteiros para serem somados.

public class Soma{

public static void main(String a[]){int i,soma=0;for (i=0;i<a.length;i++)

soma += Integer.parseInt(a[i]);System.out.println(“A soma é:”+soma);

}}

Exemplo III-22. Imprimindo a soma dos números.

Page 64: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

63

Assert (Assertivas)

Com o surgimento da versão 1.4 do SDK uma nova alteração nalinguagem Java foi introduzida, envolvendo a inclusão de uma nova palavrareservada: a palavra assert. O objetivo desta alteração é incluir na linguagemrecursos que permitam que o programador verifique se uma dada condição,chamada de assertiva, é verdadeira em um local específico do código. Istopossibilita o desenvolvimento de códigos mais confiáveis, sendo um recursoutilizado durante a etapa de desenvolvimento e desabilitado em tempo deexecução.

Devido a inclusão de uma nova palavra chave, códigos fontespreexistentes que incluam a palavra assert como identificador gerarão erro decompilação ao serem compilados com a versão 1.4 do SDK. Este problema decompatibilidade é solucionado por meio de flags de compilação.

A linguagem C++ possui recurso semelhante, com a diferença de serimplementado por meio de biblioteca e não a nível de linguagem. No caso deJava, a decisão de não utilizar uma biblioteca para implementação deste recursodeveu-se ao objetivo de se buscar uma implementação mais transparente, apesardo inconveniente da perda de compatibilidade.

A inclusão de recursos de para verificação de condições estava presentena especificação original da linguagem, quando ainda era denominada oak, maisfoi retirada da primeira versão por se acreditar que não haveria tempo para sedesenvolver uma implementação adequada.

Sintaxe e semântica

A formato geral de uma assertiva é:

assert<expressão booleana1>;

ou

assert<expressão booleana1>:<expressão booleana2>;

A avaliação de uma assertiva funciona da seguinte forma: a primeiraexpressão é avaliada. Caso o resultado seja false e não exista uma segundaexpressão então a exceção AssertionError é lançada. Caso o resultado sejafalse e exista uma segunda expressão então ela é avaliada e o resultado épassado para o construtor da exceção AssertionError antes de ser lançada.Caso o resultado seja da primeira expressão seja true então a segunda expressão,caso exista, não será avaliada.

Page 65: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

64

O exemplo III-23 mostra um exemplo do uso de assertivas para garantirque uma determinada condição seja verdadeira.

... assert b > 0; int x = a/b;...

Exemplo III-23. Uso de assertivas.

Habilitando e Desabilitando Assertivas

As assertivas podem ser habilitadas/desabilitadas por flags na linha decomando e chamadas a métodos durante a execução. A habilitação/desabilitaçãopode ter uma atuação que varia desde o envolvimento de uma única classe atéum pacote ou todo o programa. Por default as assertivas estão desabilitadas.

Habilitação por flags

A forma geral para a habilitação de assertivas é:

java [-enableassertions | -ea] [:<nome package>“...” |:<nome classe>]

O flag sem argumento habilita as assertivas para todas as classes. Se forseguindo por o nome de um pacote seguido por “...” as assertivas serãohabilitadas para o pacote especificado e todos os subpacotes. Se for seguidoapenas de “...”as assertivas serão habilitadas para o pacote do diretório corrente etodos os subpacotes. Se o argumento não terminar com “...”, então as assertivasserão habilitadas apenas para a classe especificada. Abaixo segue um exemplode habilitação de assertivas:

java –ea:br.ufv.dpi.apo... Teste

A desabilitação de assertivas segue a mesma lógica, mudando apenas oflag que passa ser –disableassertions ou –da.

Page 66: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

65

Habilitação por métodos

Os seguintes métodos da classe ClassLoader podem ser invocados parahabilitar/desabilitar as assertivas em tempo de execução:

void setDefaultAssertionStatus(boolean status)– habilita/desabilita pordefault as assertivas.

void setPackageAssertionStatus(String nomepack, boolean status)–habilita/desabilita as assertivas no pacote e subpacotes.

void setClassAssertionStatus(String nomeclasse, boolean status)–habilita/desabilita as assertivas na classe.

void clearAssertionStatus()– retorna ao default.

Page 67: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

66

Capítulo IV Classes, Pac kages eInterfaces

A unidade fundamental de programação em Java é a Classe. Não épossível fazer um programa em Java que não tenha pelo menos uma classe. Issonão é verdade para todas as linguagens Orientadas a Objeto. Em C++, porexemplo, é possível fazer um programa que não use classe. Em Java todas asvariáveis e métodos de um programa Java devem ser definidos dentro de umaclasse. Um programa que não contenha classes não é um programa orientado aobjetos. No entanto, o fato de um programa conter classes também não o tornamerecedor do título de “orientado a objetos”. A programação orientada a objetosé mais um estilo de programação do que um conjunto de palavras-chavecolocadas em um programa. Porém, é obviamente melhor implementar esteestilo usando uma linguagem que oferece suporte a ele. Neste capítuloestudaremos o suporte oferecido por Java a este estilo de programação. Não só aimplementação de classes será vista, como também conceitos relacionados,como pacotes e interfaces.

Classes

No Capítulo II foram discutidas Classes e Objetos do ponto de vista demodelagem e de implementação. Nesta seção será detalhada a implementação declasses em Java. A definição de uma classe em Java obedece a seguinte formageral:

[public] class <Identificador>{

<corpo da classe>}

A palavra reservada public é opcional e indica que a classe pode serreferenciada por qualquer outra classe além do próprio pacote (conceito que serávisto mais adiante). Apenas uma classe por arquivo pode ser precedida pelapalavra reservada public e o nome do arquivo tem que ser idêntico ao nomedesta classe. Se a declaração da classe não for precedida de public, então ela sópoderá ser referenciada por outras classes do mesmo pacote. Os modificadores

Page 68: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

67

de acesso private e protected não podem ser aplicados às classes. O<Identificador> é usado para referenciar a classe. No <corpo da classe>são definidos os atributos e métodos da classe. Na comunidade deprogramadores Java existe a convenção de associar às classes identificadoresque iniciem com letra maiúscula, enquanto que os identificadores de variáveis emétodos devem iniciar com letra minúscula. No exemplo IV-1 é mostrada adefinição da classe de uma classe com o identificador Pessoa. Nele foi definidoum construtor para atribuir valores aos atributos e definido os métodos paraacesso aos atributos. Note que os métodos que atribuem valores às variáveis daclasse iniciam com a palavra set e os métodos que retornam os valoresarmazenados nas variáveis da classe iniciam com a palavra get. Este padrão denomeação de método foi adotado a partir da versão 1.1 da linguagem e é muitoimportante seguí-lo, principalmente se pretendemos implementar JavaBeans,como será visto no Capítulo X.

public class Pessoa{ String nome; String telefone; String endereço;

public Pessoa(String n, String t, String e) { nome = n; telefone = t; endereço = e; }

public void setNome(String n) { nome=n; } public void setTelefone(String t) { telefone = t; } public void setEndereço(String e) { endereço = e; }

public String getNome() { return nome; } public String getTelefone() { return telefone; } public String getEndereço() { return endereço; }}

Exemplo IV-1. Definição da classe Pessoa.

Unidade de CompilaçãoCada arquivo fonte Java é uma unidade de compilação. Ao compilar o arquivo fonte o

compilador irá gerar um arquivo .class para cada classe constante no arquivo. O nome decada arquivo será o nome da cada classe.

Page 69: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

68

Os atributos ou variáveis declarados na classe são criados somentequando os objetos são criados. Ou seja, cada objeto da classe Pessoa terá a suavariável nome, telefone e endereço. Portanto, a variável pertence à instânciada classe e não à classe. Variáveis que pertencem ao objeto são chamadasvariáveis de instância. Com os métodos o raciocínio é o mesmo, ou seja, parapodermos usar o método getNome() é preciso criar um objeto da classe Pessoae usar o método getNome() deste objeto. Métodos que pertencem ao objeto sãochamados de métodos de instância. Como veremos mais adiante, podemos usar apalavra reservada static para declarar variáveis e métodos que pertencem àclasse (métodos e variáveis de classe).

Os métodos definem operações sobre os atributos. Eles possuem a formageral:

<modificador> <tipo> <identificador>(<parâmetros>){

<corpo do método>}

onde <modificador> é um modificador de acesso, <tipo> é o tipo do valor deretorno do método, <identificador> é o identificador do método e<parâmetros> é uma lista de parâmetros. O corpo do método é composto decomandos, expressões e declarações de variáveis locais ao método. Os métodosdo exemplo IV.1 são muito simples. Eles apenas retornam um valor ou atribuemum valor aos atributos do objeto.

Construtores

Podemos observar no exemplo IV-1 que existe um método público com omesmo nome da classe e que não define um valor de retorno. Métodos comoesse são denominados de construtores e são chamados pelo operador new. Umaclasse pode não ter construtor ou ter vários, desde que tenham diferentes tipos deargumentos. O interpretador decidirá qual chamar a partir dos argumentospassados para o construtor. Se o programador não declarar nenhum construtorentão o compilador irá criar automaticamente um construtor default para aclasse.

Valor de Retorno

Page 70: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

69

Com exceção dos construtores todos os outros métodos precisam retornaralgum valor. Se programador não precisa que o método retorne algum valor,então ele deve especificar que o método irá retornar o valor void que é o valorvazio. Se o método não foi definido com valor de retorno void e não é umconstrutor então é preciso que no corpo do método seja indicado o valor deretorno. Esta indicação deve ser feita em toda ramificação de código que leve aofim da execução do método e é feita com a palavra chave return seguida deuma expressão:

return <expressão>

A expressão pode ser uma variável, um literal ou qualquer outraexpressão que gere um valor do tipo especificado para o retorno da função. Oexemplo IV-2 mostra um método que retorna um inteiro. Note que todaramificação de código que leve ao fim da execução do método necessita de umcomando return.

public class ExemploIV2{... public int calc(int a) { if (a==0) return 1; else return a*a; }}

Exemplo IV-2. Método que retorna um inteiro.

Objetos

Para se criar um objeto de uma classe (ou uma instância da classe) épreciso primeiro declarar uma variável que irá referenciar o objeto, para depoiscriar o objeto. A declaração de um referência a um objeto é feita obedecendo aseguinte forma geral:

<nome da classe> <identificador>;

Por exemplo, para declarar uma referência à um objeto da classe Pessoadevemos adicionar a seguinte linha ao código.

Page 71: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

70

Pessoa p1;

Pode-se declarar mais de uma referência a objetos de uma classe em umaúnica declaração, separando os identificadores por vírgula.

Pessoa p1, p2;

Para criar um objeto usa-se o operador new conforme a forma geralabaixo:

<identificador> = <nome da classe>(<argumentos>);

onde <argumentos> é uma lista de argumentos que serão passados para ummétodo especial da classe, denominado de construtor. Por exemplo, para criarum objeto do tipo Pessoa podemos usar a declaração abaixo:

P1 = new Pessoa(“Ana”,”432-6969”,”Rua 17 134”);

Podemos também combinar a declaração da referência com a criação doobjeto em uma única linha de código.

Pessoa P1 = new Pessoa(“Ana”,”432-6969”,”Rua 17 134”);

Uma vez criado o objeto podemos acessar os elementos do objeto pormeio da referência ao objeto e do operador ‘.’. Por exemplo para acessar ométodo getNome() do objeto referenciado pela variável P1 devemos usar oseguinte código:

P1.getNome();

Para acessar um atributo diretamente a sintaxe é mesma. Por exemplo,para acessar o atributo nome diretamente basta usar a seguinte linha de código.

P1.nome;

O exemplo IV-3 mostra a criação de um objeto do tipo Pessoa e o acessoa seus membros. Para que a classe seja executável diretamente pela máquinavirtual é preciso que ela possua um método main() que servirá como ponto deentrada para a execução. Podemos então, inserir código no método main() paracriar uma instância da classe para que, a partir de então, possamos a acessar os

Page 72: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

71

membros do objeto. O método main() existe antes da criação da instância, eportanto pode ser acessado pela máquina virtual, porque foi declarado com omodificador static. Isto significa que o método pertence à classe (método declasse) e não ao objeto (método de instância).

public class Pessoa{ ... // igual ao exemplo IV.1 ... public static void main(String args[]) { Pessoa p; p = new Pessoa(“Ana”,”432-6969”,”Rua 17 134”);

// Acessa os dados via métodos System.out.println(“Nome:”+getNome()); System.out.println(“Telefone:”+ getTelefone()); System.out.println(“Endereço:”+ getEndereço());

// Altera o endereço setEndereço(”Rua 17 138”)

// Acessa os atributos diretamente System.out.println(“Endereço:”+ endereço); }}

Exemplo IV-3. Definição da classe Pessoa.

As implementações da classe Pessoa mostradas nos exemplos IV-1 eIV-3 possuem alguns problemas que iremos abordar gradativamente. O primeiroproblema está relacionado com o acesso direto aos atributos. Em um programabem projetado o acesso aos atributos da classe a partir de métodos definidos emoutras classe é restringido de modo a diminuir a dependência em relação àrepresentação interna de uma classe. Quanto maior for esta independência maioré a facilidade para manutenção do programa. Para se restringir o acesso aosmembros da classe deve-se preceder a declaração dos membros com palavrasreservadas denominadas de modificadores de acesso que serão descritos a seguir.

Page 73: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

72

Modificadores de acesso

Os modificadores de acesso tem por objetivo definir a visibilidade de ummembro de uma classe (atributo ou método) em relação à outras classes. Atabela IV-1 mostra os modificadores de acesso disponíveis em Java.

Modificador Descriçãodefault Somente classes do mesmo package possuem acessopublic Todos possuem acessoprotected Apenas os membros da classe e subclasseprivate Apenas os membros da classe

Tabela IV-1. Modificadores de acesso.

Quando não é especificado nenhum modificador de acesso é assumido omodificador default, também chamado de friend. Ou seja, não existe umapalavra reservada default. O acesso default determina que todas as classesdentro do mesmo package (pacote) podem acessar os membros da classecorrente. O conceito de package será detalhado mais adiante, no entantopodemos adiantar que um package é um agrupamento de classes e interface(também será vista mais adiante). Toda classe e interface pertence a umpackage, mesmo que o programador não indique o package explicitamente. Se oprogramador não indicar o package então será assumido que a classe ouinterface pertence ao package default.

O modificador public determina que todas as classes podem acessar omembro. Já o modificador protected limita o acesso ao membro apenas aosmembros da própria classe e aos membros das subclasses da classe. Finalmente,o modificador private limita o acesso ao membro apenas aos membros daprópria classe.

O exemplo IV-4 é uma redefinição da classe Pessoa, explicitando osmodificadores de acesso dos atributos com objetivo de limitar a visibilidade dosmesmos.

public class Pessoa{ protected String nome; protected String telefone; protected String endereço;

...

Page 74: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

73 // igual ao exemplo IV.1 ...}

Exemplo IV-4. Definição da classe Pessoa com os atributos protegidos.

O modificador de acesso usado para os atributos no exemplo IV-4 foi oprotected. Portanto, se for criada uma subclasse da classe Pessoa, esta poderáacessar diretamente os atributos da classe Pessoa. O exemplo IV-5 mostra adefinição da classe Funcionario como subclasse de Pessoa. Note que oatributo de instância salario da classe Funcionario é definido com omodificador de acesso private, impedindo, dessa forma, acessos diretos aoatributo a não ser por membros da própria classe. Note também que o construtorda classe Funcionario possui uma chamada a um método super. Esta chamadarepresenta, na verdade, uma chamada ao construtor da superclasse. Isto serávisto com maiores detalhes mais adiante.

public class Funcionario extends Pessoa{ private double salario;

public Funcionario(String n, String t, String e, double s) { super(n,t,e); salario = s; }

public void setSalario(double s) { salario = s; } public double getSalario() { return salario; }}

Exemplo IV-5. Definição da classe Funcionario.

Para utilizar a classe Funcionario pode-se criar uma terceira classe,como mostra o exemplo IV-6, com o um método main() que serve de ponto deentrada para o início da execução. Foi colocado propositadamente uma tentativade acesso ao atributo privado por um método externo à classe do atributo, demodo a ilustrar um acesso não permitido.

public class TesteFun{ public static void main(String a[]) {

Page 75: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

74 Funcionario f; f = new Funcionario(“Carlos”,”555-7777”, “Av Nova 32”,3000.0); System.out.println(“Nome:”+f.getNome());

// Acesso Ilegal. Use o método. System.out.println(“Salario:”+f.salario); }}

Exemplo IV-6. Utilizando a classe Funcionario.

Outros Modificadores

Além dos modificadores de acesso existem outros modificadores queestabelecem significados distintos da visibilidade. A tabela IV-2 exibe osmodificadores adicionais.

Modificador Descriçãostatic A variável ou método é comum a todas as instâncias da

classe.final O valor da variável não pode ser modificado.synchronized atribui o monitor do objeto ao thread corrente.native indica que se trata de um método nativos.

Tabela IV.2– Modificadores de adicionais.

O modificador static

Um atributo declarado com o modificador static significa que é umatributo da classe e não de instância. Em outras palavras, existirá apenas umatributo, ocupando uma única posição de memória, em vez de um atributo paracada instância, cada um com sua própria posição de memória. Como resultado, oatributo existirá antes mesmo que qualquer objeto seja criado e, se for público,poderá ser acessado prefixando-o com o nome da classe e o operador “.”. Oexemplo V-7 mostra uma classe com um atributo static. Note que o não épreciso declarar uma instância da classe X para que o atributo exista e paraacessá-lo basta prefixá-lo como nome da classe.

class X{

Page 76: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

75 static public int tot =0;}

public class Main{ public static void main(String a[]) { X.tot = 2; System.out.println(“Valor de tot:”+X.tot); }}

Exemplo IV-7. Classe com atributo static.

Outro efeito é que o atributo será compartilhado por todas as instânciasda classe. Desta forma, se um objeto alterar o conteúdo do atributo, a alteraçãoafetará todos os outros objetos da classe. O exemplo V-8 mostra a declaração dedois objetos da classe X. Um dos objetos altera o valor do atributo static e ooutro imprime o valor do atributo. Isto mostra que as alterações feitas por umobjeto no atributo é percebida por todos os outros objetos da classe.

class X{ static public int tot =0; public void inc() {tot++;}

}

public class Main{ public static void main(String a[]) { X x1, x2; x1 = new X(); x2 = new X();

// x1 modifica o valor x1.inc();

System.out.println(“Valor de tot:”+x2.tot); }}

Saída:

Page 77: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

76Valor de tot:1

Exemplo IV-8. Objetos com atributo static.

O modificador static também pode ser usado na declaração demétodos. Neste caso o método fica ligado à classe e não à instância, sendodenominado de método de classe. Como consequência o método pode seracessado antes de existir um objeto da classe. Vários exemplos mostrados nestelivro tem pelo menos um método static: o método main(). Ele serve comoponto de entrada para a execução da aplicação Java, uma vez que inicialmentenão existem objetos. Os métodos static não podem acessar atributos e outrosmétodos não estáticos da classe, a não ser que exista uma declaração de umobjeto da classe no corpo do método. Os métodos estáticos são muito usados emclasses utilitárias. Classes utilitárias são classes que servem para agruparmétodos que prestam algum tipo de serviço a outras classes. Por exemplo, ométodo exit() é um método estático da classe System. Ele serve para encerrara execução da máquina virtual corrente. Sendo um método estático não é precisocriar um objeto da classe System para acessá-lo. A classe System é uma classeutilitária, contendo vários métodos e atributos estáticos úteis para outras classes.

O Modificador final

O modificador final pode ser usado em atributos, métodos e classes. Omodificador final impede se modifique o que está sendo prefixado. Um atributoprefixado com final indica que uma vez definido seu valor ele não seráalterado. Ou seja, é uma constante. A definição do valor do atributo pode serfeito tanto na declaração como durante a execução do programa, sendo que estaúltima possibilidade não era permitida na versão 1.0 da linguagem Java. Oexemplo IV-9 mostra o uso do modificador final em atributos.

class X{ public int k =0;}

public class Main1{ public final int i = 1; public final int j; public final X x = new X();

Page 78: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

77

public Main1(){j = 2;}

public static void main(String a[]) { Main1 m = new Main1(); m.x.k= 3; // Erro : o atriuto não pode ser modificado // m.j = 4; System.out.println("Valor de k:"+ m.x.k); System.out.println("Valor de j:"+ m.j); System.out.println("Valor de i:"+ m.i); }}

Exemplo IV-9. Uso do modificador final em atributos.

Note que no exemplo IV-9 o atributo j é inicializado no construtor e nãona declaração. No exemplo o atributo k do objeto referenciado pelo atributo x émodificado, mesmo sendo x um atributo final. Isto ocorre porque x é umareferencia a um objeto e não o próprio objeto, portanto, no caso de referencias aobjeto, o modificador final implica que o atributo não pode referenciar outroobjeto, mas não significa que o objeto referenciado não possa ser modificado.

Um método declarado com o modificador com final não pode sersobrescrito em uma subclasse. Alguns compiladores podem aproveitar isso everificar se é possível definir as chamadas a esses métodos como inline. Naschamadas inline o compilador substitui a chamada ao método pelo o código dométodo, tornando mais eficiente a execução do programa. O exemplo IV-10mostra o uso do modificador final em um método.

class X{ public int k =0;

public final void mostra() { System.out.println("Valor de k:"+ k); }}

class SX extends X{ // Erro: Sobrescrita ilegal public void mostra() {

Page 79: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

78 System.out.println("k:"+ k); }}

Exemplo IV-10. Uso do modificador final em métodos.

Uma classe declarada com o modificador com final impede que sejamcriadas subclasses desta classe. O programador pode decidir fazer isso porrazões de projeto ou de segurança, já que neste caso ele terá certeza que afuncionalidade da classe não será alterada. Outra razão pode ser eficiência, umavez que os métodos de uma classe final também são final, e portanto podemser otimizados para serem tratados como inline.

Os Modificadores synchronized e native

O modificador synchronized é para controlar o acesso a áreas críticasno processamento concorrente em Java. É usado em métodos e blocos decomandos, e seu uso será discutido em detalhes no Capítulo XI.

O modificador native é usado em métodos para indicar que o métodofoi implementado em outra linguagem de programação. O programador deveapenas indicar a assinatura do método, como mostrado abaixo:

native int meuMetodo(int a);

O uso de chamadas nativas restringe a portabilidade do programa. Nomomento a linguagem Java só suporta chamadas nativas implementadas nalinguagem C/C++.

Referências Compartilhadas

Um outro problema das implementações da classe Pessoa mostradas nosexemplos IV-1 e IV-3 está relacionado com o compartilhamento de referências.No construtor, assim como nos métodos setXXX, o argumento é atribuídodiretamente às variáveis de instância. Como toda variável de objeto em Java é naverdade uma referência para o objeto então as variáveis de instância da classePessoa e os argumentos do construtor e dos métodos setXXX são referências aobjetos do tipo String. Portanto, ao atribuir diretamente o argumento àsvariáveis de instância geramos um compartilhamento de referências. Essasituação é melhor ilustrada graficamente, como pode ser visto na figura IV-1,

Page 80: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

79

onde é mostrado o compartilhamento entre o argumento n e a variável deinstância nome após a atribuição.

O problema do compartilhamento de referências, é que ele permiteacesso aos objetos referenciados internamente pelos objetos. Com isso é possívelmodificar, com métodos externos ao objeto, o objeto referenciado. No entanto,no caso particular dos objetos da classe String, isso não chega a ser umproblema. Strings são constantes, ou seja, seus valores não podem ser alteradosapós a sua criação e, portanto, objetos Strings podem ser compartilhados semriscos. Toda alteração em um objeto do tipo String retorna um novo objetoString, deixando a original inalterada.

Antes da atribuição

n

nome null

Após a atribuição

n

nome

Figura IV-1.Compartilhamento de referencias.

Se o programador desejar alterar o valor de uma cadeia de caracteres semcriar um novo objeto, então ele deve optar por utilizar a classe StringBufferque implementa uma sequência mutável de caracteres. No entanto, é precisoestar alerta para o problema de compartilhamento de referências. O trecho decódigo do exemplo IV-11 mostra uma ocorrência de compartilhamento dereferência. No exemplo a classe Pessoa é definida usando a classeStringBuffer para armazenar as sequências de caracteres. Os objetos da classeX possuem uma referência a um objeto do tipo Pessoa. Na construção do objetoPessoa são passados como parâmetros as referências dos objetos StringBufferdo objeto da classe X, gerando um compartilhamento de referencias. Quando éinvocado o método m1() do objeto da classe X, este concatena a sequência “fim”ao StringBuffer referenciado por n. Como n compartilha o mesmo objeto coma variável de instância nome do objeto Pessoa, então a alteração também afeta oobjeto Pessoa, ocasionando um efeito colateral, provavelmente indesejável.

Objeto

Objeto

Page 81: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

80

Para se evitar esta situação é necessário que o objeto crie uma cópia doobjeto que está recebendo e retorne uma cópia do objeto que referencia. No casode objetos do tipo StringBuffer basta construir um novo objeto, passandocomo parâmetro a String correspondente ao StringBuffer anterior, comomostrado abaixo:

nome = new StringBuffer(n.toString());

No entanto, no caso de objetos mais complexos é mais complicado criaruma cópia por meio do construtor. Neste caso é necessário criar uma cópiausando o método clone(). Este método será visto na próxima seção.

class Pessoa{ StringBuffer nome; StringBuffer telefone; StringBuffer endereço;

public Pessoa(StringBuffer n, StringBuffer t, StringBuffer e) { nome = n; telefone = t; endereço = e; } // O restante da da classe é semelhante ao exemplo VI.1 // ...}

public class X{ StringBuffer n = new StringBuffer("Pedro"); StringBuffer t = new StringBuffer("324-6789"); StringBuffer e = new StringBuffer("Rua 17/148 Natal"); Pessoa p;

public X() {p = new Pessoa(n,t,e);}

public void m1() { n.append("fim");}

public static void main(String a[]) { X x = new X(); x.m1(); System.out.println(x.p.nome); }}

Page 82: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

81

Exemplo IV-11. Exemplo de compartilhamento de referência.

Copiando Objetos

Como visto na seção anterior, a atribuição envolvendo duas referencias aobjetos acarreta um compartilhamento do objeto e não uma cópia do objetooriginal. No entanto, em algumas situações não queremos compartilhar umobjeto e sim criar uma cópia de um objeto que já existe, ou seja um clone.Existem dois tipos de modos de se clonar um objeto:

1- Cópia rasa (shallow copy) - neste caso os atributos do objeto resultanterecebem os valores dos atributos correspondentes no objeto original. Osobjetos referenciados pelo objeto original serão compartilhados peloobjeto resultante. A figura IV-2 ilustra este tipo de cópia. Note ocompartilhamento das referencias.

Figura IV-2.Cópia rasa entre os objetos A e D.

2- Cópia profunda (deep copy) - neste caso não só o objeto original écopiado como também todos os objetos por ele referenciados. Este tipode cópia pode ser bastante ineficiente. A figura IV-3 ilustra este tipo decópia.

Page 83: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

82

Figura IV-3.Cópia profunda entre os objetos A e D.

Java oferece suporte para a cópia rasa. Para que a classe esteja apta a serclonada é preciso que ela implemente a interface Cloneable (interfaces serãodiscutidas mais adiante).

O objeto this

Em algumas situações é necessário referenciar o próprio objeto corrente.Por essa razão todo objeto possui uma variável especial identificada por thisque contém uma referência para o próprio objeto. O exemplo IV.xx mostra umuso típico do atributo this. Ele mostra um método cujo parâmetro formal possuio mesmo nome de um atributo de instância. Para distinguí-los é necessárioqualificar o atributo da instância com o atributo this.

public class objetoGeo{ protected Color cor; protected int x, y;

public objetoGeo(Color cor, int x, int y) {

this.cor = cor; this.x=x; this.y = y; } public Color retCor() {return cor};}

Exemplo IV-12. Exemplo de uso do atributo this.

Outro uso típico e quando queremos passar a instância corrente comoargumento de um método. Como mostra o exemplo IV.xx.

class X{ ...

Page 84: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

83 public void mx(Y y) {

...; }}

class Y{ X x;

public void my() {

x.mx(this); ... }}

Exemplo IV-13. Exemplo de uso do atributo this como argumento.

No exemplo IV.xx o objeto da classe Y passa ele próprio comoargumento do método mx() do objeto da classe X.

Packages

Pacotes (Packages) é a solução proposta por Java para agrupar Classes eInterfaces relacionadas para compor bibliotecas. As Interfaces serão vistas maisadiante. Organizando as classes em pacotes evita a colisão entre os nomes dasclasses. No caso dos métodos isso não é necessário, pois métodos como omesmo nome em classes diferentes são facilmente distinguidos uma vez que sãoqualificados pelos objetos das classes. No entanto como distinguir classes com omesmo nome? Esse problema é muito comum, principalmente quando setrabalha em equipe. Como impedir que um programador trabalhando no mesmoprojeto crie uma classe com o mesmo nome que outra criada por outroprogramador? Na hora de unir as classes os sistema não irá compilar devido aoproblema de redeclaração de classes. Sendo Java uma linguagem para atuar naInternet o problema é ainda mais grave: como impedir que uma classe que foibaixada de outra máquina não possua o mesmo nome de uma classe. Paracontornar todos estes problemas foi criado os Pacotes.

Usando Packages

Page 85: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

84

Toda classe pertence a um pacote. No caso de o programador não indicara que pacote pertence a classe, o compilador irá assumir que a classe pertence aopacote default. Para se usar uma classe definida em outro package é preciso usara palavra chave import seguida do nome da classe qualificada pelo nome dopacote como mostra a forma geral abaixo:

import nome_Package.nomeClasse;

Por exemplo para importar a classe Color do pacote java.awt oprogramador deverá usar a diretiva abaixo:

import java.awt.Color;

Se o programador quiser importar todas as classes do pacote java.awtbasta usar o caractere ´*` no lugar do nome da classe:

import java.awt.*;

É possível usar uma classe declarada em outro pacote sem usar a palavrachave import. Nesse caso é necessário qualificar o nome da classe com onome do pacote toda vez que a classe for referenciada. Por exemplo, no caso daclasse Color seria necessário qualificá-la da seguinte forma:

java.awt.Color

Existem dois pacotes que não precisam ser importados para que possamser usadas as suas classes sem a qualificação: o pacote default e o pacotejava.lang. O pacote default agrupa todas a classes que estão no diretóriocorrente e o pacote java.lang agrupa as classes do núcleo básico dalinguagem.

Criando Packages

Para incluir uma unidade compilação em um pacote basta que oprogramador inclua a seguinte declaração no arquivo.

package nomepacote;

Page 86: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

85

Importante: a declaração acima precisa ser a primeira declaração noarquivo.

O nome do pacote pode ser composto por vários nomes separados pelocaractere ‘.’, como no caso do pacote java.awt.

As classes de um determinado pacote devem ser colocadas em umdiretório obedecendo a mesma estrutura do nome do pacote, a partir de algumdiretório constando na variável de ambiente classpath. A variável deambiente classpath indica os diretórios que servem como pontos de entradapara procura de classes pela máquina virtual.

Por exemplo, suponha que eu resolva colocar as classes sobre objetosgeométricos em um determinado pacote, digamos br.com.alcione.geo.Para indicar que unidade de compilação pertence a esse pacote devemos colocara diretiva adequada no início do arquivo fonte, como mostrado no exemploIV.xx.

package br.com.alcione.geo;

public class objetoGeo{ protected Color cor; protected int x, y;

public objetoGeo(Color cor, int x, int y) {

this.cor = cor; this.x=x; this.y = y; }; public Color retCor() {return cor};}

Exemplo IV-14. Indicando que uma classe pertence ao pacotebr.com.alcione.geo.

Para que a máquina virtual consiga achar o pacote devemos colocá-lo emdiretório com a mesma estrutura do nome do pacote e que tenha como raizalgum diretório constante na variável de ambiente classpath. Por exemplo,suponha que a variável classpath contenha os seguintes diretórios:

CLASSPATH=.;C:\JAVA\LIB;C:\meujavalib

então o arquivo objetoGeo.class resultante da compilação do arquivoobjetoGeo.java pode ser colocado no diretório:

Page 87: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

86

C:\meujavalib\br\com\alcione\geo

Note que a estrutura do diretório combina com a estrutura do nome dopacote. Para usar a classe em outra unidade de compilação basta incluir aseguinte diretiva no arquivo fonte:

import br.com.alcione.geo.*;

O formato do nome do pacote não foi escolhido por acaso. Se existe apretensão de usá-lo na Internet então deve-se adotar um nome que seja único narede. Para garantir esta unicidade utiliza-se o nome do domínio do criador dopacote com a ordem dos campos invertida, evitando assim a colisão de nome naInternet. Por exemplo, nome do pacote br.com.alcione.geo origina-se dainversão do nome do meu domínio (alcione.dpi.ufv.br) concatenado com onome geo.

Por simplicidade. na maioria dos exemplos adotados neste livro,adotaremos o pacote default.

O Mecanismo de Extensão

A partir da versão 1.2 a linguagem Java apresentou um mecanismo paraadicionar classes ao núcleo básico da linguagem, dispensando deste modo o usoda variável de ambiente classpath. Este mecanismo é chamado deMecanismo de Extensão. O mecanismo de extensão também oferece suportepara envio de classes pela rede para uso em Applets. As extensões são agrupadasem arquivos JAR que são abordados no capítulo que trata dos Applets. Uma vezfeito isso, pode-se transformar as classes em extensões utilizando uma das duasformas:

1. Extensão Instalada – colocando o arquivo JAR em um localpredeterminado na estrutura de diretórios do ambiente de tempo deexecução de Java (Java Runtime Environment ou JRE).

2. Extensão de download –Extensão referenciando o arquivo JAR de umaforma específica, a partir do manifesto de outro arquivo JAR.

Extensão Instalada

Page 88: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

87

Para incluir uma nova classe ou pacote no núcleo básico da linguagembasta colocar o arquivo JAR onde que contém a classe no diretório /lib/extdo ambiente de tempo de execução. O diagrama mostrado na figura IV.xxmostra a localização deste diretório dentro da estrutura de diretórios do ambienteJava.

Figura IV.xx- localização do diretório ext dentro da estrutura de diretóriosJava.

Por exemplo, suponha que desejamos acrescentar o pacote do exemploIX. às extensões da linguagem Java no ambiente local. Para isso devemos criarprimeiro o arquivo JAR. No ambiente DOS o comando seria o abaixo, executadono diretório acima do diretório /br:

jar cvf geo.jar br\com\alcione\geo\objetoGeo.class

Após isso colocaríamos o arquivo geo.jar dentro do diretório /ext.Para usar a classe o procedimento é idêntico ao uso no caso do classpath, ouseja basta colocar a seguinte diretiva no arquivo fonte:

import br.com.alcione.geo.*;

Extensão de Download

As extensões de download ocorrem quando arquivos JAR ou classes sãoindicados como extensões de outros arquivos JAR. Por exemplo, suponha que

Java 1.3

lib includebin jre

bin

bin

lib

audio cmm fonts ext images security

Page 89: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

88

existem dois arquivos JAR, x.jar e y.jar, localizados no mesmo diretório.Para tornar o arquivo y.jar uma extensão do arquivo y.jar basta colocar aseguinte informação no manifesto do arquivo x.jar:

Class-Path: y.jar

Deste modo toda classe no arquivo x.jar pode referenciar as classes dopacote y.jar. Se os arquivos não estiverem no mesmo diretório seránecessário indicar o caminho relativo até o arquivo da extensão. É possívelindicar várias extensões, separando-as por espaço ou usando várias diretivasClass-Path. Para indicar um diretório como extensão basta adicionar osufixo ‘/’ no ao nome do diretório. Por exemplo:

Class-Path: meudir/

Derivando classes

O reuso de componentes de programas tem sido uma das principais metasdos projetistas de linguagens de programação. A razão desta busca é que areutilização de componentes economiza esforços e acelera o processo dedesenvolvimento de sistemas de computadores. Essa meta pode ser atingida emparte por meio da criação de classes que são extensões de classes predefinidas.As extensões herdam todos os atributos da classe base ou superclasse. Porexemplo, suponha que alguém tenha definido uma classe para representar osdados de uma conta bancária:

Figura IV.2- Classe Conta.

Suponha também que além da conta corrente básica mais dois tipos deconta devam ser criadas: poupança e conta especial. A poupança possui todos os

Conta

-número:num-Saldo: float-CPF:Num

Page 90: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

89

atributos de uma corrente e mais um atributo contendo a data de abertura daconta que será usada para cálculo do valor dos juros e correção monetária queserá acrescentado ao saldo da conta. A conta especial possui todos os atributosde uma corrente e mais um atributo contendo o valor de limite de crédito.

No exemplo descrito acima seria um desperdício de tempo e código seprecisássemos codificar todos os atributos e métodos relacionados da classeConta nessas duas novas classes. Para evitar esta duplicação de esforço bastadeclaramos essas duas novas classes como subclasses da classe Conta. Destaforma apenas os atributos que não estão declarados na superclasse e métodosassociados precisam ser codificados, uma vez que os membros da superclassesão herdados pelas subclasses. A figura IV.3 mostra o diagrama de classecontendo o relacionamento entre as classes e o exemplo IV.13 mostra o códigoJava correspondente.

Page 91: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

90

Figura IV.3- Relação entre as classes.

public class Conta{ long numero; long cpf; double saldo;

public Conta(long n, long c, double s) { numero = n; cpf = c; saldo = s; } public long getNumero(){return numero;} public long getCpf(){return cpf;} public double getSaldo(){return saldo;} public void setSaldo(double s){saldo = s;} public void somaSaldo(double v){saldo += v;}}

import java.util.*;

public class CPoupanca extends Conta{ Date dataAber;

public CPoupanca(long n, long c, double s, String d) { super(n,c,s); dataAber = new Date(d);

Conta

-número:num-Saldo: float-CPF:Num

CPoupança

-DataAber:Data

CEspecial

-Limite: float

Page 92: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

91 } public String getData(){return dataAber.toString();}}

public class CEspecial extends Conta{ double limite;

public CEspecial(long n, long c, double s, double l) { super(n,c,s); limite = l; } public double getLimite(){return limite;} public double getSaldo(){return saldo+limite;} public void setLimite(double l){ limite = l;}}

Exemplo IV-15. Implementação das Classes.

Podemos notar que para declarar uma classe como subclasse de outrabasta colocarmos a palavra-chave extends após o nome da classe e o nome dasuperclasse após a palavra-chave. Apenas o nome de uma superclasse épermitido, portanto Java não permite que uma classe seja subclasse de mais deuma classe (herança múltipla).

Herança MúltiplaA capacidade de possuir mais de uma superclasse é chamada de herança múltipla. A

linguagem C++ suporta a herança múltipla. No entanto, a implementação desta facilidade écomplexa e sua utilização tende a gerar erro. Além disso poucos são os casos que demandam ouso desta solução, e mesmo nestes casos é possível utilizar outras soluções. Por essas razões alinguagem Java não implementou a herança múltipla. Nos casos onde é necessário que um objetoadote o comportamento de mais de uma classe devemos utilizar as interfaces, como será vistomais adiante.

Todos os membros declarados com os modificadores public eprotected podem ser acessados diretamente na subclasse. O membrosdeclarados com o modificador private não são visíveis dentro da subclasse.

super

Page 93: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

92

Podemos notar também que no construtor das subclasses do exemploIV.12 existe uma chamada a um método super(). Este método representa achamada ao construtor da superclasse. Se não for chamado explicitamente ocompilador irá gerar código para chamar o construtor default da superclasse. Noentanto, se desejamos chamar explicitamente um construtor com argumentosdevemos usar o método super().

A classe Object

É importante salientar que toda classe em Java, com exceção da classeObject é subclasse de alguma classe. Se o programador não declarar a classebase então a classe base será a classe Object. Desta forma a classe Object éa raiz da hierarquia de classes da linguagem Java. Sendo assim, todo objeto nalinguagem Java herda os seguintes métodos públicos e protegidos da classeObject.

Métodos Públicos Descriçãopublic boolean equals(Objectobj)

Verifica se dois objetos são iguais. Averificação é feita sobre o endereço do objeto .

public final native ClassgetClass()

Retorna a classe do objeto em tempo deexecução.

public native int hashCode() Retorna o valor do objeto.public final native voidnotify()

Notifica um thread que está esperando sobreum objeto.

public final void notifyAll() Notifica todos os threads que está esperandosobre um objeto.

public String toString() Retorna uma representação em String doobjeto.

public final void wait() Espera para ser notificado por outro thread.public final void wait(longtimeout)

Espera para ser notificado por outro thread.

public final void wait(longtimeout, int nanos)

Espera para ser notificado por outro thread.

Métodos Protegidos Descriçãoprotected native Object clone() Cria uma cópia do objeto corrente.protected void finalize() Chamado pelo coletor de lixo antes de liberar a

área de memória.

Tabela IV.xx- Métodos público e protegidos da classe Object.

Page 94: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

93

Sobrescrita e Polimorfismo

Outro ponto interessante que podemos observar no exemplo IV.12 é quea classe CEspecial possui um método com a mesma assinatura que ummétodo da superclasse. É o método getSaldo() que no caso da classeCEspecial deve incluir o limite de crédito como parte do saldo.

Neste caso o método da subclasse está sobrescrevendo ou ocultando ométodo da superclasse. Toda vez que o método getSaldo() for invocadodentro de algum método da classe CEspecial ou for chamado por meio deum objeto da classe CEspecial o método chamado será uma instância dodeclarado na classe e não do declarado na superclasse. No entanto, é possívelinvocar uma instância do método declarado na superclasse de dentro de algummétodo da subclasse, bastando qualificar o método com a palavra chave supercomo mostrado abaixo:

super.getSaldo();

Por exemplo, o método getSaldo() da classe CEspecial poderiaser rescrito da seguinte forma:

public double getSaldo(){ return super.getSaldo()+limite;}

Suponha agora uma classe como mostrado no exemplo IV.13. O métodoimprimeSaldo() espera um objeto da classe Conta mas recebe um objeto daclasse CEspecial. Isto não causa nenhum problema porque todo objeto da classeCEspecial é também um objeto da classe Conta. No entanto fica a pergunta:que método getSaldo() é invocado dentro o método imprimeSaldo()? O daclasse Conta ou o da classe CEspecial?

public class TestaConta{ public void imprimeSaldo(Conta c) { System.out.println(“O Saldo e’:”+c.getSaldo()); }

public static void main(String a[])

Page 95: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

94 { TestaConta testa = new TestaConta(); CEspecial c= new CEspecial(1, 123456, 500.0, 100.0); testa.imprimeSaldo(c); }}

Exemplo IV-16. Teste de polimorfismo.

A resposta é: o método chamado pertence a instância da classeCespecial. Portanto a regra é a seguinte: sempre é chamado o método dadeclarado na classe a que o objeto pertence e não da classe superclasse. Paraque essa regra seja implementada é necessário que a associação da chamada dométodo com o código do método em casos como no exemplo IV.13 seja feito emtempo de execução. Isso ocorre porque somente em tempo de execução serápossível saber a classe do objeto que está sendo recebido como parâmetro.

O momento em que ocorre a associação de um identificador com a objetoque identifica é chamado tempo de amarração. Se este momento ocorre emtempo de compilação a amarração é dita estática (static binding). Se associaçãoocorre em tempo de execução a amarração é dita dinâmica (dynamic binding).Assim, na linguagem Java, em se tratando da associação da chamada do métodoao código do método a amarração é dinâmica. A única exceção é se o método fordeclarado como final. Neste caso a amarração é estática porque não é possívelsobrescrever o método.

A implementação da amarração dinâmica é claramente mais ineficienteque a estática, uma vez que o compilador precisa gerar código para determinar aclasse do objeto em tempo de execução. No entanto, existem vantagensconsideráveis na adoção da amarração dinâmica. Ela facilita o reuso e aextensão de programas. Por exemplo, se criarmos uma nova subclasse da classeConta que também sobrescrevesse o método imprimeSaldo(), nenhumamodificação precisaria ser feita em métodos como o imprimeSaldo() daclasse TestaConta, uma vez que o método correto sempre é chamado.Portanto, podemos ampliar a hierarquia de um conjunto de classes sem precisaralterar, na maioria das vezes, os métodos que fazem uso dessa hierarquia.

A amarração dinâmica de métodos também acarreta um comportamentopolimórfico. Por exemplo, o objeto que é passado para o métodoimprimeSaldo() pode exibir comportamento diversos, dependendo da classea qual realmente o objeto pertence.

Amarração Dinâmica em C++

Page 96: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

95Apesar da amarração dinâmica entre os identificadores dos métodos e o corpo dos

métodos ser considerada uma característica importante para linguagens orientadas a objetos, nemtodas a linguagens deste estilo de programação adotam este comportamento como padrão. Porexemplo, a linguagem C++ adota a amarração estática como padrão. Se o programador desejarque os métodos possuam amarração dinâmica então o deve instruir o compilador explicitamenteprefixando os métodos com a palavra-chave virtual. A razão para esta decisão dos projetistas dalinguagem está na eficiência. A amarração dinâmica é bem mais ineficiente que a amarraçãoestática e a linguagem C++ se propõe a ser uma linguagem que é capaz de gerar código queexecuta eficientemente.

O exemplo IV.14 procura esclarecer melhor a amarração dinâmica dosmétodos na linguagem Java.

public class Animal{ public void fala(){}}

public class Cachorro extends Animal{ public void fala(){System.out.println(“Au au!”);}}

public class Gato extends Animal{ public void fala(){System.out.println(“Miau!”);}}

public class UsaAnimal{ public void falaAnimal(Animal a){a.fala();}}

Exemplo IV-17. Classes de vozes dos animais.

No exemplo IV.14 o método falaAnimal() da classe UsaAnimalrecebe qualquer subclasse da classe Animal é invoca o método fala() dasubclasse. Para incluir mais um animal na hierarquia basta declarar mais umasubclasse:

public class Pato extends Animal{ public void fala(){System.out.println(“Quá Quá!”);}}

Page 97: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

96

Exemplo IV-18. Classe com a voz do pato.

Nada precisa ser alterado nas outras classes. A nova classe pode serinclusive subclasse de outra subclasse que não haverá problema:

public class GatoRonronando extends Gato{ public void fala(){System.out.println(“Purr!”);}}

Exemplo IV-19. Classe com a voz do pato.

Podemos observar que a classe Animal propriamente dita não faz nadaa não ser servir de “cabide” para as outras classes. É pouco provável que ela sejainstanciada, já que o seu único método não faz nada. Classes como essafuncionam como um esquema para as subclasses e deveriam ser tratadasadequadamente pelo compilador. Este tópico é tratado adequadamente napróxima seção.

Classes e Métodos Abstratos

Classes abstratas são esquemas ou esqueletos de classes cujo únicopropósito e servir de “cabides” para “pendurar” classes. Uma classe abstrata nãopode ser instanciada e possui um ou mais métodos abstratos. Um métodoabstrato é um método sem corpo cuja a assinatura é precedida da palavra-chaveabstract. Na verdade o programador não é obrigado a declarar métodosabstratos em classes abstratos, porém raramente surgira uma situação em quenão isso não faça sentido. As subclasses precisam sobrescrever os métodosabstratos, caso contrário também não poderão ser instanciadas.

A classe Animal do exemplo IV.14 é uma ótima candidata à classeabstrata. Para torná-la uma classe abstrata basta preceder a declaração da classecom a palavra chave abstract e declarar um ou mais de seus métodos comoabstratos, como mostra o exemplo IV.17.

abstract public class Animal{ abstract public void fala();}

Page 98: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

97

Exemplo IV-20. Classe abstrata Animal.

Além de não poder ser instanciada a classe abstrata possui outraslimitações. Uma classe abstrata não pode possuir métodos estáticos econstrutores. Outra limitação é que os métodos abstratos não podem serprivados, uma vez que as subclasses precisam sobrescrever os métodosabstratos.

Interfaces

As Interfaces podem ser encaradas como classes abstratas completamentenão implementadas. Ou seja, todos os métodos são abstratos e os atributos sópodem ser do tipo static final (constantes). A forma geral de uma Interfaceobedece o seguinte esquema:

interface identificador{

corpo da interface}

A classe que implementa uma interface precisa fornecer umaimplementação para todas os métodos definidos na Interface. Para que umadeterminada classe seja vista como uma implementação de uma interface épreciso indicar isto colocando a palavra chave implements na declaração daclasse e após a palavra chave a lista com o nome de todas as interfaces que sedeseja implementar, separados por vírgula. O esquema abaixo mostra a formageral do uso de Interfaces.

class Identificador implements Interface1, Interface2,...{

corpo da classe}

O leitor deve estar se perguntando: se a interface é apenas uma classeabstrata completamente não implementada então porque não criar simplesmenteuma classe abstrata? A resposta está relacionada com o tipo de herança queocorre entre as classes de Java. Como já mencionamos a linguagem Java nãopermite a herança múltipla, ou seja, uma classe só pode ser subclasse de apenasuma classe. No entanto, existem situações em que é necessário definir umaclasse que possa ser vista de modos distintos. É ai que entram as Interfaces. Ainterface define uma forma de ver uma classe, restando para a classe aimplementação desta visão e a linguagem Java permite que uma classe

Page 99: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

98

implemente tantas Interfaces quantas se desejar. Desta forma Java evita osprincipais problemas da herança múltipla (herdando múltiplas definições e nãomúltiplas implementações), sem abrir mão de criar classes que podem ser vistasde formas diferentes.

Por exemplo, suponha que um método receba um objeto que representa ainterface de saída de um determinado programa. O objetivo deste método é usarum método do objeto de interface para escrever uma mensagem na tela. Oexemplo IV.xx mostra o código da classe que contém o método.

public class EscreveMem{ public static void escreve(InterUsuario inter) { inter.exibeMensagem(“ola mundo!”); }}

Exemplo IV-21. Classe que recebe um objeto de interface.

Suponha também que desejamos que o programa tenha tanto umainterface com o usuário em modo gráfico e em modo texto. Usaremos de agoraem diante as iniciais IU para significar interface com o usuário para evitar aconfusão com o conceito de Interfaces que estamos introduzindo. Se desejamosque o método escreve() possa receber instâncias dos dois tipos de IU énecessário que ambas sejam do tipo InterUsuario. No entanto, como veremosmais adiante, as classes que implementam IU gráficas devem ser subclasses declasses predefinidas como por exemplo da classe java.awt.Frame. Portanto,temos agora um problema de herança múltipla. A classe que implementa a IUgráfica de herdar de uma classe como a Frame e da classe InterUsuario. Asolução é simples. Basta definir InterUsuario como uma interface comomostra o exemplo IV.xx.

interface InterUsuario{ abstract public void exibeMensagem(String men);}

Exemplo IV-22. Definição de como InterUsuario interface.

Agora basta que cada classe que representa um tipo de IU implemente ainterface InterUsuario. O exemplo IV.xx mostra a implementação de uma

Page 100: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

99

IU gráfica simples e o exemplo IV.xx mostra a implementação de uma IU emmodo texto simples.

import java.awt.*;import java.awt.event.*;

public class Janela extends Frame implements InterUsuario{ private Label label1;

public Janela() { addWindowListener (new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } } ); setLayout (new BorderLayout());

label1 = new Label(); label1.setText ("Mensagem"); add (label1, "South"); setSize(200,100); }

public void exibeMensagem(String men) { label1.setText(men); }}

Exemplo IV-23. IU gráfica.

public class Console implements InterUsuario{ public void exibeMensagem(String men) { System.out.println(men); }}

Exemplo IV-24. IU em modo texto.

O exemplo IV.xx mostra uma forma de uso das classes definidas nosexemplos de IV.xx a IV.xx.

Page 101: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

100

public class UsaIUs{ public static void main(String args[]) { Console c = new Console(); Janela j = new Janela(); j.setVisible(true); EscreveMem. escreve(c); EscreveMem. escreve(j); }}

Exemplo IV-25. Uso das IUs.

As Interfaces também são úteis sob o aspecto de projeto. Em C++ osprogramadores estão acostumados separar a interface de uma classe de suaimplementação. Geralmente dentro das classes são declaradas apenas asinterfaces dos métodos sendo que a implementação dos mesmos pode ser feitaposteriormente. Isto permite que se possa dividir a etapa da especificação do usode uma classe (o que ela faz) de sua implementação (como ela faz). Isto reduz acomplexidade da tarefa de implementação e permite melhor divisão de tarefas.No entanto, na linguagem Java os métodos de uma classe são geralmenteimplementados dentro da classe. As Interfaces e Classes podem ser utilizadaspara permitir a separação entre a interface e a implementação a exemplo decomo e feito em C++.

Classes Internas

A partir da versão 1.1 da linguagem Java foi incluída a permissão paradeclarar uma classe dentro da declaração de outra classe. As classes declaradasdentro de outra classe são denominadas de Classes Internas. A figura IV.xxmostra um esquema contendo o posicionamento relativo de uma classe interna.

public class Externa{ ... class Interna { ... }

Page 102: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

101}

Figura IV.xx- Posicionamento relativo das classes Interna e Externa.

Os atributos e métodos declarados na classe externa são visíveis pela classeinterna, mesmo os declarados como protected ou private. No entanto, ocontrário não é verdadeiro, ou seja, os atributos e métodos da instância da classeinterna só são visíveis pela classe interna se forem declarados como públicos.

Como já foi dito as classes mais externas (nível topo) só podem serdeclaradas como públicas ou friendly (default). No entanto, as classes internaspodem também receber os qualificadores private e protected. O efeito destesqualificadores sobre a visibilidade da instância da classe é o mesmo obtido sobreum atributo qualquer. O exemplo IV.xx mostra o caso de uma classe contendouma classe interna privada. O exemplo tem por objetivo apenas ilustrar o uso declasses internas.

public class Calc{ Incrementa inc1, inc5; public Calc () { inc1=new Incrementa(1); inc5=new Incrementa(5); }

private class Incrementa { int i; public Incrementa(int ai){i=ai;} public int inc(int num){return i+num;} } public int calcula(int x){return inc1(x)+inc5(x);}}

Exemplo IV-26. Uso de classes internas.

A inclusão de classes internas foi uma modificação a nível de linguagem emJava e o leitor deve estar se perguntando o que motivou a uma modificação tãoprofunda em Java. A reposta está no novo modelo de eventos proposto pelaversão 1.1. No novo modelo, como poderá ser constatado no capítulo que tratasobre a AWT, as classes internas se adequam perfeitamente. Aliado a esta

Page 103: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

102

motivação existe o fato de que esta alteração na linguagem não acarretounenhuma modificação na máquina virtual, tratada pelo compilador. Desta modoesta facilidade não gerou qualquer impacto em termos desempenho dosprogramas. O exemplo IV.xx mostra o exemplo de uso de uma classe internapara capturar eventos. Este tipo de uso será tratada com maiores detalhes nocapítulo que trata sobre AWT.

public class Janela extends Frame { public Janela (String Titulo){

super(Titulo);addWindowListener(new JanelaListener());

setSize(100,50); }

private class JanelaListener implements WindowListener { public void windowOpened(WindowEvent we){} public void windowClosed(WindowEvent we){} public void windowIconified(WindowEvent we){} public void windowDeiconified (WindowEvent we){} public void windowActivated(WindowEvent we){} public void windowDeactivated(WindowEvent we){} public void windowClosing(WindowEvent we){ setVisible(false); dispose(); System.exit(0); } };};

Exemplo IV-27. Uso de classes internas para receber eventos.

Classes Internas Anônimas

Java permite que se crie um objeto de uma classe sem nome. As classes sãodeclaradas no momento do retorno de um método ou durante a passagem deparâmetros e o objeto é criado quando o argumento ou a expressão de retorno éavaliada. O exemplo IV.xx mostra o retorno de um objeto de uma classeanônima.

public class TesteAnonima{ public Object retAnon()

Page 104: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

103 { return new Object() { // Definição da classe anônima private int i=10; public int value(){return i;} }; }};

Exemplo IV-28. Retorno de um objeto de uma classe anônima.

Pode parecer pelo exemplo IV.xx que o objeto retornado é uma instânciada classe Object, no entanto é na verdade uma instância de uma classeanônima que é subclasse da classe Object. A classe anônima possui atributos emétodos próprios que a diferenciam da classe Object e estão definidos nadeclaração da classe. Usamos a classe Object apenas para exemplificar comuma classe conhecida. Qualquer classe pode fazer o papel de superclasse. Oexemplo IV.xx mostra o uso de uma classe anônima na criação de um objetopara lidar com eventos sobre um botão.

class BT{ Button bt; public BT()

{ bt = new Button(“OK); bt.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { dispose(); } });

}}

Exemplo IV-29. Uso de uma classe anônima para tratamento de eventos.

As classes anônimas são adequadas para situações onde necessitamos em umlocal específico de um objeto de uma classe ligeiramente diferente de outraclasse já declarada. Com a classe anônima evitamos ter que declarar uma novaclasse para atender apenas uma necessidade local.

Page 105: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

104

Conversão

Uma variável declarada como referencia para objetos de umadeterminada classe pode receber referencias de objetos de subclasses sem anecessidade de se usar qualquer operador de conversão. A conversão é feitaautomaticamente, uma vez que toda instância de uma subclasse é também umainstância da superclasse. Por exemplo:

Object o;String s = “teste”;o = s;

A atribuição acima é possível porque a classe Object é uma superclassede String (Na verdade é superclasse de todas as classes). Já a conversãoinversa só é possível se o objeto for realmente do tipo da subclasse, e mesmoassim é preciso utilizar um operador de conversão forçada (casting):

Object o;String s = “teste”;String t = “teste”;o = s;t = (String) o;

Exceções

Quanto maior o número de situações de exceção que um determinadoprograma consegue lidar, mais robusto é este programa. Para construir umprograma robusto o programador deve prever, além das situações onde os dadosde entrada e os recursos se apresentam de forma adequada, as situações ondealgo pode impedir a computação normal. Existem três abordagens típicas paraesses casos:

1) Ignorar – neste caso a ação será a padrão do sistema, provavelmentea interrupção do programa, ou no mínimo do comando onde ocorreuo erro, e a exibição de uma mensagem ininteligível na saída padrão,gerada pelo sistema. Esta é abordagem mais simples, mas certamentenão é a mais interessante, principalmente do ponto de vista do usuáriofinal.

Page 106: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

105

2) Retornar o código de erro. No caso da linguagem Java este retornosó pode ser feito via valor de retorno da função. No entanto algumasvezes não existem valores disponíveis para indicar o erro. Porexemplo, quando um método retorna um valor inteiro costuma-seusar os valores 0 ou –1 para sinalizar uma condição de erro, mascomo agir no caso desses e todos os outros valores de inteiros seremvalores válidos em uma execução normal? Existe ainda o problemade que esta abordagem não resolve o problema de erros que ocorremnos construtores. Como os construtores não retornam valores não épossível sinalizar erros dessa forma. Esta é uma abordagem muitocomum entre os programadores de C e Pascal, e é ainda usada pelosprogramadores de C++. No entanto, as linguagens mais modernascomo C++ e Java disponibilizam recursos que permitem um melhortratamento de exceções, como veremos na terceira abordagem.

3) Declarar um ou mais tratadores de exceções. Um tratador deexceção é uma parte do código que tem por objetivo recuperar aexecução do programa após a ocorrência da exceção, permitindo queo sistema se comporte “suavemente”, mesmo sob condições adversas.A sintaxe e semântica dos tratadores de exceção variam muito delinguagem para linguagem, mas tem tendido a uma certauniformização nas linguagens mais modernas. A linguagem Java, porter como objetivo ser uma linguagem segura, obriga que osprogramador capture todas as exceções, menos as derivadas da classeRuntimeException.

Na linguagem Java a amarração do tratador à exceção é definida emtempo de compilação. Nela, o programador envolve os comandos passíveis degerar exceções em blocos try/catch com o formato geral mostrado abaixo:

try{

código que pode gerar exceções} catch(classe de exceção1 objeto) {

tratamento da exceção1} catch(classe de exceção2 objeto) {...} catch(classe de exceçãoN objeto) {

tratamento da exceçãoN}

Page 107: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

106

As exceções são representadas como objetos A porção catch do blocopossui um bloco com comandos para tratamento da exceção. O bloco que tratadas exceções não tem acesso às variáveis declaradas dentro do bloco try{},uma vez que o escopo destas variáveis está delimitado pelo bloco. Por exemplo,o método estático parseInt() da classe Integer lança como exceção umobjeto da classe NumberFormatException se receber como argumento umString que não pode traduzido para uma representação inteira. O código paracapturar este tipo de exceção poderia ser semelhante ao apresentado no exemploXX.XX.

public class Excecao1{ public static void main(String a[]) { try { int i = Integer.parseInt(a[0]); System.out.println("A cadeia passada pode ser ”+ ”tranformada para número :“+i); } catch(NumberFormatException e) { System.out.println("A cadeia passada não pode ser ”+ ”tranformada para número :“+a[0]); } }}

Exemplo IV.XX- Capturando a exceção NumberFormatException.

Se o bloco catch não possuir nenhum comando de return ou algumachamada à função exit(), então o programa é reassumido após o último blococatch.

A hierarquia de Exceções

As exceções são objetos que pertencem a classes que estão organizadasem uma hierarquia e cuja classe que se encontra no topo da hierarquia é a classeThrowable. A classe Throwable possui duas subclasses: Exception eError. Exception e suas subclasses são usadas para indicar condições quepodem ser recuperadas. Error e suas subclasses indicam condições que em geralnão podem ser recuperadas, causando a terminação do programa.

Page 108: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

107

Todos os objetos da classes Exception devem ser capturados ouexplicitamente relançados para um nível acima na pilha de chamadas. Isto só nãoé válido para os objetos da classes RuntimeException. A RuntimeException ésuas subclasses fazem definem as exceções que podem ser lançadas durante aexecução normal da máquina virtual, como divisão por zero ou indexação forados limites do array. A exceção NumberFormatException mostrada no exemploé uma subclasse da RuntimeException. Como essas exceções podem serlançadas por um número muito grande de métodos, seria trabalhoso para oprogramador se ele fosse obrigado a incluir código para capturar todas essasexceções. Portanto, instâncias da classe RuntimeException e suas subclassesnão precisam ser capturadas. A figura IV.XX mostra uma parte da hierarquiaThrowable até o nível 3. O número de classes nesta hierarquia é muito grandecomo o leitor pode verificar no apêndice XX. O programador pode tambémadicionar classes a esta hierarquia como veremos mais adiante.

Figura IV.XX- Hierarquia de exceções.

Capturando mais de uma exceção

Um determinado método pode lançar mais de uma exceção, assim comopode existir mais de um método dentro de um bloco try/catch com potencialde lançar exceções. Portanto, muitas vezes é preciso definir um blocotry/catch com capacidade de tratar mais de uma exceção. Isto é feito por meioda definição de mais de uma cláusula catch. Cada cláusula catch trata umaexceção. Como a busca pela cláusula catch que deve tratar uma determinadaexceção é feita de cima para baixo é preciso tomar o cuidado de posicionar as otratamento das exceções mais genéricas mais abaixo do que o tratamento dasexceções mais específicas. Caso contrário o tratamento das exceções mais

Throwable

Exception

RuntimeException

Error

ThreadDeathError VirtualMachineError LinkageError......

Page 109: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

108

especificas nunca será executado. O exemplo IV.xx mostra um trecho de códigocujo bloco try/catch é capaz de capturar as exceções IOException,NumberFormatException e Exception. Note que por ser uma exceção maisgenérica que as outras duas o tratamento da exceção Exception é posicionadoapós os outros. Como as exceções NumberFormatException e IOExceptionnão se encontram na mesma linha de herança, a posição de uma relativa a outranão tem significado.

import java.io.*;

class Excecao2{ public static void main(String a[]) { try { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Entre um número:"); int i = Integer.parseInt(in.readLine()); }catch(IOException e) {System.out.println(“Erro de leitura!”);} catch(NumberFormatException e) {System.out.println(“Não é um número!”);} catch(Exception e) {System.out.println(“ocorreu algum erro”);} }}

Exemplo IV.XX- Capturando a várias exceções.

Lançando exceções

Até agora temos visto apenas como capturar as exceções lançadas. Estána hora de olharmos o outro lado da moeda, ou seja, como lançar as exceções.As exceções são lançadas utilizando-se o operador throw. A forma geral docomando é a seguinte:

throw <objeto>

Pode-se também criar o objeto no instante do lançamento, invocando oconstrutor. Neste caso a forma geral do comando seria a seguinte:

Page 110: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

109throw new <classe>(<parâmetros>)

Note que pode-se passar parâmetros para o construtor que podem ajudarna recuperação do problema pelo tratador de exceções. O método onde aexceção é lançada deve tratar a exceção ou passá-la para método que o invocou.Para passar a exceção para o método que o invocou a assinatura do métodocorrente deve conter uma cláusula throws após a lista de argumentos, comomostrado abaixo:

<modificador><tipo retorno> <identificador>(<argumentos>) throws <exceção1>,<exceção2>,...,<exceçãon>{

}

Note que é possível indicar na assinatura do método o repasse de váriasexceções. O exemplo IV.xx mostra tanto o lançamento de um objeto da classeException caso os parâmetros para o construtor da classe não sejam corretos.

import java.io.*;

class NumPos{ private int num; public NumPos(int aNum) throws Exception { if (aNum < 1) throw new Exception(“Número não positivo”); num = aNum; }}

public class Excecao3 { public static void main(String a[]) { try { NumPos np = new NumPos(Integer.parseInt(a[0])); }catch(Exception e) {System.out.println(e.getMessage());} }}

Exemplo IV.XX- Lançando exceções.

Na verdade o pode-se usar a cláusula throws na assinatura do métodopara repassar qualquer exceção que se desejar. O exemplo IV.xx , mostra o

Page 111: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

110

método m1 que repassa qualquer objeto da classe Exception que for lançado emseu corpo, mesmo os que não forem explicitamente lançado por meio docomando throw:

public class Excecao4{ public void m1(int i) throws Exception { if (i == 0 ) throw new NumberFormatException(); System.out.println(2/i); }}

Exemplo IV.XX- Repassando todas as exceções.

Comportamento do Sistema diante das Exceções

Agora que já vimos como tratar e como lançar exceções podemos discutircomo é o comportamento global do sistema diante das exceções. Ou seja, comoé a sequência de busca por um tratador após a ocorrência de uma exceção?Quando ocorre uma exceção em um método o sistema verifica se o comandoonde ocorreu a exceção está incluso em bloco try/catch com uma cláusulacatch associada à exceção. Neste caso o controle é transferido para o bloco detratamento da cláusula catch. Caso contrário, o sistema desempilha um nível napilha de chamada de métodos e verifica se a chamada ao método anterior estáinclusa em bloco try/catch com uma cláusula catch associada à exceção. Osistema prossegue desta forma até que um bloco tratador seja encontrado. Casoencontre o bloco tratador e este não possua nenhum comando de saída (returnou System.exit()), então o controle será retomado no nível de chamada ondefoi tratado após o último bloco catch. e não onde ocorreu a exceção. Caso nãoencontre nenhum bloco tratador, ao atingir o nível mais alto da pilha dechamadas o programa é abortado.

A figura IV.xx procura ilustrar o comportamento do sistema diante deuma exceção, tratada em um nível da pilha de chamada diferente de ondeocorreu.

Pilha de chamadas Código fonte

m1

m2

m3

public class Excecao5{ public void m1(int i) { try { m2(i) }catch (Exception e){...}; ... }

public void m2(int i) throws Exception { m3(i); }

Page 112: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

111

Figura IV.XX- Propagação das exceções.

Criando suas próprias exceções

Se o programador concluir que nenhuma exceção pré-existente seencaixa no tipo de erro que pretende sinalizar, então criar uma classe nova pararepresentar essa exceção. A única condição é que a nova classe seja umaextensão da subclasse Throwable ou de uma de suas subclasses. Procureestender a classe Exception ou uma de suas subclasses, exceto o ramo daRuntimeException, uma vez que, como já foi dito, esta ramificação dahierarquia de exceções é utilizada para exceções do sistema. Por exemplo,podemos rescrever o exemplo IV.xx de modo que o método lance uma exceçãodefinida pelo programador.

import java.io.*;

class NumPosException extends Exception{ public NumPosException(String m){super(m);}}

class NumPos{ private int num; public NumPos(int aNum) throws NumPosException { if (aNum < 1)

ocorrênciada exceção

tratamentoda exceção

Page 113: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

112 throw new NumPosException (“Número não positivo”); num = aNum; }}

public class Excecao6 { public static void main(String a[]) { try { NumPos np = new NumPos(Integer.parseInt(a[0])); }catch(NumPosException e) {System.out.println(e.getMessage());} }}

Exemplo IV.XX- Lançando exceções.

A cláusula finally

Existe mais uma cláusula opcional do bloco try/catch. Esta é a cláusulafinally. A cláusula finally abriga uma trecho de código que deve serexecutado independente se ocorreu ou não uma exceção no bloco try/catch.Pode ser usada para realizar operações de finalizações, como por exemplofechamento de arquivos e canais de comunicação. O exemplo IV.xx ilustra o usoda cláusula finally.

import java.io.*;

class Excecao7

public static void main(String a[]) { try { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Entre um número:"); int i = Integer.parseInt(in.readLine()); }catch(IOException e) {System.out.println(“Erro de leitura!”);} catch(NumberFormatException e) {System.out.println(“Não é um número!”);} finally() {System.out.println(“Terminou.”);}

Page 114: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

113 }}

Exemplo IV.XX- Usando a cláusula finally.

No exemplo IV.xx se não ocorrer nenhuma exceção a cláusula finally éexecutada e a execução é reassumida após a cláusula finally. Caso ocorraalguma exceção no bloco try/catch e exista alguma cláusula catch associada àexceção então a cláusula finally é executada após o tratamento da exceção e aexecução é reassumida após a cláusula finally. Caso ocorra alguma exceção nobloco try/catch e não exista alguma cláusula catch associada à exceção entãoa cláusula finally é executa antes da transferência do controle para o métodochamador.

Documentando o código

Uma das maiores dificuldades no desenvolvimento de software éconseguir que os programadores produzam uma documentação relacionada comos programas que estão desenvolvendo. Eles não gostam de interromper odesenvolvimento para escrever paralelamente a documentação e após o términoda implementação não se animam a passar um grande período de tempodocumentando todo o código escrito. Pensando nisso os projetistas de Javadesenvolveram um meio do programador embutir a documentação no própriocódigo, de modo que, não precisasse interromper a implementação.

A documentação é inserida como um comentário e usa uma sintaxeespecial que pode ser interpretada pelo programa javadoc para gerar umdocumento HTML. Todo comentário que deve ser interpretado pelo javadocdeve ser iniciado por “/**” e terminado por “*/”. O programador pode inserira documentação de duas formas:

1. rótulos (tags) iniciados pelo caractere ‘@’ e que denotam comandosde documentação; ou

2. por meio de código HTML embutido.

Page 115: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

114

Rótulos

O javadoc relaciona os comentários com a estrutura codificada após ocomentário. As estruturas relacionadas com os comentários são as classes,variáveis e métodos. A exceção do rótulo @see todos os rótulos estãorelacionados com a documentação de classes ou métodos.

Rótulo @see

O rótulo @see é usado para gerar links para documentação de outrasclasses. Os links não serão verificados pelo javadoc. Os formatos possíveissão os seguintes:

@see <nome da classe>@see <nome da classe>#<nome do método>

Rótulos para documentação de classes

Os seguintes rótulos são usados na documentação de classes:

Rótulo Descrição@version <versão> Usado para incluir informação sobre a versão.@author <autor> Usado para incluir informação sobre o autor.

Tabela IV.xx- Rótulos para documentação de classes.

Rótulos para documentação de métodos

Os seguintes rótulos são usados na documentação de métodos:

Rótulo Descrição@param <nome> <descrição> Usado para incluir informação sobre o

parâmetro do método.@return <descrição> Usado para incluir informação sobre o

valor de retorno do método.@exception <nome da classe> <descrição>

Usado para incluir informação sobre aexceção que pode ser lançada pelométodo.

Page 116: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

115@deprecated Incluído a partir da versão 1.1. Indica

que o método pode não ser mantidonas próximas versões da linguagem.

Tabela IV.xx- Rótulos para documentação de métodos.

Exemplo de Documentação

O exemplo IV.xx ilustra o uso dos rótulos para documentação do código.

/** Pessoa Mantem os dados pessoais de uma pessoa. @author Alcione de Paiva Oliveira @author [email protected] @version 1.0*/public class Pessoa{

private String Nome;private String Tel;private String End;

// Construtor /** @param n String contendo o nome @param t String contendo o telefone @param e String contendo o endereço @return não retorna valor */

public Pessoa(String n, String t, String e){

Nome = n; Tel = t; End = e;}

/**Retorna o nome da pessoa

@return uma String contendo o nome */

public String getNome(){return Nome;}/**Retorna o telefone da pessoa

@return uma String contendo o telefone */

public String getTel(){return Tel;}/**Retorna o endereço da pessoa

Page 117: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

116 @return uma String contendo o endereço */

public String getEnd(){return End;}}

Exemplo IV.XX- Exemplo de documentação.

HTML embutida

O programador pode incluir código HTML dentro dos comentários paradocumentação da mesma forma que faria em um documento da Web, comomostra o exemplo IV.xx.

/*** <b>Pessoa<\b>* Possui os seguintes objetivos* <ol>* <li> Objetivo1* <li> Objetivo2* </ol>*/

public class Pessoa{ ...}

Exemplo IV.XX- Uso de HTML embutida para documentar código.

O javadoc irá ignorar os caracteres ‘*’ no início de cada linha ao gerara documentação. Não use rótulos de títulos como <h1> ou <hr>, uma vez queo javadoc irá inserir rótulos de títulos automaticamente.

Agenda Eletrônica versão Console 1.0

Iniciaremos agora a primeira versão de um programa que implementauma agenda eletrônica de endereços e telefones. Este programa evoluirá aolongo do livro, de acordo com os conhecimentos que serão apresentados. Em suaprimeira versão a agenda eletrônica terá uma interface baseada em linha decomando e não armazenará o seu conteúdo em algum dispositivo de memória

Page 118: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

117

permanente, o que não a torna muito útil em termos práticos. Nas versõesposteriores a agenda eletrônica armazenará o seu conteúdo em arquivos e Bancode Dados, ganhará interface gráfica, poderá ser utilizada em navegadores deWeb, terá uma arquitetura Cliente/Servidor, e outras facilidades. Esperamos comisso mostrar os vários aspectos da linguagem durante a evolução do programa.Outros exemplos serão apresentados de acordo com a necessidade, porém aagenda eletrônica permanecerá como exemplo principal.

O diagrama de classes da figura III.xx mostra os objetos que compõe aversão console da agenda.

Figura III. – Diagrama de classes da versão console da agenda eletrônica.

Os objetos da classe Pessoa armazenam os dados de uma pessoa. Elafornece os métodos para o acesso a esses dados.

O objeto da classe Agenda é composto por vários dados de pessoa. Estefato está representado no diagrama pela associação de agregação. A classeAgenda possui os métodos necessários para inserção e recuperação dos dados. Ométodo inserir(), trata de inserir uma pessoa na lista de pessoas, o métodogetPessoas(), retorna uma lista contendo todos os objetos da classe Pessoa eo método getPessoa() retorna um objeto da classe Pessoa com o nomeespecificado.

AgendaInt

+obterPessoa()+exibirLista()+exibirPessoa()

Agenda

+inserir(pessoa p)+pessoas getPessoas()+Pessoa getPessoa(String Nome)

Pessoa

-String Nome-String Tel-String End

+getNome()+getTel()+getEnd()

0..*

Page 119: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

118

A Classe AgendaInt é responsável por fornecer os métodos queimplementam a interface com o usuário. Ela foi criada por questões de projeto,uma vez que é importante manter separado o código das interfaces do sistema.

Primeiramente apresentaremos o código da classe Pessoa.

/**Pessoa

*/

public class Pessoa{

private String Nome;private String Tel;private String End;

// Construtorpublic Pessoa(String n, String t, String e){

Nome = n; Tel = t; End = e;}

// Metodos

public String getNome(){return Nome;}public String getTel(){return Tel;}public String getEnd(){return End;}

}

Por questões de simplicidade a classe pessoa possui apenas umconstrutor. As variáveis de instância são declaradas private para preveniracessos que não sejam por meio dos métodos da classe. Segue abaixo o códigoda classe Agenda:

/**AGENDA Versão Console 1.0.

*/

public class Agenda{

Pessoa pessoas[];

// Construtorpublic Agenda() {pessoas = null;}

Page 120: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

119// Metodos/**

inserir*/public void inserir(Pessoa p){

if (pessoas == null) pessoas = new Pessoa[1];else AumentaCapacidade();

pessoas[pessoas.length-1] = p;}

/**Consultar

*/public Pessoa getPessoa(String nome){

Pessoa aux = null;for (int i=0; i< pessoas.length; i++)

if (pessoas[i].getNome().equals(nome))aux = pessoas[i];

return aux;}

/**listar

*/public Pessoa[] getPessoas(){return pessoas;}

/**AumentaCapacidade

*/private void AumentaCapacidade (){

Pessoa aux[] = new Pessoa[pessoas.length+1];for (int i=0;i< pessoas.length;i++)

aux[i] = pessoas[i];pessoas = aux;

}}

De modo a manter o programa com poucas linhas não inserimos códigopara tratar erros para testar os valores que são passados para os métodos ouretornados por eles. O leitor deve ter isto em mente se por acaso pretende utilizartrechos deste programa para aplicações profissionais.

Page 121: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

120

Existem várias formas de representar a associação entre duas classes.Escolhemos representar a agregação por meio de um array de objetos da classePessoa. Um outra forma, mais fácil de se trabalhar, será apresentada na seção xx.A variável que referencia o array é inicializada com null. Toda vez que éinserido um novo objeto o array precisa ser redimensionado. Isto é feito pelométodo privado AumentaCapacidade(). Na verdade o método cria umnovo array maior em uma unidade que o anterior. Esta não é uma solução muitoeficiente. O melhor seria incrementar o array em várias unidades, de modo que oredimensionamento seria necessário em intervalos menores. Contudo, o códigonecessário para gerenciar a inserção seria bem mais complexo.

O método getPessoa() retorna um objeto com o dado nome igual aopassado ao método. Se não existir tal objeto é retornado null. Já o métodogetPessoas() retorna uma referencia para array de objetos do tipo Pessoa.

/**AgendaIntInterface console da agenda.

*/

import java.io.*;

public class AgendaInt{

Agenda ag;BufferedReader in;

// Construtorpublic AgendaInt(){

ag = new Agenda();in = new BufferedReader(new

InputStreamReader(System.in));}

// Metodos/**

Exibirlista*/public void Exibirlista(){ Pessoa p[]=ag.getPessoas(); for (int i= 0; i<p.length; i++)

System.out.println("\nNome:"+p[i].getNome()+"\nTelefone:"

+p[i].getTel()+"\nEndereço:"+p[i].getEnd()+"\n");

Page 122: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

121}

/**exibirPessoa

*/public void exibirPessoa(){

String nome=null;

try {System.out.println("Entre com o nome:");nome = in.readLine();if (nome.length()<1) System.exit(-1);

} catch(IOException e) {System.out.println(e.getMessage());System.exit(-1);}

Pessoa p = ag.getPessoa(nome); if (p!=null) {

System.out.println("\nNome:"+p.getNome()+"\nTelefone:"+p.getTel()+"\nEndereço:"+p.getEnd());

}}

/**obterPessoa

*/public void obterPessoa(){

String nome; String tel; String end;

try { System.out.println("Entre com o nome:"); nome = in.readLine(); if (nome.length()<1) System.exit(-1); System.out.println("\nEntre com o Telefone:"); tel = in.readLine(); System.out.println("\nEntre com o Endereço:"); end = in.readLine(); ag.inserir(new Pessoa(nome ,tel,end)); } catch(IOException e) {System.out.println(e.getMessage());System.exit(-1);}}

// mainpublic static void main(String args[]){

Page 123: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

122 AgendaInt agInt = new AgendaInt(); String opcao="";

for(;;) {

System.out.println("\nAgenda Tabajara\n***********************\n");System.out.print("Opcoes:\n(i)nserir\n(c)onsultar\n(l)istar\n(f)im=>"

);try { opcao = agInt.in.readLine(); if (opcao.length()==0) continue;} catch(IOException e){System.out.println(e.getMessage());System.exit(-

1);}

switch(opcao.charAt(0)){

case 'f': System.exit(0); break;case 'i': agInt.obterPessoa(); break;case 'c': agInt.exibirPessoa(); break;case 'l': agInt.Exibirlista(); break;

} }}

}

O método main da classe AgendaInt cria um objeto da própria classe,que por sua vez possui um objeto da classe Agenda. A partir de então oprograma entra em um laço, que aguarda e atende às solicitações do usuário.Todos os métodos da classe recebem e exibem dados por meio dos dispositivosde E/S padrão. Para ler os dados do dispositivo de entrada padrão, uma linha porvez, foi necessário encapsular o objeto System.in em objetos das classesBufferedReader e InputStreamReader . Não detalharemos aqui ouso destas classes, que será abordado no próximo capítulo. No momento bastaobservarmos que a entrada de dados será realizada por meio do métodoreadLine(), que retorna a linha digitada pelo usuário.

Page 124: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

123

Capítulo V – Entrada e Saída(java.io)

Acesso Sequencial

As funções de entrada e saída são suportadas por classes agrupadas nopacote java.io. Todas se baseiam no conceito de stream de bytes (corrente ousequência), onde a entrada/saída é um duto onde se retira/coloca cada bytecomo em uma fila do tipo First in-first out. A figura V.1 ilustra este tipo deenfoque.

Figura V.1 Stream de bytes.

O produtor e o consumidor podem se selecionados de uma amplavariedade que vai desde arquivos e portas de protocolos TCP/IP até arranjos(arrays) de bytes e Strings. De modo a pode lidar com essa ampla variedade defontes/consumidores de dados e prover todo o tipo de facilidade de leitura opacote java.io possui um conjunto razoavelmente grande classes. Essasclasses são combinadas, formando camadas, onde as classes das camadasinferiores fornecem serviços básicos como leitura/escrita de um byte, enquantoque as classes superiores fornecem serviços de leitura/escrita mais sofisticados,como leitura de linha, leitura de um tipo float, etc. A figura V.2 mostra este tipode combinação.

CCaammaaddaa nn

CCaammaaddaa 1

CCllaassssee II//OOBBáássiiccaa

NNíívveellddoosssseerrvviiççooss

Page 125: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

124

Figura V.2 Organização das classes de I/O.

Para complicar um pouco mais a situação, a linguagem Java Possui doisconjuntos distintos de classes para I/O. Um originado da versão 1.0 e outrointroduzido na versão 1.1. A razão para isso é que as classes projetadas naversão 1.0 são orientadas para bytes e portanto não são adequadas para lidarcódigos Unicodes que utilizam dois bytes. A versão 1.2 não introduziu grandesmodificações, realizando apenas um aperfeiçoamento na java.io.File ealgumas mudanças na assinatura de alguns métodos . O leitor deve então estarpensando que basta então utilizar o novo conjunto de classes e esquecer doantigo, porém a coisa não é tão simples assim. Primeiramente, é importanteconhecer o conjunto antigo de classes uma vez que existe um grande número deprogramas escrito na versão 1.0 e o leitor pode se ver obrigado a ler ou darmanutenção no código destes programas. Em segundo lugar, algumas vezes serápreciso combinar as funções antigas com as novas para obter algum tipo defuncionalidade. E em terceiro lugar a Sun adicionou novas facilidades aoconjunto antigo na versão 1.1, dando sinais que não pretende simplesmenteabandoná-lo. Tudo isto faz com que o tratamento de entrada e saída em Java nãoseja algo muito simples de se dominar. As figuras V.3 e V.4 apresentamdiagramas que mostram algumas das camadas dos dois conjuntos de classes, demodo que o leitor possa ter uma idéia da sua equivalência, embora nem sempreuma classe de um conjunto possua uma classe correspondente em outroconjunto.

Figura V.3 Comparação entre as classes de entrada.

SSttrriinnggBBuuffffeerrIInnppuuttSSttrreeaammBByytteeAArrrraayyIInnppuuttSSttrreeaammPPiippeeddIInnppuuttSSttrreeaammFFiilleeIInnppuuttSSttrreeaammIInnppuuttSSttrreeaamm

iinnttssffllooaattss

SSttrriinnggeettcc..

bbyytteess

FFiilltteerrIInnppuuttSSttrreeaammDDaattaaIInnppuuttSSttrreeaammBBuuffffeerreeddIInnppuuttSSttrreeaammLLiinneeNNuummbbeerrIInnppuuttSSttrreeaamm

iinnttssffllooaattss

SSttrriinnggeettcc..

ccaarraacctteerreePPiippeeddRReeaaddeerrCChhaarrAArrrraayyRReeaaddeerrSSttrriinnggRReeaaddeerrFFiilleeRReeaaddeerrRReeaaddeerr

FFiilltteerrRReeaaddeerrBBuuffffeerreeddRReeaaddeerrLLiinneeNNuummbbeerrRReeaaddeerr

Page 126: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

125

Figura V.4 Comparação entre as classes de saída.

Note que não existe uma equivalência perfeita entre os dois conjuntos,nem entre o par entrada/saída em um mesmo conjunto. Por exemplo, a classeStringBufferedInputStream não possui uma classe equivalenteStringBufferedOutputStream nem a DataInputStream possui umaequivalente DataWriter. Esta é uma das razões para o uso combinado dos doisconjuntos. Para realizar a conversão entre os dois conjuntos são fornecidas asclasses InputStreamReader e OutputStreamWriter.

As funções básicas são tratadas pelas classes abstratas básicasInputStream e OutputStream. Para as funções de entrada e saída com Bufferssão utilizadas as classes BufferedInputStream, BufferedOutputStream,BufferedReader e BufferedWriter. O tamanho padrão do buffer é de 2048bytes. A tradução entre InputStream, OutputStream e BufferedReader,BufferedWriter é feita por InputStreamReader e OutputStreamWriter. ParaIO em arquivos podem ser utilizadas classes de baixo nível: FileInputStream,FileOutputStream, FileReader e FileWriter.

De modo a possibilitar a comparação e o entendimento do uso dos doisconjuntos os exemplos abaixo mostram a mesma função implementada comcada grupo de classes.

a) Streams b) I/O 1.1import java.io.*;

class TesteIO101

import java.io.*;

class TesteIO111

BByytteeAArrrraayyOOuuttppuuttSSttrreeaammPPiippeeddOOuuttppuuttSSttrreeaammFFiilleeOOuuttppuuttSSttrreeaammOOuuttppuuttSSttrreeaamm

iinnttssffllooaattss

SSttrriinnggsseettcc..

bbyytteess

FFiilltteerrOOuuttppuuttSSttrreeaammPPrriinnttSSttrreeaammDDaattaaIInnppuuttSSttrreeaammBBuuffffeerreeddOOuuttppuuttSSttrreeaamm

iinnttssffllooaattss

SSttrriinnggsseettcc..

ccaarraacctteerreePPiippeeddWWrriitteerrCChhaarrAArrrraayyWWrriitteerrSSttrriinnggWWrriitteerrFFiilleeWWrriitteerrWWrriitteerr

FFiilltteerrWWrriitteerrBBuuffffeerreeddWWrriitteerrPPrriinnttWWrriitteerr

Page 127: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

126{ public static void main(String a[]) { try { DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream(a[0]))); String str; while((str = in.readLine())!= null) System.out.println(str); } catch(IOException e) { System.out.println(e.getMessage());} }}

{ public static void main(String a[]) { try { BufferedReader in = new BufferedReader( new FileReader(a[0])); String str; while((str = in.readLine())!= null) System.out.println(str); } catch(IOException e) {System.out.println(e.getMessage());} }}

Exemplo V.1 – Leitura não formatada de arquivos.

O exemplo V.1 mostra a leitura de um arquivo passado pela linha decomando feita (a) por meio de stream e (b) por meio de reader. Em ambos oscasos a leitura é utiliza buffers, de modo a otimizar os acessos a disco. No caso(b) basta utilizar um objeto da classe BufferedReader, uma vez que a leituraé não formatada, com o uso do método readLine(). Já no caso (a), é preciso“envolver” o objeto da classe BufferedInputStream em um objeto daclasse DataInputStream, apesar de não ser uma leitura formatada, uma vezque o método readLine() pertence à classe DataInputStream. Mesmoassim o programa receberá a mensagem

The method java.lang.String readLine() in classjava.io.DataInputStream has been deprecated.

significando que o método readLine() está sendo descontinuado para a classeDataInputStream, tendendo a desaparecer nas próximas versões.

a) Streams b) I/O 1.1import java.io.*;

class TesteIO102{ public static void main(String a[]) { try { PrintStream out = new PrintStream( new BufferedOutputStream( new FileOutputStream("saida.out"))); out.println("Linha de teste 1");

import java.io.*;

class TesteIO112{ public static void main(String a[]) { try { PrintWriter out = new PrintWriter( new BufferedWriter( new FileWriter("saida.out"))); out.println("Linha de teste 1");

Page 128: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

127 out.println("Linha de teste 2"); out.close(); }catch(IOException e) { System.out.println(e.getMessage());} }}

out.println("Linha de teste 2"); out.close(); }catch(IOException e) { System.out.println(e.getMessage());} }}

Exemplo V.2 – Escrita não formatada em arquivos.

a) Streamsimport java.io.*;

class TesteIO103{ public static void main(String a[]) { try { DataOutputStream out = new DataOutputStream( new BufferedOutputStream( new FileOutputStream("a.out"))); out.writeBytes("O valor de pi: \n"); out.writeDouble(3.14159); out.close();

DataInputStream in = new DataInputStream( new FileInputStream("a.out")); System.out.println(in.readLine()); System.out.println(in.readDouble());

}catch(IOException e) {System.out.println(e.getMessage());} }}

Exemplo V.3 – Escrita e leitura formatada em arquivos..

A leitura/escrita formatada utiliza as classes DataInputStream eDataOutputStream. Como não existem as correspondentes DataReadere DataWriter, somos obrigados a usar o conjunto antigo de classes pararealizar a leitura e escrita formatada.

Os dispositivos de entrada e saída padrões (equivalentes na linguagemC++ a cin, cout e cerr), são mantidos pela por variáveis estáticas da classeSystem, referenciadas por System.in, System.out e System.error.Como essas variáveis referenciam a objetos das classes InputStream eOutputStream, se desejarmos manipular os dispositivos de E/S padrões como conjunto de classes novos devemos utilizar as classes tradutoras

Page 129: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

128

InputStreamReader e OutputStreamWriter, como mostrado noexemplo V.4.

import java.io.*;

class TesteIO114{ public static void main(String a[]) { try { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Entre uma linha:"); System.out.println(in.readLine()); }catch(IOException e) {System.out.println(e.getMessage());} }}

Exemplo V.4 – Leitura e Escrita nos dispositivos de saída e entrada padrões.

Acesso Direto

Até agora lidamos com dispositivos de entrada e saída que tratamsequência de bytes ou caracteres (streams). No entanto, alguns dispositivoscomo disco rígido e CDs permitem o acesso direto à um byte sem a necessidadede ler todos os outros bytes posicionados antes. Este tipo de acesso é chamadode acesso direto e Java permite este tipo acesso a arquivos armazenados emdispositivos que suportam o acesso direto por meio da classeRandomAccessFile. Esta classes não pertence a nenhuma das hierarquiasapresentadas anteriormente uma vez que não acessa os dados na forma desequência. A única semelhança com as outras hierarquias é o fato deimplementar as interfaces InputStream e OutputStream. De fato, a classeRandomAccessFile torna muito conveniente o acesso a arquivos porimplementar simultaneamente as duas interfaces, permitindo desta forma tanto aleitura quanto a escrita no arquivo. Os construtores da classe são os seguintes:

public RandomAccessFile(File file, String mode) throws IOExceptionpublic RandomAccessFile(String name, String mode) throws IOException

Page 130: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

129

O primeiro construtor recebe um objeto da classe File e um objeto daclasse String especificando o modo de acesso do arquivo. O acesso direto seráfeito sobre o objeto da classe Files. Os modos acesso possíveis são: modo deleitura, especificado pela String “r” e modo de leitura e escrita, especificadopela String “rw”. O segundo construtor recebe um objeto da classe Stringcontendo o nome do arquivo e outro objeto da classe String especificando omodo de acesso do arquivo. Ambos os construtores lançam a exceçãoIOException.

A maioria dos métodos implementados por RandomAccessFile sãoimplementados pela classe FileInputStream ou pela classeFileOutputStream, uma vez que ela lida tanto com leitura como saída,porém, a classe RandomAccessFile possui alguns métodos adicionais quepermitem definir a posição corrente no arquivo e estabelecer onde serálido/escrito o próximo dado. A tabela V.1 mostra os métodos da classeRandomAccessFile.

Método Descriçãoclose() Fecha o arquivo.getFD() Retorna o descritor arquivo objeto associado com

este stream.getFilePointer() Retorna a posição corrente neste arquivo.length() Retorna o tamanho deste arquivo.read(byte[] b, intoff, int len)

Lê até len bytes em um array de bytes.

read() Lê um byte.read(byte[] b) Lê até to b.length bytes em um array de bytes.readBoolean() Lê um boolean.readByte() Lê um um byte.readChar() Lê um caracter Unicode.readDouble() Lê um double.readFloat() Lê um float.readFully(byte[] b,int off, int len)

Lê exatamente len bytes no array byte.

readFully(byte[] b) Lê b.length bytes no array byte.readInt() Lê um inteiro de 32-bit com sinal.readLine() Lê a próxima linha de texto.readLong() Lê um inteiro com sinal de 64-bits.

Page 131: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

130readShort() Lê um inteiro com sinal de 16-bits.readUnsignedByte() Lê um inteiro sem sinal de 8-bits.readUnsignedShort() Lê um inteiro sem sinal de 16-bits.readUTF() Lê um String usando a codificação UTF-8.seek(long pos) Define pos como a posição em bytes no arquivo

onde será feita a próxima leitura/escrita.skipBytes(int n) Salta exatamente n bytes.write(int b) Escreve um byte.write(byte[] b, intoff, int len)

Escreve len bytes do array iniciando em off.

write(byte[] b) Escreve b.length bytes do array.writeBoolean(booleanv)

Escreve um boolean como um valor 1-byte.

writeByte(int v) Escreve um byte como um valor 1-byte.writeBytes(String s) Escreve uma String como uma sequência de

bytes.writeChar(int v) Escreve um caractere como um valor 2-byte, byte

alto primeiro.writeChars(String s) Escreve uma String como uma sequência de

caracteres.writeDouble(doublev)

Escreve um double como um valor de 8-bytes.

writeFloat(float v) Escreve um float como um valor de 4-bytes.writeInt(int v) Escreve um inteiro como quatro bytes.writeLong(long v) Escreve um long como oito bytes.writeShort(int v) Escreve um short como dois bytes.writeUTF(String str) Escreve uma String usando a codificação UTF-8.

Tabela V.1 – Métodos públicos da classe RandomAccessFile.

O Exemplo V.5 mostra o uso da classe RandomAccessFile paraacessar o byte no meio do arquivo.

import java.io.*;class RandomTeste{ public static void main (String args[]) { if (args.length ==0) { System.err.println("Forneça o nome do arquivo!"); System.exit(0);

Page 132: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

131 } try { RandomAccessFile f = new RandomAccessFile(args[0], "r"); long tam = f.length(); if (tam==0) { System.out.println("Arquivo vazio!"); } else { f.seek(tam>>1); System.out.println("O byte no meio é: "+f.read()); } } catch (Exception e) { System.out.println("Erro: " + e.toString()); }}

Exemplo V.1 – Uso da classe RandomAccessFile.

Page 133: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

132

Capítulo VI – java.util

O pacote java.util reúne um conjunto interessante de classes einterfaces úteis ao desenvolvimento de aplicações. Contém recursos para lidarcom coleções, data e hora, internacionalização, arrays de bits, tokenização decadeias de caracteres e etc. Nesta seção abordaremos as classes e interfaces maisutilizadas.

Lidando com Coleções

Antigamente, era muito comum que, durante o desenvolvimento de umsistema, os programadores tivessem a necessidade de implementar uma estruturade dados como uma lista, pilha ou tabela hash para agrupar e gerenciar umconjunto de elementos. Como as primeiras linguagens de programação nãopossuíam recursos para que se implementasse estas estruturas de forma genérica,de modo que pudessem ser usadas independentemente do tipo dos elementos, oprogramador era obrigado a implementar deste o início toda a estrutura paracada novo tipo de elemento.

Com as linguagens de programação mais recentes este quadro mudou. Asnovas linguagens permitem que o programador implemente estruturas de dadosgenéricas, independentes de tipos. Além disso, a maioria delas já implementam,embutidas na linguagem ou na forma de bibliotecas, as estruturas de dados maiscomuns. Este é o caso da linguagem Java que possui, dentro do pacotejava.util classes e interfaces que implementam estruturas de dados comolistas (List), arrays crescentes (Vector), pilhas (Stack), tabela hash(Hashtable) e etc. O pacote possui também interfaces para percorrer oselementos das estruturas (Iterator e Enumeration). Apresentaremos aquiapenas as classes e interfaces mais usadas.

As Interfaces Iterator e Enumeration

As interfaces Iterator e Enumeration são usadas na criação deobjetos que tem por objetivo percorrer sequencialmente os elementos de umacoleção. Como ambas as interfaces possuem o mesmo objetivo o leitor deve

Page 134: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

133

estar se perguntando sobre necessidade de existirem duas interfaces. O fato é queaté a versão 1.1 da linguagem Java existia apenas a interface Enumeration.No entanto, como o nome deste tipo de objeto na comunidade de Engenharia deSoftware é iterator a Sun aproveitou para incluir uma interface com este nomena versão 1.2 e fazer algumas pequenas modificações.

O métodos que devem ser implementados em cada interface sãosemelhantes e estão descritos nas tabelas VI.1 e VI.2.

Método Descriçãoboolean hasMoreElements() Testa se Enumeration possui mais elementos.Object nextElement() Retorna o próximo elemento da Enumeration.

Tabela VI.1 – Métodos da interface Enumeration.

Método Descriçãoboolean hasNext() Testa se Iterator possui um próximo elemento.Object next() Retorna o próximo elemento do Iterator.void remove() Remove da coleção associada o último elemento

retornado pelo Iterator.

Tabela VI.2 – Métodos da interface Iterator.

Um objeto que implementa a interface Enumeration é retornado poralguma classe que implementa uma estrutura de dados sempre que invocamos ométodo elements() da classe. Por exemplo, suponha que desejamos imprimiros elementos reunidos por um objeto v da classe Vector. O trecho de códigopara cumprir essa tarefa poderia ter a seguinte forma:

for (Enumeration e = v.elements() ; e.hasMoreElements() ;){ System.out.println(e.nextElement());}

Já no caso da interface é preciso usar o método iterator() herdadopor toda subclasse da interface Collection. Neste caso o trecho de códigopara cumprir essa tarefa poderia ter a seguinte forma:

for (Iterator it = v.iterator() ; it.hasNext() ;){ System.out.println(it.next());

Page 135: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

134}

Vector

public class Vectorextends AbstractListimplements List, Cloneable, Serializable

A classe Vector implementa um array dinâmico. Ou seja, um array quecresce ou diminui a medida da necessidade. O uso de objetos classe Vector éindicado para situações onde o programador precisa manter uma lista deelementos mas não sabe, a priori, o número de elementos que pertencerão à listaou o número de elementos da lista irá variar durante o processamento.

Hierarquia

java.lang.Object | +--java.util.AbstractCollection | +--java.util.AbstractList | +--java.util.Vector

Construtores

Construtor Descriçãopublic Vector() Constrói um Vector vazio com espaço inicial

para 10 elementos e incremento 0.public Vector(Collection c) Constrói um Vector contendo os elementos do

objeto do tipo Collection.public Vector(int iniCapac) Constrói um Vector vazio com espaço inicial

para iniCapac elementos e incremento 0.public Vector(int iniCapac, int inc)

Constrói um Vector vazio com espaço inicialpara iniCapac elementos e incremento inc.

Tabela VI.3 – Construtores da classe Vector.

Page 136: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

135

Atributos

Atributo Descriçãoprotected int capacityIncrement Quantidade que é incrementada à

capacidade do Vector toda vez que otamanho se torna maior que a capacidade.

protected int elementCount Número de elementos referenciadosprotected Object[] elementData Array onde são armazenadas as referencias

aos elementos.

Tabela VI.4 – Atributos públicos da classe Vector.

Métodos

Devido ao grande número de métodos da classe Vector mostraremosapenas os mais usados.

Método Descriçãovoid add(int i, Object o) Adiciona um elemento na posição indicada por i.public boolean add(Objecto)

Adiciona um elemento no final do Vector.

public boolean addAll (Collection c)

Adiciona todos os elementos da coleção especificadano final do Vector.

public void addElement(Object o)

Adiciona um elemento no final do Vector.

public int capacity() Retorna a capacidade atual.public void clear() Remove todos os elementos do Vector.public Object clone() Retorna um clone do Vector.public boolean contains(Object o)

Testa se o objeto é um elemento do Vector.

public booleancontainsAll(Collection c)

Retorna true se o Vector contém todos oselementos referenciados por c.

public void copyInto (Object[] a)

Copia os elementos do Vector no array.

public Object elementAt(int i)

Retorna o elemento na posição i.

public Enumerationelements()

Retorna um objeto do tipo Enumeration quepermite percorrer os elementos do Vector.

public voidensureCapacity(int min)

Aumenta a capacidade do Vector para o valor min.

public booleanequals(Object o)

Compara se o é igual ao Vector. Retorna truesomente se o objeto é também do tipo List, possui omesmo tamanho e referencia os mesmos elementos namesma ordem.

Page 137: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

136public ObjectfirstElement()

Retorna o primeiro elemento.

public Object get(int i) Retorna o elemento da posição i.public int indexOf(Object o)

Retorna a posição da primeira ocorrência de o. Ométodo equals() do objeto é usado para o teste deigualdade.

public int indexOf(Objecto,int i)

Retorna a posição da primeira ocorrência de o a partirde i. O método equals() do objeto é usado para oteste de igualdade.

public voidinsertElementAt(Object o,int i)

Insere o objeto o na posição i.

public boolean isEmpty() Testa se o Vector está vazio.public ObjectlastElement()

Retorna o último elemento.

public intlastIndexOf(Object o)

Retorna a posição da última ocorrência de o. Ométodo equals() do objeto é usado para o teste deigualdade.

public Object remove(inti)

Remove o elemento da posição i.

public booleanremoveAll(Collection c)

Remove todos os elementos que também pertencem àCollection.

public voidremoveAllElements()

Remove todos os elementos.

public voidremoveElementAt(int i)

Remove o elemento da posição i.

public booleanretainAll(Collection c)

Mantém apenas os elementos que também pertencemà Collection.

public Object set(int i,Object o)

Substitui o objeto na posição i pelo objeto o.

public void setSize(ints)

Define o tamanho do Vector.

public int size() Retorna o tamanho do Vector.public List subList(inti, int f)

Retorna uma parte dos elementos do Vector entrefromIndex, inclusive, e toIndex, exclusive.

public Object[] toArray() Retorna um array contendo todos os elementos noVector na ordem correta.

public String toString() Retorna uma representação na forma de String doVector.

Tabela VI.5 – Métodos da classe Vector.

Exemplo

Page 138: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

137

O exemplo a seguir mostra a inserção das strings passadas pela linha decomando em um objeto da classe Vector. Os elementos do objeto Vectorpodem ser exibidos na tela invocando o método print().

import java.util.*;

public class TesteVector{ Vector v;

public TesteVector(String a[]) { v = new Vector(a.length); v.copyInto(a); }

public void print() { for (Iterator it = v.iterator(); it.hasNext() ;) { System.out.println((String)it.next()); } }

public static void main(String args[]) { TesteVector teste = new TesteVector(args); teste.print(); }}

Exemplo VI.xx – Uso do Vector.

Stack

public class Stackextends Vector

A classe Stack implementa a estrutura de dados pilha. Ou seja, umaestrutura de dados que segue a regra LIFO (last-in-first-out – último a entrar,primeiro a sair). Esta regra impõe define uma lista que é acessada apenas poruma extremidade, de modo que o último elemento a ser inserido na pilha tenhaque ser o primeiro elemento a sair.

Page 139: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

138

Hierarquia

java.lang.Object | +--java.util.AbstractCollection | +--java.util.AbstractList | +--java.util.Vector | +--java.util.Stack

Construtor

Construtor Descriçãopublic Stack() Constrói um Stack vazio.

Tabela VI.6 – Construtor da classe Stack.

Métodos

Método Descriçãopublic boolean empty() Testa se a Stack está vazia.public Object peek() Retorna uma referência para o elemento no topo da

Stack sem retirá-lo.public Object pop() Retorna uma referência para o elemento no topo da

Stack e o retira.public Object push(Object o)

Insere o objeto o no topo da Stack.

public int search(Object o)

Retorna a distância do topo da pilha da primeiraocorrência de o. O elemento no topo da pilha possui adistância 1. O método equals() do objeto é usadopara o teste de igualdade.

Tabela VI.5 – Métodos da classe Stack.

Exemplo

Page 140: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

139

O exemplo a seguir mostra a inserção das strings passadas pela linha decomando em um objeto da classe Stack. Os elementos do objeto Stackpodem ser exibidos na tela invocando o método print().

import java.util.*;

public class TesteStack{ Stack s;

public TesteStack(String a[]) { s = new Stack(); for (int i=0; i<a.length; i++) s.push(a); }

public void desempilha () { String aux = (String)s.pop(); while (aux !=null) { System.out.println(aux); } }

public static void main(String args[]) { TesteStack teste = new TesteStack(args); teste.desempilha(); }}

Exemplo VI.xx – Uso do Stack.

Hashtable

public class Hashtableextends Dictionaryimplements Map, Cloneable, Serializable

A classe Hashtable implementa uma estrutura de dados conhecidacomo tabela hash. Neste tipo de estrutura todo elemento armazenado possui uma

Page 141: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

140

chave que permite recuperar diretamente o elemento, sem a necessidade de irexaminando cada elemento armazenado até encontrar o elemento desejado,como seria o caso em uma lista. Cada chave identifica apenas um elemento.Existem vários bons livros sobre estruturas de dados nas livrarias que o leitorpode consultar para se aprofundar no tema.

Hierarquia

java.lang.Object | +--java.util.Dictionary | +--java.util.Hashtable

Construtores

Construtor Descriçãopublic Hashtable() Constrói um Hashtable vazio com fator de

carga 0,75.public Hashtable(int capac) Constrói um Hashtable com capacidade

inicial capac e com fator de carga 0,75.public Hashtable(int capac, float fatCarga)

Constrói um Hashtable com capacidadeinicial capac e com fator de carga fatCarga.

public Hashtable(Map m) Constrói um Hashtable com os elementos dem.

Tabela VI.xx – Construtores da classe Hashtable.

Métodos

Devido ao grande número de métodos da classe Hashtable mostraremosapenas os mais usados.

Método Descriçãopublic void clear() Remove todos os elementos do Hashtable.public Object clone() Retorna um clone raso do Hashtable.public boolean contains(Object o)

Testa se o objeto é acessado por alguma chave doHashtable.

public boolean containsKey(Object o)

Testa se o objeto é chave no Hashtable.

Page 142: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

141public booleancontainsValue(Object o)

Testa se o objeto é acessado por alguma chave doHashtable.

public Enumerationelements()

Retorna um objeto do tipo Enumeration quepermite percorrer os elementos do Hashtable.

public Set entrySet() Retorna um Set contendo os elementos doHashtable.

public booleanequals(Object o)

Compara se o é igual ao Hashtable. Retorna truesomente se o objeto é também do tipo Map e faz omesmo mapeamento.

public Object get(Objectkey)

Retorna o elemento da posição mapeado pela chavekey.

public boolean isEmpty() Testa se o Hashtable está vazio.public Enumeration keys() Retorna um objeto do tipo Enumeration que

permite percorrer as chaves do Hashtable.public Set keySet() Retorna um Set contendo as chaves do Hashtable.public Object put(Objectkey,Object o)

Insere o objeto o no Hashtable tendo como chavekey.

protected void rehash() Reorganiza internamente o Hashtable para acessare acomodar os elementos mais eficientemente.

public Objectremove(Object key)

Remove o elemento que tem como chave key.

public int size() Retorna o número de chaves do Hashtable.public String toString() Retorna uma representação na forma de String do

Hashtable.public Collectionvalues()

Retorna um Collection contendo os elementos doHashtable.

Tabela VI.xx – Métodos da classe Hashtable.

Exemplos

O exemplo a seguir mostra a inserção das objetos da classe Integer emum objeto Hashtable. A chave usada para cada objeto é o número porextenso.

Hashtable numbers = new Hashtable(); numbers.put("one", new Integer(1)); numbers.put("two", new Integer(2)); numbers.put("three", new Integer(3)); ... Integer n = (Integer)numbers.get("two"); if (n != null) { System.out.println("two = " + n);

Page 143: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

142 } ... for (Enumeration e = numbers.elements();e.hasMoreElements();){ Integer i = (Integer)e.nextElement() System.out.println( i.toString()); }

Exemplo VI.xx – Uso do Hashtable.

O exemplo a seguir mostra a inserção das objetos da classe Pessoa emum objeto Hashtable. A chave usada para cada objeto é o nome da pessoa.

class pessoa { String nome; String tel; public pessoa(String nome, String tel) {this.nome = nome; this.tel = tel;} public String getNome(){return nome;} public String getTel(){return tel;}} ... Hashtable pessoas = new Hashtable(); ... pessoa P1 = new pessoa("Pedro", "899-1313"); pessoas.put(P1.getNome(), P1); ... pessoa P2 =(pessoa) pessoas.get("Pedro"); if (P2!=null) System.out.println ("Nome:"+P2.getNome(), "\nTel:"+P2.getTel());

Exemplo VI.xx – Uso do Hashtable.

Miscelânea de Classes do pacote java.util

Arrays

public class Arraysextends Object

Page 144: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

143

Esta classe foi inserida no pacote java.util a partir da versão 1.2 doSDK. É uma classe utilitária, fornecendo métodos de ordenação e busca emarrays.

Hierarquia

java.lang.Object | +--java.util.Arrays

Métodos

Método Descriçãopublic static List asList(Object[] a) Retorna uma List criada a partir do array.public static int binarySearch(byte[] a, byte key)public static int binarySearch(char[] a, char key)public static int binarySearch(double[] a, double key)public static int binarySearch(float[] a, float key)public static int binarySearch(int[] a, int key)public static int binarySearch(long[] a, long key)public static int binarySearch(Object[] a, Object key)public static int binarySearch(short[] a, short key)

Realiza uma pesquisa binária retornando aposição de key no array.

public static int binarySearch(Object[] a, Object key, Comparator c)

Realiza uma pesquisa binária retornando aposição de key no array. O array tem queestar ordenado ascendentemente de acordocom o Comparator.

public static boolean equals(boolean[] a, boolean[] a2)public static boolean equals(byte[] a, byte[] a2)public static boolean equals(char[] a, char[] a2)public static boolean equals(double[] a, double[] a2)public static boolean equals(float[] a, float[] a2)public static boolean equals(int[] a, int[] a2)public static boolean equals(long[] a, long[] a2)public static boolean equals(Object[] a, Object[] a2)

Retorna true se os dois arrays são iguais.

Page 145: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

144public static boolean equals(short[] a, short[] a2)public static void fill(boolean[] a, boolean val)public static void fill(byte[] a, byte val)public static void fill(double[] a, double val)public static void fill(float[] a, float val)public static void fill(int[] a, int val)public static void fill(long[] a, long val)public static void fill(Object[] a, Object val)public static void fill(short[] a, short val)

Preenche o array com o valor especificado.

public static void fill(boolean[] a, int ini, int fim, boolean val)public static void fill(byte[] a, int ini, int fim, byte val)public static void fill(double[] a, int ini, int fim, double val)public static void fill(float[] a, int ini, int fim, float val)public static void fill(int[] a, int ini, int fim, int val)public static void fill(long[] a, int ini, int fim, long val)public static void fill(Object[] a, int ini, int fim, Object val)public static void fill(short[] a, int ini, int fim, short val)

Preenche o array com o valor especificado apartir do elemento de índice ini inclusiveaté o elemento de índice fim exclusive.

public static void sort(byte[] a)public static void sort(double[] a)public static void sort(float[] a)public static void sort(int[] a)public static void sort(long[] a)public static void sort(Object[] a)public static void sort(short[] a)

Ordena o array em ordem ascendente.

public static void sort(byte[] a, int ini, int fim)public static void sort(double[] a, int ini, int fim)public static void sort(float[] a, int ini, int fim)public static void sort(int[] a, int ini, int fim)public static void sort(long[] a, int ini, int fim)public static void sort(Object[] a, int ini, int fim)public static void sort(short[] a, int ini, int fim)

Ordena o array em ordem ascendente apartir do elemento de índice ini inclusiveaté o elemento de índice fim exclusive.

public static void sort(Object[] a, Comparator c)

Ordena o array em ordem ascendentedefinida pelo objeto Comparator.

public static void sort(Object[] a, int ini, int fim, Comparator c)

Ordena o array em ordem ascendentedefinida pelo objeto Comparator apartir do elemento de índice ini inclusive

Page 146: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

145

até o elemento de índice fim exclusive.

Tabela VI.5 – Métodos da classe Arrays.

O algoritmo de ordenaçãoO algoritmo de ordenação é uma variação quicksort apresentado por Jon L. Bentley e

M. Douglas McIlroy's "Engineering a Sort Function", Software-Practice and Experience, Vol.23(11) P. 1249-1265 (November 1993). Este algoritmo possui complexidade n*log(n) emconjunto de dados que causariam a degradação de outros algoritmos de quicksort para umdesempenho de ordem quadrática.

Exemplo

O exemplo a seguir mostra a impressão ordenada das strings passadaspela linha de comando.

import java.util.arrays;class TestArrays{ public static void main(String a[]) { if(a.length>0) { Arrays.sort(a); for(int i=0;i<a.length; i++) System.out.println(a[i]); } }}

Exemplo VI.xx – Uso do Arrays.

Date

public class Dateextends Objectimplements Serializable, Cloneable, Comparable

Page 147: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

146

Esta classe é responsável pela representação da data com precisão demilisegundos. Antes da versão 1.1 do SDK a classe Date também tinha asfunções de formatação e análise de datas no tipo String assim como deinterpretar as datas em anos, meses, dias, horas, minutos e segundos. Devido àcomplexidade da internacionalização estas funções foram transferidas para asclasses DateFormat e Calendar. O métodos da classe Date que realizavamessas funções tornaram-se deprecated. A data base padrão, a partir da qual sãocontados os milisegundos é 01/01/1970, 00:00:00 GMT.

Hierarquia

java.lang.Object | +--java.util.Date

Construtores

Os construtores deprecated não estão listados.

Construtor Descriçãopublic Date() Constrói um Date representando a data do momento de

sua alocação.public Date(long data) Constrói um Date contendo a data calculada a partir

número de millisegundos representados por data tendocomo base a data 01/01/1970, 00:00:00 GMT.

Tabela VI.xx – Construtores da classe Date.

Métodos

Os métodos deprecated não estão listados.

Método Descriçãopublic boolean after(Date d) Testa se a data é anterior à data passada como

argumento.public boolean before(Date d) Testa se a data é posterior à data passada

como argumento.public Object clone() Cria um clone do objeto.public int compareTo(Date d) Compara duas datas. Retorna 0 se as duas

Page 148: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

147

datas são iguais. Retorna um valor maior que0 se a data passada como argumento é menore um valor menor que 0 se data passada comoargumento e maior.

public boolean equals(Object o) Retorna true se duas datas são iguais.public long getTime() Retorna o número de milisegundos desde

01/01/1970, 00:00:00 GMT até a datarepresentada pelo objeto corrente.

public void setTime(long time) Define a data desde objeto usando o númerode milisegundos desde 01/01/1970, 00:00:00GMT passado como argumento.

Tabela VI.5 – Métodos da classe Date.

Exemplo

O exemplo a seguir exibe a representação da data corrente emmilisegundos.

import java.util.Date;

class TestDate{ public static void main(String a[]) { System.out.println(new Date().getTime());

}}

Exemplo VI.xx – Uso da classe Date.

Observable

public class Observableextends Object

A classe Observable permite criar objetos “observáveis”. Objetoobservável é um objeto que, quando sofre alguma alteração, notifica outrosobjetos, chamados de “observadores”. Os objetos observáveis e observadoresfazem parte do padrão de projeto conhecido como MVC (Modelo–Visão–Controle) introduzido na linguagem Smalltalk. A utilização deste padrão de

Page 149: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

148

projeto facilita a implementação programas onde um modelo possui váriasvisões que devem ser atualizadas toda vez que o modelo muda. O controle atuasobre o modelo, ocasionando alterações. Por exemplo, suponha que modelo quearmazene os valores de ações da bolsa. Podemos exibir várias visões dessesdados, como gráficos de barras e em forma de pizza. Os controladoresmodificariam o modelo que em seguida notificaria as visões para refletirem oestado atual do modelo. As figuras VI.XX e VI.XX ilustram esquematicamenteo padrão MVC. Na linguagem Java, para um objeto ser um observador é precisoimplementar a interface Observer.

Figura VI.XX – Esquema do padrão MVC.

Observável

Figura VI.XX – Duas formas de visualização de um modelo.

Visão

Visão

Modelo

Controle

Controle

a bx 30 45

window X window X

a b

a=30; b=45;

Page 150: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

149

Hierarquia

java.lang.Object | +--java.util.Observable

Construtor

Construtor Descriçãopublic Observable() Constrói um Observable possuindo zero

observadores.

Tabela VI.XX – Construtor da classe Observable.

Métodos

Método Descriçãopublic voidaddObserver(Observer o)

Adiciona um observador ao conjunto deobservadores do objeto.

protected void clearChanged() Limpa a indicação de que o objeto mudou.public int countObservers() Retorna o número de objetos observadores

deste objeto.public voiddeleteObserver(Observer o)

Remove o objeto passado como argumentodo conjunto de objetos observadores.

public void deleteObservers() Remove todos os objetos observadores doconjunto de objetos observadores.

public boolean hasChanged() Retorna true se o objeto sofreu uma mudança.public void notifyObservers() Se o método hasChanged() retornar

true notifica todos os objetos observadorese chama o método clearChanged().

public voidnotifyObservers(Object arg)

Se o método hasChanged() retornartrue notifica todos os objetos observadorese chama o método clearChanged(). Oobjeto arg é passado como argumento para ométodo update() do observador.

protected void setChanged() Marca este objeto como tendo sofrido umamudança.

Tabela VI.XX – Métodos da classe Observable.

Page 151: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

150

Exemplo

O exemplo VI.xx mostra uma classe Observavel que muda de valoraleatoriamente. A classe implementa a interface Runnable, uma vez que seráexecutada concorrentemente. A concorrência será abordada detalhadamente noCapítulo XI.

import java.util.*;

public class Observavel extends Observable implements Runnable{ int valor =0;

public void notifyObservers() { setChanged(); super.notifyObservers(); }

public int getValue(){return valor;}

public void run() { for(;;) { if (Math.random()>0.5) { valor =(new Double(Math.random()*200)).intValue(); this.notifyObservers(); } try {Thread.sleep(300);} catch(Exception e){}; } }}

Exemplo VI.xx – Uma classe Observable.

O exemplo a seguir mostra uma classe que define um observador. Paraisso é necessário implementar a interface Observer, cujo único método a sercodificado é o método update(). Este método é chamado quando o objetoobservado notifica alguma alteração. No exemplo o objeto observador simulauma barra de progresso que movimenta de acordo com a mudança do valor doobjeto observado.

Page 152: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

151import java.awt.*;import java.util.*;

public class FrameOb extends Frame implements Observer{ Observavel ob = new Observavel(); Thread t = new Thread(ob); Canvas progress = new Canvas();

public FrameOb() { setLayout(null); setSize(300,60); add(progress); progress.setBackground(Color.blue); progress.setBounds(0,0,0,30); setTitle("Exemplo de Observável"); SymWindow aSymWindow = new SymWindow(); this.addWindowListener(aSymWindow); ob.addObserver(this); t.start(); }

static public void main(String args[]) {

(new FrameOb()).setVisible(true); }

class SymWindow extends java.awt.event.WindowAdapter { public void windowClosing(java.awt.event.WindowEvent event) { System.exit(0); } }

public void update(Observable o, Object arg) { progress.setSize(ob.getValue(), 100); }}

Exemplo VI.xx – Uso da classe Observable.

StringTokenizer

Page 153: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

152

public class StringTokenizerextends Objectimplements Enumeration

A StringTokenizer é uma classe que permite quebrar uma cadeia decaracteres em subcadeias denominadas de tokens. um token é uma subcadeiacercada por caracteres denominados delimitadores. Portanto, o que é um tokendependerá da especificação dos delimitadores. Por exemplo, dada cadeia decaracteres “ola mundo,ola vida” teremos os tokens “ola mundo” e“ola vida” caso o delimitador seja o caractere ‘,’ e os tokens “ola”,“mundo,ola” e “vida” caso o delimitador seja o caractere ‘ ’

Hierarquia

java.lang.Object | +--java.util.StringTokenizer

Construtores

Construtor DescriçãopublicStringTokenizer(String s)

Constrói um StringTokenizer para s.

publicStringTokenizer(String s,String del)

Constrói um StringTokenizer para s,usando como delimitadores os caracterescontidos em del.

public StringTokenizer (String s, String del, boolean voltaTokens)

Constrói um StringTokenizer para s,usando como delimitadores os caracterescontidos em del. Se voltaTokens possui ovalor true, então os caracteres contidos emdel também são retornados.

Tabela VI.XX – Construtores da classe StringTokenizer.

Métodos

Método Descrição

Page 154: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

153public int countTokens() Retorna o número de tokens.public booleanhasMoreElements()

Mesmo efeito que hasMoreTokens().

public boolean hasMoreTokens() Retorna true se existir mais tokens.public Object nextElement() Retorna o próximo token como uma instância

de Object.public String nextToken() Retorna o próximo token como uma instância

de String.public String nextToken(Stringdel)

Retorna o próximo token como uma instânciade String usando como delimitadores oscaracteres contidos em del.

Tabela VI.XX – Métodos da classe StringTokenizer.

Exemplo

import java.util.*;

public class TestToken{ static public void main(String args[]) { StringTokenizer st = new StringTokenizer("ola mundo louco"); while (st.hasMoreTokens()) println(st.nextToken()); }}

Saída:olamundolouco

Exemplo VI.XX – Uso da classe StringTokenizer.

Agenda Eletrônica versão Console 2.0

Neste ponto já estamos preparados para fazer alguns aperfeiçoamentos nanossa agenda eletrônica de endereços. As alterações serão de dois tipos:passaremos a utilizar um objeto da classe Hashtable para agrupar as pessoasda agenda, e acrescentaremos métodos para gravar e recuperar os dados da

Page 155: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

154

agenda em um arquivo. Estas modificações acarretarão mudanças apenas noscódigos das classes Agenda e AgendaInt. O diagrama de classes da figuraIV.XX mostra as adições dos métodos gravarAgenda() erecuperarAgenda(), responsáveis pela gravação e recuperação dos dadosem arquivo.

Figura VI.xx – Diagrama de classes da versão console 2.0 da agendaeletrônica.

Como a classe Pessoa não sofrerá nenhuma modificação. Ela éapresentada abaixo apenas por questões de comodidade.

/**Pessoa

*/

public class Pessoa{ private String Nome; private String Tel; private String End;

// Construtor public Pessoa(String n, String t, String e) { Nome = n; Tel = t; End = e; }

/**getNome

*/ public String getNome(){return Nome;} /**

getNome

AgendaInt

+obterPessoa()+exibirLista()+exibirPessoa()+gravarAgenda()+recuperarAgenda()

Agenda

+inserir(pessoa p)+getPessoas()+getPessoa(String Nome)

Pessoa

-String Nome-String Tel-String End

+getNome()+getTel()+getEnd()

0..*

Page 156: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

155 */ public String getTel(){return Tel;} /**

getEnd */ public String getEnd(){return End;}}

A classe Agenda será alterada de modo que o a associação deagrupamento com a classe Pessoa seja implementada por meio de um objeto daclasse Hashtable e não por um array.

/**AGENDA Versão Console 2.0.

*/import java.util.*;

public class Agenda{ Hashtable pessoas;

// Construtor public Agenda() {pessoas = new Hashtable();}

/**inserir

*/ public void inserir(Pessoa p) {pessoas.put(p.getNome(),p);}

/**Consultar

*/ public Pessoa getPessoa(String nome) {return (Pessoa) pessoas.get(nome);}

/**listar

*/ public Enumeration getPessoas(){return pessoas.elements();}}

Podemos notar que o código fica bem mais simples com a adoção dainstância da classe Hashtable. Foi alterada a assinatura do métodogetPessoas(), de modo que não mais retorna um array e sim um objeto da

Page 157: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

156

classe Enumeration. A classe AgendaInt será alterada para tratar o retornodo método getPessoas() e receberá mais dois novos métodos. O métodomain() também será alterado para receber solicitações para a execução dasnovas funções.

/**AgendaIntInterface console da agenda.

*/

import java.io.*;import java.util.*;

public class AgendaInt{ Agenda ag; BufferedReader in;

// Construtor public AgendaInt() { ag = new Agenda(); in = new BufferedReader(new InputStreamReader(System.in)); }

/**Exibirlista

*/ public void Exibirlista() { Pessoa p; for(Enumeration e = ag.getPessoas(); e.hasMoreElements();) {

p = (Pessoa) e.nextElement(); System.out.println("\nNome:"+p.getNome()+"\nTelefone:"

+p.getTel()+"\nEndereço:"+p.getEnd()+"\n"); } }

/**exibirPessoa

*/ public void exibirPessoa() { String nome=null;

try { System.out.println("Entre com o nome:");

Page 158: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

157 nome = in.readLine(); if (nome.length()<1) System.exit(-1); } catch(IOException e) {System.out.println(e.getMessage());System.exit(-1);} Pessoa p = ag.getPessoa(nome); if (p!=null) { System.out.println("\nNome:"+p.getNome()+"\nTelefone:" +p.getTel()+"\nEndereço:"+p.getEnd()); } }

/**obterPessoa

*/ public void obterPessoa() { String nome; String tel; String end;

try { System.out.println("Entre com o nome:"); System.out.flush(); nome = in.readLine(); if (nome.length()<1) System.exit(-1); System.out.println("\nEntre com o Telefone:"); System.out.flush(); tel = in.readLine(); System.out.println("\nEntre com o Endereço:"); System.out.flush(); end = in.readLine(); ag.inserir(new Pessoa(nome ,tel,end)); } catch(IOException e) {System.out.println(e.getMessage());System.exit(-1);} }

/** gravar */ public void gravar() { try { Pessoa p; BufferedWriter fout = new BufferedWriter( new FileWriter("agenda.dat")); for (Enumeration e = ag.getPessoas(); e.hasMoreElements();)

Page 159: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

158 { p = (Pessoa) e.nextElement(); fout.write(p.getNome()+"\n"+p.getTel()+"\n" +p.getEnd()+"\n"); } fout.flush(); fout.close(); } catch(FileNotFoundException e) { System.out.println("Arq. Não encontrado");} catch(IOException e) {System.out.println("Erro na gravação!");} }

/**carregar

*/ public void carregar() { try { String nome; String tel; String end;

BufferedReader fin = new BufferedReader( new FileReader("agenda.dat"));

while ((nome = fin.readLine()) != null) { tel = fin.readLine(); end = fin.readLine(); ag.inserir(new Pessoa(nome,tel,end)); } fin.close(); } catch(FileNotFoundException e) {System.out.println("Arq. Não encontrado");} catch(IOException e) {System.out.println("Erro na leitura!"); } }

// main public static void main(String args[]) { AgendaInt agInt = new AgendaInt(); String opcao="";

for(;;) { System.out.println(

Page 160: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

159 "\nAgenda Tabajara\n***********************\n"); System.out.print("Opcoes:\n(i)nserir\n(c)onsultar"+ "\n(l)istar\n(g)ravar\n(r)ecuperar\n(f)im=>"); System.out.flush(); try { opcao = agInt.in.readLine(); if (opcao.length()==0) continue; } catch(IOException e) {System.out.println(e.getMessage());System.exit(-1);}

switch(opcao.charAt(0)) { case 'f': System.exit(0); break; case 'i': agInt.obterPessoa(); break; case 'c': agInt.exibirPessoa(); break; case 'l': agInt.Exibirlista(); break; case 'g': agInt.gravar(); break; case 'r': agInt.carregar(); break; } }

}}

Page 161: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

160

Capítulo VII - Serialização ePersistência

Um objeto é serializável se podemos transformá-lo em uma sequência debytes de modo que seja possível o seu armazenamento em arquivo ou envioatravés de um stream. Desta forma o estado do objeto pode ser preservado emmemória não volátil. Neste caso dizemos que o objeto possui persistência, ouseja o estado do objeto persiste enter as execuções do programa. A persistênciaimplementada pela serialização é chamada de persistência leve, uma vez que oprogramador deve providenciar o armazenamento. Em uma persistênciacompleta o programador apenas informa ao sistema que o objeto é persistente,ficando a cargo do ambiente o armazenamento e recuperação do objeto de formatransparente.

A serialização de objetos foi adicionada à linguagem Java a partir daversão 1.1 com o intuito de possibilitar a transmissão de objetos entre máquinasexecutando diferentes plataformas operacionais, viabilizando dessa forma o RMI(Remote Method Invocation) e permitir a utilização JavaBeans, que sãocomponentes configuráveis em tempo de execução, e que mantém aconfiguração entre ativações.

Para que os objetos de uma classe sejam serializáveis basta que a classeimplemente a interface Serializable. A partir de então é possívelarmazenar e recuperar os objetos da classe por meio de instâncias das classesObjectOutputStream e ObjectInputStream, respectivamente. Oexemplo VII.1 mostra como armazenar e recuperar um objeto da classe Pessoaem um arquivo p.dat.

class pessoa implements Serializable{ String Nome; String Tel; public pessoa(String Nome, String Tel) {this.Nome = Nome; this.Tel = Tel;}} ... Pessoa p = new pessoa(“Ana”,”234-6757”); FileOutputStream fout = null; ObjectOutputStream out;

Page 162: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

161 try { fout = new FileOutputStream(”p.dat"); out = new ObjectOutputStream(fout); out.writeObject(p); out.close(); } catch(Exception e) {System.out.println(”Erro:");return;} FileInputStream fin = null; ObjectInputStream in;

try { fin = new FileInputStream(”p.dat"); in = new ObjectInputStream(fin); p = (pessoa) in.readObject(); in.close(); } catch(Exception e)

{ System.out.println(”Erro:”+e); return;}

Exemplo VII.1 – Armazenamento e recuperação de um objeto da classePessoa.

Uma questão interessante é: o que acontece com os objetos que sãoreferenciados pelo objeto que está sendo armazenado? Devem ser armazenadostambém ou não? Se os objetos referenciados não forem armazenados juntos como objeto corrente, a recuperação do mesmo posteriormente poderá resultar emuma instância incompleta. Por exemplo, um objeto do tipo Pessoa comomostrado no exemplo VII.1, referencia dois objetos do tipo String quearmazenam o nome e o telefone da pessoa representada pelo objeto. Se estesobjetos não forem armazenados junto com a instância de Pessoa, qual osentido da posterior recuperação do objeto? Portanto, quando um objeto éarmazenado todos os objetos referenciados por ele também são armazenados,desde que os objetos implementem a interface Serializable. Caso o objetoreferenciado também referencie outro objeto, este último também seráarmazenado, e assim por diante, até que toda os objetos da cadeia de referenciassejam armazenados. Isto pode fazer com que o objeto armazenado ocupe muitomais espaço do que o imaginado inicialmente pelo programador. Outra perguntaseria: o que acontece então quando um objeto é referenciado mais de uma vezou quando acontece um ciclo no grafo de referências? Neste caso, o objeto éarmazenado apenas uma vez.

Page 163: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

162

Agenda Eletrônica versão Console 2.1

Com o objetivo de exemplificar o que foi discutido neste capítulo,modificamos a agenda eletrônica para que a gravação e a carga do arquivo sejafeita através da serialização do objeto Agenda. Primeiramente, foi modificadaas classes Pessoa e Agenda de modo que implementassem a interfaceSerializable. Para isto basta importar a interface do pacote java.io emodificar a declaração das classes, como mostrado abaixo. Como o restante docódigo dessas duas classes permanece inalterado, não o repetimos aqui. O leitordeve se reportar às versões anteriores caso deseje recordar sobre o códigoomitido.

/**Pessoa

*/import java.io.*;

public class Pessoa implements Serializable{

...Sem alteração...

}

/**AGENDA Versão Console 2.1.

*/import java.util.*;import java.io.*;

public class Agenda implements Serializable

{...Sem alteração...

}

A classe AgendaInt sofre modificações nos métodos gravar() ecarregar(), que os tornam bem mais simples, uma vez que o trabalho deseguir as referências do objeto da classe Agenda para serializá-los e armazená-los é feito implicitamente. Segue abaixo apenas o código dos métodosmodificados classe AgendaInt. Note que foi preciso usar a hierarquia stream

Page 164: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

163

para gravar e recuperar os objetos, uma vez que não existem classes do tipoObjectReader e ObjectWriter no novo conjunto de classes de E/S.

/**AgendaIntInterface console da agenda.

*/

import java.io.*;import java.util.*;

public class AgendaInt{ ... Sem alteração ... /** gravar */ public void gravar() { try { ObjectOutputStream fout = new ObjectOutputStream( new FileOutputStream("agenda.dat")); fout.writeObject(ag); fout.close(); } catch(FileNotFoundException e) { System.out.println("Arq. Não encontrado");} catch(IOException e) {System.out.println("Erro na gravação!");} }

/**carregar

*/ public void carregar() { try { ObjectInputStream fin = new ObjectInputStream( new FileInputStream("agenda.dat")); ag = (Agenda) fin.readObject(); fin.close(); } catch(FileNotFoundException e) {System.out.println("Arq. Não encontrado");} catch(Exception e) {System.out.println("Erro na leitura!"); } }

Page 165: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

164 ... Sem alteração ...}

Page 166: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

165

Capítulo VIII – AWT (AbstractWindow Toolkit)

Até este ponto, todos o exemplos apresentados neste livro foram deaplicações em modo texto, também chamadas de aplicações não gráficas ou deconsole. Hoje em dia, não é possível lançar no mercado uma linguagem deampla aplicação que não possua ferramentas para construção de interfacesgráficas sofisticadas. A linguagem Java além de ter a necessidade de atender esterequisito possui a condição adicional de prover recursos gráficos que permitam odesenvolvimento de interfaces independentes de plataforma. Talvez, devido aesta forte exigência, a primeira versão do pacote que implementa o suportegráfico acabou sendo conhecido como um excelente exemplo de como não sedeve realizar um projeto. O pacote conhecido como AWT 1.0 (Abstract WindowToolkit), não era muito harmônico, tinha um conjunto muito pobre decomponentes gráficos e possuía um modelo para tratamento de eventos muitoineficiente. A versão AWT 1.1 solucionou vários deste problemas, com ooferecimento de um novo modelo para tratamento dos eventos e com aintrodução de um modelo para programação de componentes, denominados deJavaBeans. Na versão 1.2 da linguagem novas facilidades foram incorporadascom a adição de um conjuntos de componentes leves, denominados de Swing, ouJFC (Java Foundation Classes). A denominação de componentes leves para aJFC se deve ao fato dos componentes não utilizarem os componentes nativos daGUI (Graphical User Interface) do ambiente. Eles utilizam primitivas de baixonível para sua construção na tela, obtendo assim um alto nível de portabilidade.Já a AWT utiliza os componentes da GUI (widgets), para sua exibição e por issosão chamados de componentes pesados. Por isso, para atingir uma portabilidaderazoável, apenas componentes básicos estão presentes na AWT. Mesmo assim aportabilidade da AWT não é tão grande quanto a JFC, apresentando, em algunscasos, grandes diferenças de visualização entre ambientes operacionais.

Neste capítulo, abordaremos a versão 1.1 do AWT. Os componentes daJFC/Swing serão tratados isoladamente no capítulo XX.

A Hierarquia de componentes

Page 167: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

166

O AWT é um pacote contendo classes e interfaces para a criação de objetospara interação em janelas gráficas. Com essas classes é possível criar e manterobjetos tais como:

♦ Botões (Classe Button)♦ Caixa de Escolha (Classe Choice)♦ Diálogos (Classe Dialog)♦ Janelas (Classe Window)♦ Menus (Classe Menu)♦ Barra de Rolamento (Classe Scrollbar)♦ Etc.

As classes se organizam em uma hierarquia. A figura VI.XX mostra aorganização hierárquica das classes.

! Color! Component

" Button" Canvas" Checkbox" Choice" Container

# Panel# ScrollPane# Window

• Dialog

♦ FileDialog• Frame

" Label" List" Scrollbar" TextComponent

# TextArea# TextField

! MenuComponent" MenuBar" MenuItem

# Menu

Page 168: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

167

Figura VI.1 – Hierarquia das classes no pacote AWT.

Olá Mundo AWT

Para usar classes definidas na AWT é preciso importá-las:

import java.awt.*;

Algumas classes são usadas para criar objetos que servirão para conter outrosobjetos. Estas classes são descendentes da classe Container. Cada classepossui um conjunto de atributos que podem ser acessados por meio de métodos.Como de praxe, apresentaremos primeiramente a versão AWT do “olá mundo”para ilustrar os principais componentes de uma aplicação

import java.awt.*;

class OlaFrame extends Frame{ public OlaFrame() { super(“Ola”); setSize(100,50); add(new Label("ola mundo")); } public static void main(String args[]){ new OlaFrame().setVisible(true); }}

Exemplo XX.XX – Versão AWT do “Olá mundo”.

Para criarmos uma aplicação gráfica precisaremos de algum tipo dejanela para colocarmos os componentes. Por isso a classe OlaFrame doexemplo XX.XX é uma subclasse da classe Frame que, por sua vez, esubclasse da classe Window. A classe Frame implementa uma janela gráficacom título e margem, sendo que a área do Frame inclui a margem. No exemploconstrutor da classe invoca o construtor da superclasse, passando comoargumento o título da janela.

Page 169: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

168

A classe Frame cria uma janela com 0 x 0 pixels e invisível. Paradimensioná-la e torná-la visível é necessário usar os métodos setSize() esetVisible(). A classe Label é usada para criar um objeto de texto que éadicionado ao Frame. O objeto é posicionado dentro do Frame de acordo comum esquema de posicionamento, denominado de layout. Se você executou esteprograma deve ter notado que não foi possível finalizar o programa a não ser pormeio de um Ctrl-C na console ou algum outro método indireto como o kill dashell Unix. Isto acontece porque os objetos gráficos na linguagem Java nãopossuem tratadores implícitos de eventos. Ou seja, se você quer que algumevento seja tratado, então forneça o código para isto.

Existem dois modelos para tratamento dos eventos que incidem sobre ainterface. O primeiro foi introduzido na versão 1.0 do AWT e o segundo foiintroduzido na versão 1.1 do AWT com o objetivo de substituir o primeiro, umavez que ele sofre de deficiências de projeto e desempenho. Neste livroabordaremos apenas o modelo de eventos 1.1.

Tratamento de Eventos

O estilo de programação relacionado com interfaces gráficas é aprogramação voltada para eventos. Ou seja, o usuário define a interface e umconjunto de procedimentos para lidar com os eventos que incidirão sobre ainterface. A construção de uma aplicação gráfica exige a criação de pelo menosum objeto que defina uma área no vídeo para exibir os componentes daaplicação. Para isso pode-se utilizar um objeto da classe Window ou Frame. Oexemplo XX.XX contém o código de um programa que exibe uma mensagem natela. Posteriormente é necessário definir quem deve receber os eventos geradospela interação com a interface. Cada linguagem apresenta uma solução distintapara o tratamento de eventos. A solução Java implementada no modelo deeventos 1.1 é explicada a seguir.

Modelo de Eventos 1.1

O Modelo de eventos do AWT1.1 é um grande avanço sobre o modelo1.0. Ele não só é mais flexível e orientado a objetos, como permitiu odesenvolvimento da interface de aplicação JavaBeans, que viabiliza a descriçãode componentes visuais.

Page 170: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

169

A idéia por trás do novo modelo é que uma fonte de eventos possa enviaros eventos para um ou mais objetos cadastrados para o recebimento do evento,denominados de event listeners. Geralmente, a fonte de evento é umcomponente, ou seja, um objeto da classe Component. Um listener é um objetoque implementa a interface EventListener ou alguma de suas sub-interfaces. A figura IV.XX ilustra a estratégia adotada.

Figura VI.XX – Esquema de delegação de eventos AWT1.1.

Note que um Listener pode estar registrado em mais de umcomponente. Um componente pode ter mais de uma lista de Listener,dependendo dos tipos de eventos que ele pode gerar. Uma ação sobre umcomponente pode gerar mais de um evento. Para ilustrar o tratamento deeventos, o exemplo XX.XX mostra como criar uma janela da classe Frame quetrata o evento para fechar a janela, gerado quando o usuário clica o ícone ××××,situado no canto superior direito do Frame.

class FrameX extends Frame implements WindowListener{ public FrameX() {this("FrameX");}

public FrameX(String Titulo){ super(Titulo); addWindowListener(this); setSize(100,50); }

Componente1

A

Componente2

B

Listener

Listener

Listener

Listener

Listener

evento

evento

Page 171: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

170 public void windowOpened(WindowEvent we){} public void windowClosed(WindowEvent we){} public void windowIconified(WindowEvent we){} public void windowDeiconified (WindowEvent we){} public void windowActivated(WindowEvent we){} public void windowDeactivated(WindowEvent we){} public void windowClosing(WindowEvent we){ setVisible(false); dispose(); System.exit(0); }};

Exemplo XX.XX – Código para tratar o evento para fechar a janela.

Para simplificar o exemplo o próprio componente (do tipo Frame) seregistrou como um Listener para os eventos gerados por ele. De modo a sehabilitar a receber os eventos gerados por um componente do tipo Window aclasse deve implementar a interface WindowListener que é uma sub-interface da EventListener.

class FrameX extends Frame implements WindowListener

É preciso também se registrar junto ao componente para receber oseventos. Como no exemplo VI.XX o componente é uma instância da própriaclasse que implementa a interface, basta então adicionar a linhaaddWindowListener(this) no construtor da classe. Como a classeimplementa a interface é necessário incluir código para implementar todos osmétodos da interface. Cada método da interface trata um tipo de evento. No casodo exemplo VI.XX, estamos interessados em tratar eventos que solicitam ofechamento da janela. Portanto, é necessário incluir o código para tratamento doevento neste método. Os outros métodos são implementados sem linhas decódigo, para cumprir a exigência do compilador. Note que todos os métodos daclasse FrameX recebem um tipo de evento: WindowEvent. No modelo deeventos 1.1, na versão SDK1.3, existem 14 classes para os eventos, definidas nopacote java.awt.event, todas subclasses da classejava.awt.event.AwtEvent e cada uma representando um conjunto deeventos relacionados, como mostrado na tabela VI.XX.

Evento DescriçãoComponentEvent Indica que um componente moveu, foi escondido, exibido ou mudou

de tamanho.

Page 172: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

171FocusEvent Indica que um componente recebeu ou perdeu o foco.KeyEvent Indica que um componente recebeu uma entrada pelo teclado.MouseEvent Indica que um componente recebeu uma entrada pelo mouse.ActionEvent Indica que um componente foi ativado.AdjustmentEvent Indica que uma barra de rolamento ou componente similar foi

movido.HierarchyEvent indica uma mudança na hierarquia de componentes a qual o

componente pertence.InputEvent É o evento raiz de todos os eventos de entrada

de componentes.InputMethodEvent Contém informação sobre o texto que está sendo editado. Sempre que

o texto for alterado este evento será enviado.InvocationEvent O evento que executa o método run() em um tipo Runnable

quando disparado pelo thread despachador de eventos da AWT.ItemEvent Indica que um item de um componente como lista, checkbox, ou

similar foi selecionado.ContainerEvent Indica que um componente foi adicionado ou removido de um

container.WindowEvent Indica que a janela mudou de estado.TextEvent Indica que uma mudança ocorreu em um campo de texto.

Tabela VI.XX – Classes de Eventos.

O exemplo XX.XX mostra o código de uma janela contendo um botão. Aclasse que implementa a janela se cadastra junto ao componente Button parareceber o eventos sobre os componente. Para diminuir a complexidade do códigoa classe FrameBotao é subclasse da FrameX definida anteriormente. Todavez que o componente Button é acionado, gerando um eventoActionEvent, o método actionPerformed() da instânciaFrameBotao é invocado. O método alterna o texto exibido pelo botão a cadachamada entre os textos “Aperte aqui” e “Valeu”.

import java.awt.*;import java.awt.event.*;

public class FrameBotao extends FrameX implements ActionListener{ Button b;

public FrameBotao() { setLayout(null); setSize(100,80); b = new Button("Aperte aqui");

Page 173: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

172 add(b); b.setBounds(10,40,80,30); b.addActionListener(this); }

public void actionPerformed(ActionEvent e) { if (b.getLabel().equals("Aperte Aqui")) b.setLabel(“Valeu”); else b.setLabel("Aperte Aqui"); }

public static void main(String args[]){ (new FrameBotao()).setVisible(true); }}

Exemplo XX.XX – Código para tratar um evento gerado em botão.

Tratamento de Eventos com classes Internas

Agora vamos supor que uma determinada classe necessitasse recebervários eventos de vários componentes. O código da classe poderia ficar umpouco confuso, além da lista enorme de interfaces que necessitariam de serdeclarada após a palavra implements. Uma forma mais elegante de se lidarcom estes casos é por meio de classes internas, ou inner classes. Desta forma, ocódigo para tratar cada grupo de eventos fica localizado em uma única classe, ecomo as classes internas possuem acesso à classe externa, os atributos e métodosda classe externa podem ser diretamente referenciados. O exemplo XX.XXmostra o exemplo XX.XX alterado de forma que o evento ActionEventgerado acionamento do componente Button seja tratado por uma classeinterna.

import java.awt.*;import java.awt.event.*;

public class FrameBotao extends FrameX{ Button b;

Public FrameBotao()

Page 174: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

173 { setLayout(null); setSize(100,80); b = new Button("Aperte Aqui"); add(b); b.setBounds(10,40,80,30); b.addActionListener(new Bl()); }

class Bl implements ActionListener { public void actionPerformed(ActionEvent e) { if (b.getLabel().equals("Aperte Aqui")) b.setLabel(“Valeu”); else b.setLabel("Aperte Aqui"); } }

public static void main(String args[]){ (new FrameBotao()).setVisible(true); }}

Exemplo XX.XX – Código para tratar um evento gerado em botão.

Cada componente pode receber um determinado conjunto de listener parareceber eventos. A Figura VI.XX mostra a relação entre alguns componentes eos eventos que podem ser gerados por eles.

Page 175: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

174

Figura XX.XX – Relação entre os componentes e os eventos.

FocusEvent

ActionEvent

AdjustmentEvent

ItemEvent

ContainerEvent

TextEvent

WindowEvent

TextFieldMouseEvent

Scrollbar

Component

Label

Dialog

Panel

MenuItem

Button

Frame

Choice

Menu

ComponentEvent

KeyEvent

Page 176: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

175

As instâncias das classes de eventos mantém as informações relativas aoevento. Por exemplo, a classe MouseEvent possui os seguintes métodos pararecuperação de informação sobre o evento:

Método Descriçãoint getId() tipo do evento. Por exemplo:

MouseEvent.MOUSE_CLICKED,MouseEvent.MOUSE_PRESSED

int getX() coordenada x do evento.int getY() coordenada y do evento.Point getPoint() coordenada x e y do evento.int getClickCount() retorna o número de mouse clicks.boolean isPopupTrigger() indica se o evento é um disparo para menu pop-up.void translatePoint(int x, int y)

move a posição do evento por x e y.

Tabela VI.XX – Métodos da classe MouseEvent.

Basicamente, para se codificar um tratador para um determinado eventobasta seguir os seguintes passos:

1. Determine o grupo de eventos deseja tratar.2. No nome do grupo de eventos substitua o termo trecho Event por

Listener. Este é o nome da interface que você deve implementar. Crieuma classe interna que implementa a interface.

3. Codifique os métodos que tratam os eventos que você deseja tratar. Todos osmétodos da interface tem que ser implementados, mas o corpo dos métodosque não interessam podem ser deixados vazios.

4. Registre um objeto da classe interna junto ao componente, por meio dométodo addXXX, onde XXX é o nome da interface implementada.

Por exemplo, no exemplo VI.XX, para tratar o grupo de eventosActionEvent foi criada uma classe interna que implementa a interfaceActionListener, e um objeto da classe interna é registrado no componentepor meio do método addActionListener. Portanto, tendo o nome do grupode eventos é fácil obter o nome da interface e do método de registro nocomponente. Segue abaixo uma lista com alguns métodos para registro delisteners.

♦ Button.addActionListener(ActionListener l)

Page 177: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

176

♦ Frame.addWindowListener(WindowListener l)♦ Choice.addItemListener(ItemListener l)♦ TextField.addTextListener(TextListener l)♦ Scrollbar.addAdjustamentListener(AdjustamentListene

r l)♦ Component.addComponentListener(ComponentListener l)♦ Component.addFocusListener(FocusListener l)♦ Component.addKeyListener(KeyListener l)

Algumas interfaces exigem a implementação de um grande número demétodos, como por exemplo a interface WindowListener, como foi visto noexemplo VI.XX. Isto pode tornar a implementação das interfaces uma tarefa umtanto tediosa. Com o objetivo de auxiliar esta tarefa, foi incluído no pacotejava.awt.event seis classes abstratas, denominadas adapters que facilitama implementação de Listener. O programador só precisa criar uma subclasse daclasse adapter escolhida e sobrescrever o método desejado. Para determinar onome da classe adapter basta substituir no nome da interface a subcadeiaListener por adapter. A tabela VI.XX apresenta os nomes das classes adapters.

ComponentAdapterContainerAdapterFocusAdapterKeyAdapterMouseAdapterMouseMotionAdapterWindowAdapter

Tabela VI.XX – Classes adapters.

O exemplo XX.XX mostra o exemplo XX.XX alterado de forma que oevento ActionEvent gerado acionamento do componente Button sejatratado por uma classe interna que é subclasse da classe MouseAdapter.

import java.awt.*;import java.awt.event.*;public class Botao extends FrameX { Button b; public Botao() {

Page 178: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

177 setLayout(null); setSize(100,80); b = new Button("Aperte Aqui"); add(b); b.setBounds(10,40,80,30); b.addActionListener(new Bl()); } class Bl extends MouseAdapter { public void actionPerformed(ActionEvent e) { if (b.getLabel().equals("Aperte Aqui")) b.setLabel("Valeu"); else b.setLabel("Aperte Aqui"); } } public static void main(String args[]){ (new Botao()).setVisible(true); }}

Exemplo XX.XX – Código para tratar um evento gerado em botão.

No entanto, existem algumas desvantagens em se usar classes abstratasno lugar de interfaces. A primeira delas é que elimina a possibilidade da classeser subclasse de outra classe e a segunda é que se o programador cometer algumerro na digitação do nome de algum método, ele será encarado como um novométodo e o original não será sobrescrito.

Exemplo Básico

Apresentaremos agora um exemplo um pouco mais complexo, porémsimples o suficiente para que seja facilmente entendido. O objetivo desteexemplo e servir de base para apresentarmos os principais componentes dabiblioteca AWT. Portanto, a medida que novos componentes foremapresentados, iremos exemplificar o uso deste componentes acrescentando-osem nosso exemplo básico.

A função de nosso exemplo é servir como ambiente para execução decomandos MS-DOS, tais como dir e type. O exemplo foi projetado parafuncionar nos ambientes MS-WINDOWS 95 e MS-WINDOWS 98 mas pode serfacilmente adaptado para funcionar em outros ambientes operacionais. A figuraXX.XX mostra a interface da primeira versão de nosso exemplo. Note que,apesar de simples, o nosso exemplo apresenta três componentes em sua

Page 179: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

178

interface: um botão e duas caixas de texto, sendo uma com barras de rolamento ecapacidade para múltiplas linhas.

Figura XX.XX – Aparência da aplicação para execução de comandos MS-DOS.

A caixa de texto com capacidade para uma linha de texto é um componenteTextField e sua função é permitir a entrada de comandos dos para aexecução. A caixa de texto com capacidade para múltiplas linhas de texto é umcomponente TextArea e sua função é exibir o resultado da execução docomando. Finalmente, o botão é implementado por um componente Button esua função e gerar eventos para execução do comando digitado. O exemploXX.XX mostra o código da aplicação, implementado pela classe Comando.

123456

import java.io.*;import java.awt.*;import java.awt.event.*;

public class Comando extends Frame { private TextField tfComando;

Page 180: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

179

78910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

private TextArea taSaida; private Button btExec; private String com;

public Comando() { com = "command.com /c "; // Altere essa linha para outros ambientes operacionais

tfComando = new TextField(50); taSaida = new TextArea(20,60); btExec = new Button(“Executa”);

taSaida.setEditable(false);

add(tfComando,BorderLayout.NORTH); add(btExec,BorderLayout.SOUTH); add(taSaida,BorderLayout.CENTER);

addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) {

System.exit(0); }

});

btExec.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) {

btExecActionPerformed(evt); }

}); pack(); }

private void btExecActionPerformed(ActionEvent evt) { String s = tfComando.getText(); if (s==null) return; try { Process p = Runtime.getRuntime().exec(com+s); InputStream in = p.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String line; taSaida.setText(""); while ((line = br.readLine()) != null) { taSaida.append(line+'\n'); } taSaida.append("Fim!"); } catch(Exception e) {taSaida.setText(e.getMessage()); return;} }

public static void main(String args[]) {new Comando().show();

Page 181: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

180

5657

}}

Exemplo XX.XX – Código que executa um comando DOS.

Na linha 12 é criado um objeto String contendo o parte inicial do comandonecessário para invocar a shell do MS-DOS. Essa parte inicial deve ser alteradapara adaptar o exemplo para outros sistemas operacionais. Nas linhas 14 a 16são criados os componentes que farão parte da interface. Na linha 14 ocomponente TextField é criado com espaço para exibir 50 caracteres. Nalinha 15 o componente TextArea é criado com espaço para exibir 20 linhas e50 caracteres por linha. Na linha 16 o componente Button é criado com um otexto “Executa”. Na linha 18 é chamado o método setEditable() docomponente TextArea com o argumento false para impedir que o seuconteúdo seja editado. Isso ocorre porque a função do componente é apenasexibir o resultado da execução dos comandos.

O leitor deve ter notado que a criação das classes que irão tratar os eventos éum pouco diferente do que mostramos até agora. Nas linhas 24 a 28 e 30 a 34 asdeclarações das classes são feitas no mesmo local onde os objetos sãoinstanciados. Este tipo de classe interna é denominado de classe internaanônima. A classe é denominada de anônima pois nenhum nome é associado aela. A classe anônima se torna automaticamente subclasse da classe mencionadaapós o operador new. É vantajoso usar este tipo de construção quando apenasuma instância da classe será gerada, uma vez que amarra a declaração da classecom seu uso. No entanto, em alguns casos esta técnica pode diminuir alegibilidade do código.

Outro fato que pode intrigar o leitor é a distribuição dos componentes najanela. Aparentemente, pouco código foi dedicado ao posicionamento doselementos na interface. Mesmo assim os componentes foram arranjados deforma razoavelmente ordenada na interface. Isto se deve ao fato de todos oscomponentes do tipo Container seguirem um arranjo predefinido (layout).Este arranjo é implementado pelas classes BorderLayout, CardLayout,FlowLayout, GridBagLayout e GridLayout, sendo o BorderLayouto arranjo default. Existe também a possibilidade de não se adotar nenhumlayout. Neste caso é preciso posicionar os componentes em termos decoordenadas dentro do objeto do tipo Container. Os objetos de layout serãotratados mais adiante. No momento basta saber que o layout adotado é o defaulte que este tipo de layout arranja os componentes de acordo com os pontoscardeais (NORTH, SOUTH, EAST, WEST, CENTER). As linhas 20 a 22

Page 182: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

181

mostram as adições de componentes dentro do Frame, com a indicação do seusposicionamentos relativos segundo o layout adotado. A adição de componentesé feita por meio do método add().

As linhas 38 a 52 mostram o código do método que executa o comando MS-DOS e exibe o resultado no componente TextArea. Na linha 42 o comandoMS-DOS é executado por meio do método exec() do objeto Runtime. Oobjeto Runtime é obtido pelo método estático getRuntime() da classeRuntime, uma vez que não pode ser instanciado diretamente. O processo filho,uma vez iniciado, é executado de forma concorrente com o processo pai. Ométodo exec() retorna um objeto do tipo Process, tornando possívelcontrolar o processo e obter informações sobre ele. No nosso caso estamosinteressados em capturar a saída padrão do processo filho para exibi-la nainterface. Isso é feito na linha 43 por meio do método getInputStream()do objeto Process. O objeto InputStream é canalizado para um objetoBufferedReader com o objetivo de facilitar sua manipulação. As linhasrestantes do método tratam da leitura da saída padrão do processo filho e de suaexibição na TextArea. Na linha 46 é usado o método setText() paracolocar um texto vazio no componente e, dessa forma, limpar a TextArea. Nalinha 48 a String lida da saída padrão do processo filho é anexada naTextArea.

Acrescentando Cores

Podemos alterar as cores de alguns componentes do exemplo XX.XX paratorná-lo visualmente mais interessante por meio de objetos da classe Color.Esta classe encapsula a criação de cores por meio dos níveis RGB. Ela mantémtambém um conjunto de atributos constantes com valores de cores predefinidos.Podemos, por exemplo, alterar a cor de fundo do componente TextArea pormeio do método setBackground().

taSaida.setBackground(Color.lightGray);

Podemos alterar também a cor de fundo do componente Button. Nestecaso vamos obter para definir a cor por meio de um número que representa seuscomponentes RGB.

btExec.setBackground(new Color(0x08FDDF10));

Page 183: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

182

Para modificar a cor frontal é preciso utilizar o métodosetForeground(). Todos os componentes possuem métodos equivalentes aestes para alteração das cores.

Gerenciando o Layout

O posicionamento de componentes dentro de objetos do tipo Container édeterminado por uma instância de objeto denominado de gerenciador de layout(layout managers). A AWT fornece 5 classes para a implementação de layouts,descritas na tabela XX.XX. O layout default é o implementado pela classeBorderLayout. O pacote Swing acrescenta a classe BoxLayout ao conjuntode gerenciadores de layout.

Gerenciador de Layout DescriçãoBorderLayout Posiciona e redimensiona os componentes de um Container

em cinco regiões: norte, sul, leste e oeste. Cada região éidentificada respectivamente pelas constantes: NORTH, SOUTH,EAST, WEST, e CENTER.

FlowLayout Posiciona os componentes de um Container em um fluxo daesquerda para a direita, como linhas em um parágrafo. Cadalinha é centralizada.

CardLayout Trata cada componente do Container como uma a carta.Somente uma carta é visível em um determinado instante e oContainer funciona como uma pilha de cartas. O primeirocomponente adicionado é o primeiro visível quando oContainer é exibido.

GridBagLayout É o gerenciador de layout mais flexível e o mais complexo. Elearranja os componentes verticalmente e horizontalmente semexigir que os componentes tenham o mesmo tamanho. Mantémum grade retangular de células, sendo que cada componentepode ocupar mais de uma célula.

GridLayout Posiciona e redimensiona os componentes de um Containerem uma grade retangular. O Container é dividido emretângulos de tamanhos iguais e um componente é colocado emcada retângulo.

Tabela XX.XX –Gerenciadores de Layout.

Page 184: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

183

Para definir o layout de um objeto do tipo Container basta utilizar ométodo setLayout() do objeto, passando como argumento um objetogerenciador de layout, como mostrado abaixo:

Frame f = new Frame();f.setLayout(FlowLayout);

É possível também não adotar layout algum, optando por posicionar oscomponentes em coordenadas absolutas dentro do Container. Para isso bastapassar null como argumento para o método setLayout(). Oposicionamento absoluto de componentes pode ser feito pelos métodossetLocation() ou setBounds() do componente, como mostrado abaixo.

Frame f = new Frame();f.setLayout(null);Button b = new Button(“Teste”);f.add(b);b. setLocation(10, 10);

Porém, a adoção de gerenciadores de layout permite o desenvolvimento quese adaptam mais facilmente à redimensionamentos e à mudanças de linguagens.Isto é o posicionamento e dimensionamento absoluto pode fazer com quecomponentes tornem-se parcialmente ou totalmente ocultos com oredimensionamento da janela. O mesmo pode ocorrer com os “labels” doscomponentes quando forem traduzidos para outra língua. Já estes problemas nãoocorrem com o posicionamento e dimensionamento relativo.

Exemplo com BorderLayout

O exemplo XX.XX utiliza este gerenciador de layout para distribuir oscomponentes na interface. O exemplo abaixo mostra distribuição de cinco botõesem um Frame por meio deste tipo de gerenciador de layout.

import java.awt.*;

public class BorderTeste extends FrameX { public BorderTeste() { setLayout(new BorderLayout()); add(new Button("Norte"), BorderLayout.NORTH);

Page 185: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

184

add(new Button("Sul"), BorderLayout.SOUTH); add(new Button("Leste"), BorderLayout.EAST); add(new Button("Oeste"), BorderLayout.WEST); add(new Button("Centro"), BorderLayout.CENTER); }

public static void main(String a[]){new BorderTeste().show();}}

Exemplo XX.XX – Frame com BorderLayout.

A figura XX.XX mostra o resultado da execução do código do exemploXX.XX.

Figura XX.XX – Aparência do Frame com BorderLayout.

Exemplo com FlowLayout

O exemplo abaixo mostra distribuição de cinco botões em um Frame pormeio deste tipo de gerenciador de layout.

import java.awt.*;

public class FlowTeste extends FrameX { public FlowTeste() { setLayout(new FlowLayout());

Page 186: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

185

add(new Button("UM")); add(new Button("DOIS")); add(new Button("TRÊS")); add(new Button("QUATRO")); add(new Button("CINCO")); setSize(200,100); }

public static void main(String a[]){new FlowTeste().show();} }

Exemplo XX.XX – Frame com FlowLayout.

A figura XX.XX mostra o resultado da execução do código do exemploXX.XX. Note que quando acaba o espaço em uma linha os componentes sãoposicionados na linha de baixo seguindo da esquerda para a direita. Notetambém que cada linha é centralizada no Container.

Figura XX.XX – Aparência do Frame com FlowLayout.

Exemplo com CardLayout

O exemplo abaixo mostra usar o CardLayout para alternar a exibição decomponentes. Um botão é adicionado à interface para receber eventos. Quando obotão é pressionado o tratador de eventos alterna a exibição dos componentes doCardLayout por meio de chamadas ao método next() do gerenciador delayout. A JFC fornece o componente JtabbedPane que apresenta maioresfacilidades.

import java.awt.*;import java.awt.event.*;

public class CardTeste extends FrameX {

Page 187: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

186

Panel p; CardLayout cl; Button b;

public CardTeste() { setLayout(new BorderLayout()); p = new Panel(); b = new Button("Muda carta"); cl = new CardLayout();

p.setLayout(cl); p.add(new Label("Este Label está na primeira carta"),"um"); p.add(new Label("Este Label está na segunda carta"),"dois"); add(b, BorderLayout.NORTH); add(p, BorderLayout.SOUTH); b.addActionListener( new ActionListener() {

public voidactionPerformed(ActionEvent evt) {

cl.next(p); }

}); pack(); }

public static void main(String a[]){new CardTeste().show();}}

Exemplo XX.XX – Frame com CardLayout.

Note que ao adicionar um componente ao Container é preciso passar umidentificador. A figura XX.XX mostra o resultado da execução do código doexemplo XX.XX.

Figura XX.XX – Aparência do Frame com CardLayout.

Page 188: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

187

Exemplo com GridLayout

O exemplo abaixo mostra distribuição de cinco botões em um Frame pormeio deste tipo de gerenciador de layout.

import java.awt.*;

public class GridTeste extends FrameX { public GridTeste() { setLayout(new GridLayout(3,2)); add(new Button("UM")); add(new Button("DOIS")); add(new Button("TRÊS")); add(new Button("QUATRO")); add(new Button("CINCO")); }

public static void main(String a[]){new GridTeste().show();} }

Exemplo XX.XX – Frame com GridLayout.

A figura XX.XX mostra o resultado da execução do código do exemploXX.XX.

Figura XX.XX – Aparência do Frame com GridLayout.

Page 189: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

188

Exemplo com GridBagLayout

Este gerenciador é o mais complexo, mas é também o que permite um maiorcontrole sobre o posicionamento dos elementos, sem perder as vantagens de umposicionamento relativo. O exemplo XX.XX mostra distribuição de nove botõesem um Frame por meio deste tipo de gerenciador de layout.

import java.awt.*;

public class GridBagTeste extends FrameX { public GridBagTeste() { Button b; GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints();

setLayout(gridbag);

for (int i=1;i<10;i++) { switch(i) { case 1: c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; break; case 6: case 3: c.gridwidth = GridBagConstraints.REMAINDER; c.weightx = 1.0; break; case 4: c.weightx = 0.0; break; case 5: c.gridwidth = GridBagConstraints.RELATIVE; c.weightx = 1.0; break; case 7: c.gridwidth = 1; c.gridheight = 2; c.weighty = 1.0; break; case 8: c.gridwidth = GridBagConstraints.REMAINDER; c.weighty = 0.0; c.gridheight = 1; break; } b = new Button("Botão "+i); gridbag.setConstraints(b, c); add(b);

Page 190: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

189

} pack(); }

public static void main(String args[]) { new GridBagTeste().show(); } }

Exemplo XX.XX – Frame com GridBagLayout.

O posicionamento relativo dos componentes é controlado por meio de umobjeto da classe GridBagConstraints. Ele possui vários atributos públicos queorientam o gerenciador de layout no momento de posiciona e reorganizar oscomponentes. O objeto é associado a cada componente por meio do métodosetConstraints() da instância GridBagLayout. Os atributos utilizados noexemplo foram:

fill – usado quando a área para a exibição do componente é maior que aárea é requisitada pelo componente. Os valores possíveis (definidos naclasse GridBagConstraints) são NONE (default), HORIZONTAL (torna ocomponente largo o suficiente para preencher a área horizontalmente),VERTICAL (torna o componente alto o suficiente para preencher a áreana vertical), e BOTH (preenche nos dois sentidos).

weightx, weighty – determina como o espaço excedente é distribuído,definindo o comportamento para o redimensionamento. Ou seja define aproporção do espaço que excedente que será distribuído entre oscomponentes. Se não for especificado para pelo menos uma linha(weightx) e coluna (weighty), todos os componentes serão agrupadosno centro do Container, uma vez que o peso de cada um é zero(default).

gridwidth, gridheight – Especifica o numero de células em um linha(gridwidth) ou coluna (gridheight) ocupadas pela área de exibiçãode um componente. O valor default é 1. Os valores possíveis (definidosna classe GridBagConstraints) são REMAINDER para especificar que ocomponente deve ser o último da linha (para gridwidth) ou coluna(para gridheight). RELATIVE para especificar que o componente deveser o vizinho do último na linha (para gridwidth) ou coluna (paragridheight). Ou valores inteiros especificando o número de linhas ecolunas ocupadas.

Page 191: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

190

A figura XX.XX mostra o resultado da execução do código do exemploXX.XX.

Figura XX.XX – Aparência do Frame com GridBagLayout.

Utilizando Listas

Muitas vezes é necessário que o usuário selecione um item a partir de umalista de itens disponíveis. A AWT torna possível a seleção de um item em umalista de itens por meio do componente Choice. Este componente possui métodospara a adição, remoção e acesso a itens. O exemplo abaixo mostra a alteração doexemplo XX.XX que usa uma lista de escolha para armazenar os comandosanteriores. Desta forma o usuário economiza na digitação de comandosrepetidos.

12345678910111213

import java.io.*;import java.awt.*;import java.awt.event.*;

public class Comando2 extends java.awt.Frame { private TextField tfComando; private TextArea taSaida; private Button btExec; private Panel panel; private Choice ch; private String com;

public Comando2() {

Page 192: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

191

14151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162

com = "command.com /c ";

tfComando = new TextField(50); taSaida = new TextArea(20,60); panel = new Panel(); btExec = new Button("Executa"); ch = new Choice(); ch.setVisible(false);

btExec.setBackground(new Color(0x08FDDF10)); taSaida.setBackground(Color.lightGray); taSaida.setEditable(false);

add(panel,BorderLayout.NORTH); panel.add(tfComando,BorderLayout.NORTH); panel.add(ch,BorderLayout.CENTER); add(btExec,BorderLayout.SOUTH); add(taSaida,BorderLayout.CENTER);

addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } });

btExec.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { btExecActionPerformed(evt); } });

ch.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent evt) { if (evt.getStateChange() == ItemEvent.SELECTED) tfComando.setText(ch.getSelectedItem()); } }); pack(); }

private void btExecActionPerformed(ActionEvent evt) { String s = tfComando.getText(); if (s==null) return; boolean inclui =true; for (int i= ch.getItemCount()-1;i>=0;i--) if (s.equals(ch.getItem(i))) inclui=false; if (inclui) { ch.add(s); ch.setVisible(true);

Page 193: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

192

63646566676869707172737475767778

pack(); } try { Process p = Runtime.getRuntime().exec(com+s); InputStream in = p.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String line; taSaida.setText(""); while ((line = br.readLine()) != null) taSaida.append(line+'\n'); taSaida.append("Fim!"); } catch(Exception e) {taSaida.setText(e.getMessage()); return;} }

public static void main(String args[]) { new Comando2().show(); }}

Exemplo XX.XX – Aplicação para execução de comandos MS-DOS com listade escolha.

Na linha 21 é usado o método setVisible() para que o componenteChoice fique invisível inicialmente. Isto é feito porque no início a lista de itensestá vazia e, portanto, não é preciso exibi-la. Nas linhas 45 a 50 é adicionado umobjeto ItemListener à lista de listener do objeto Choice. Este objeto receberáos eventos de seleção de itens na lista de escolha. Nas linhas 58 a 64 é verificadose o comando digitado já está incluído na lista de itens. Caso não esteja o item éincluído e o método pack() do Frame é chamado, para que a janela se ajuste aotamanho dos componentes.

A figura XX.XX mostra o resultado da execução do código do exemploXX.XX.

Page 194: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

193

Figura XX.XX – Aparência da aplicação para execução de comandos MS-DOScom lista de escolha.

Trabalhando com Menus e Diálogos

Outros componentes importantes para criação de interfaces com o usuáriosão os menus e as caixas de diálogos. De forma a ilustrar o uso desses recursosmodificaremos o exemplo XX.XX para conter uma barra de menus com apenasum menu. O menu conterá dois itens de menu. O acionamento do primeiro itemde menu ocasionará a exibição de um pequeno texto de ajuda no componenteTextArea. O acionamento do segundo item de menu ocasionará a exibição deuma caixa de diálogo contendo informações sobre a aplicação.

123456

import java.io.*;import java.awt.*;import java.awt.event.*;

public class Comando3 extends java.awt.Frame { private TextField tfComando;

Page 195: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

194

78910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

private TextArea taSaida; private Button btExec; private Panel panel; private Choice ch; private String com;

public Comando3() { com = "command.com /c ";

tfComando = new TextField(50); taSaida = new TextArea(20,60); panel = new Panel(); btExec = new Button("Executa"); ch = new Choice(); ch.setVisible(false);

btExec.setBackground(new Color(0x08FDDF10)); taSaida.setBackground(Color.lightGray); taSaida.setEditable(false);

Menu menu = new Menu("Ajuda"); menu.add("Resumo"); menu.addSeparator(); menu.add("Sobre"); MenuBar mb = new MenuBar(); mb.add(menu); setMenuBar(mb);

add(panel,BorderLayout.NORTH); panel.add(tfComando,BorderLayout.NORTH); panel.add(ch,BorderLayout.CENTER); add(btExec,BorderLayout.SOUTH); add(taSaida,BorderLayout.CENTER);

addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } });

btExec.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { btExecActionPerformed(evt); } });

ch.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent evt) { if (evt.getStateChange() == ItemEvent.SELECTED)

Page 196: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

195

5657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104

tfComando.setText(ch.getSelectedItem()); } });

menu.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if (evt.getActionCommand().equals("Sobre")) mostraSobre(); else if (evt.getActionCommand().equals("Resumo")) taSaida.setText("Digite o Comando e pressione “+ ”o botão <executa> para executar."); } }); pack(); }

private void mostraSobre() { Dialog d = new Dialog(this,"Sobre Comando"); d.setModal(true); Label lb1 = new Label("Comando Versão 1.2", Label.CENTER); Label lb2 = new Label("Alcione de Paiva Oliveira", Label.CENTER); lb1.setFont(new Font ("Dialog", Font.BOLD|Font.ITALIC, 18)); lb2.setFont(new Font ("Courier New", 0, 16)); d.add(lb1,BorderLayout.NORTH); d.add(lb2,BorderLayout.SOUTH); d.setBackground(Color.cyan); d.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { evt.getWindow().dispose(); } }); d.pack(); d.show(); }

private void btExecActionPerformed(ActionEvent evt) { String s = tfComando.getText(); if (s==null) return; boolean inclui =true; for (int i= ch.getItemCount()-1;i>=0;i--) if (s.equals(ch.getItem(i))) inclui=false; if (inclui) { ch.add(s); ch.setVisible(true); pack(); } try { Process p = Runtime.getRuntime().exec(com+s); InputStream in = p.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in));

Page 197: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

196

105106107108109110111112113114

String line; taSaida.setText(""); while ((line = br.readLine()) != null) taSaida.append(line+'\n'); taSaida.append("Fim!"); } catch(Exception e) {taSaida.setText(e.getMessage()); return;} }

public static void main(String args[]) { new Comando3().show(); }}

Exemplo XX.XX – Aplicação para execução de comandos MS-DOS com barrade menus e uma caixa de diálogo.

As linhas 27 a 33 contém o código para a inserção da barra de menus e do menu.Na linha 27 é criado um componente Menu com o label “Ajuda”. Nas linhas 28 a30 são adicionados dois itens de menu e um separador ao componente Menu. Naslinha 31 e 32 é criado um componente MenuBar e o componente Menu éadicionado ao MenuBar. Na linha 33 o componente MenuBar é definida como abarra de menu da janela corrente. Nas linhas 60 a 67 é adicionado um objetoActionListener à lista de Listener do objeto Menu. Este objeto receberá oseventos de seleção de itens do menu. Caso o item de menu selecionado seja o“Sobre” então o método mostraSobre() é invocado. Caso o item de menuselecionado seja o “Resumo” então é exibido um texto de ajuda no componenteTextArea. As linhas 71 a 88 contém o código do método mostraSobre(). Estemétodo é responsável pela montagem e exibição da caixa de diálogo cominformações sobre a aplicação. Na linha 72 é criada uma instância da classeDialog. O construtor desta classe exige que seja passado como parâmetro umobjeto da classe Frame ou Dialog para deter a posse do objeto a ser criado.Quando o objeto possuidor é tornado invisível ou minimizado a janela Dialog éautomaticamente tornada invisível ou minimizada. No caso do exemplo o Framecorrente é passado como parâmetro. Na linha 73 é invocado o métodosetModal() para torna a o diálogo modal. O diálogo modal bloqueia todaentrada em todas as janelas no contexto da aplicação, exceto pelas janelascriadas tendo o diálogo como possuidor.

A figura XX.XX mostra o resultado da execução do código do exemploXX.XX.

Page 198: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

197

Figura XX.XX – Aparência da aplicação para execução de comandos MS-DOScom barra de menus.

Capturando Eventos do Teclado

Principais Classes

Color

Esta classe encapsula a criação de cores por meio dos níveis RGB. Elamantém também um conjunto de atributos constantes com valores de corespredefinidos.

Page 199: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

198

Hierarquia

java.lang.Object | +--java.awt.Color

Atributos públicos

Atributo DescriçãoColor black A cor preta.Color blue A cor azul.Color cyan A cor azul claro.Color darkGray A cor cinza escuro.Color gray A cor cinza.Color green A cor verde.Color lightGray A cor cinza claro.Color magenta A cor violeta.Color orange A cor laranja.Color pink A cor rosa.Color red A cor vermelha.Color white A cor branca.Color yellow A cor amarela.

Construtores

Construtor DescriçãoColor(float r, float g, float b)

Cria uma cor opaca RGB com os valores red, green, eblue especificados dentro da faixa (0.0 - 1.0).

Color(int rgb) Cria uma cor opaca com os valores RGB combinados noparâmetro rgb. O componente red está definido nosbits 16-23, o componente green está definido nos bits 8-15, e o componente blue está definido nos bits 0-7.

Color(int r, int g, int b)

Cria uma cor opaca RGB com os valores red, green, eblue especificados dentro da faixa (0 - 255).

Métodos mais usados

Método DescriçãoColor brighter() Cria uma versão mais clara da cor corrente.Color darker() Cria uma versão mais escura da cor corrente.Color decode(String nm) Converte a String em um inteiro e retorna a cor

Page 200: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

199

opaca relacionada.equals(Object obj) Verifica se o objeto é igual a essa cor.int getBlue() Retorna o componente azul da cor.int getGreen() Retorna o componente verde da cor.int getRed() Retorna o componente vermelho da cor.int getTransparency() Retorna o modo de transparência desta cor.String toString() Retorna a representação em String desta cor.

Exemplo

Color c = new Color(0xFFC0C0C0);

Component

Um componente é um objeto que possui uma representação gráfica quepode ser exibida em uma tela e pode interagir com o usuário.

Hierarquia

java.lang.Object | +--java.awt.Component

Atributos públicos

Atributo Descriçãofloat BOTTOM_ALIGNMENT Alinhamento na parte inferior.float CENTER_ALIGNMENT Alinhamento ao centro.loat LEFT_ALIGNMENT Alinhamento à esquerda.float RIGHT_ALIGNMENT Alinhamento à esquerda.float TOP_ALIGNMENT Alinhamento na parte superior.

Construtor

Construtor DescriçãoComponent() Constrói um novo Component.

Page 201: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

200

Métodos mais usados

Método Descriçãovoid add(PopupMenu popup) Adiciona um menu do tipo PopupMenu ao

componente.void addComponentListener( ComponentListener l)

Adiciona o ComponentListener parareceber eventos sobre o componente.

boolean contains(int x, int y)

Verifica se o componente possui a coordenada.

float getAlignmentX() Retorna o alinhamento no eixo x.float getAlignmentY() Retorna o alinhamento no eixo y.Color getBackground() Retorna a cor de fundo do componente.Rectangle getBounds() Retorna as dimensões do componente.Component getComponentAt( int x, int y)

Retorna o componente do Component quecontém a coordenada especificada. Apenas oprimeiro nível de descendência é examinado.

Cursor getCursor() Retorna o cursor deste componente.Font getFont() Retorna o fonte deste componente.Color getForeground() Retorna a cor de frente deste componente.Graphics getGraphics() Cria um contexto gráfico para este

componente.int getHeight() Retorna a altura deste componente.Point getLocation() Retorna a localização deste componente.String getName() Retorna o nome deste componente.Container getParent() Retorna o Container onde está inserido este

componente.Dimension getSize() Retorna as dimensões deste componente.Toolkit getToolkit() Retorna o Toolkit deste componente.int getWidth() Retorna a largura deste componente.int getX() Retorna a coordenada X deste componente.int getY() Retorna a coordenada Y deste componente.boolean isDisplayable() Verifica se este componente pode se exibido.boolean isEnabled() Verifica se este componente está habilitado.boolean isFocusOwner() Verifica se este componente possui o foco.boolean isVisible() Verifica se este componente esta visível.void list(PrintStream out) Lista este componente no PrintStream.void paint(Graphics g) Pinta o este Container. Este método deve

ser sobrescrito se o programador desejadesenhar no Container. Neste casosuper.paint(g) deve ser invocado.

void processEvent(AWTEvent e) Processa os eventos ocorrendo nestecomponente.

void remove(MenuComponentpopup)

Remove o menu popup menu destecomponente.

void setBounds(int x, int y, int width,

Define os limites deste componente.

Page 202: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

201 int height)void setEnabled(boolean b) Define este componente como habilitado.void setFont(Font f) Define o fonte deste Component.void void setName(String name) Define o nome deste componente.void setSize(int width, int height)

Define o tamanho deste componente.

void setVisible(boolean b) Define este componente como visível.String toString() Retorna a representação em String deste

componente.

Exemplo

Component c= new Component();

Button

Os objetos da classe Button são objetos gráficos que simulam botões egeram eventos quando são pressionados.

Hierarquia

java.lang.Object | +--java.awt.Component | +--java.awt.Button

Construtores

Construtor DescriçãoButton() Constrói um botão sem texto.Button(String lbl) Constrói um botão com um texto.

Métodos mais usados

Método DescriçãoString getLabel() Retorna o texto apresentado no botão.void setLabel(String lbl) Define o texto apresentado no botão como o

referenciado por lbl.

Page 203: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

202

Exemplo

Button b= new Button(“ok”);

Label

Os objetos da classe Label servem para exibir textos que não serãoeditados pelo usuário.

Hierarquia

java.lang.Object | +--java.awt.Component | +--java.awt.Label

Construtores

Construtor DescriçãoLabel() Constrói um Label sem texto.Label(String lbl) Constrói um Label com um texto.Label(String lbl, int alin)

Constrói um Label com um texto e com o alinhamentoespecificado por alin. Os valores possíveis para oalinhamento são Label.LEFT, Label.RIGHT, eLabel.CENTER.

Métodos mais usados

Método DescriçãoString getText() Retorna o texto apresentado no Label.void setText(String lbl) Define o texto apresentado no Label como o

referenciado por lbl.int getAlignment() Retorna o alinhamento.void setAlignment(int alin) Estabelece o novo alinhamento, especificado

por alin. Os valores possíveis para o

Page 204: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

203

alinhamento são Label.LEFT,Label.RIGHT, e Label.CENTER.

List

O componente List permite que o programador crie uma lista deelementos passíveis de rolamento. Dependendo de como a lista foi definida ousuário pode selecionar um item ou múltiplo itens.

Hierarquia

java.lang.Object | +--java.awt.Component | +--java.awt.List

Construtores

Construtor DescriçãoList() Constrói uma nova lista rolável.List(int linhas) Constrói uma nova lista rolável com o número de linhas

visíveis igual a linhas.List(int linhas,boolean sm)

Constrói uma nova lista rolável com o número de linhasvisíveis igual a linhas e o parâmetro sm indicando seé para permitir seleções múltiplas.

Métodos mais usados

Método Descriçãovoid add(String item) Adiciona o item referenciado por item no

final da lista.void add(String item, int ind)

Adiciona o item referenciado por item naposição indicada por ind. A base é 0. Se ovalor de ind for menor que 0 ou maior que onúmero de elementos, o item será inserido nofinal da lista.

Page 205: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

204void deselect(int ind) remove a seleção do item no índice

especificado.String getItem(int ind) Obtém o item no índice especificado.int getItemCount() Obtém o número de itens na lista.String[] getItems() Obtém todos os itens da lista.int getRows() Obtém o número de linhas visíveis da lista.int getSelectedIndex() Obtém o índice do elemento selecionado.

Retorna -1 se nenhum elemento ou mais de umelemento estiver selecionado.

int[] getSelectedIndexes() Retorna todos os itens selecionados.String getSelectedItem() Obtém o elemento selecionado.String[] getSelectedItems() Obtém todos os elementos selecionados.boolean isMultipleMode() Indica se o modo de seleção é múltiplo.void makeVisible(int ind) Torna visível o elemento no índice

especificado.void remove(int ind) Remove o elemento no índice especificado.void removeAll() Remove todos os elementos na lista.void select(int ind) Seleciona o elemento no índice.

Exemplo

List lista = new List(3);lista.add("Laranja");lista.add("Abacate");lista.add("Pera");lista.add("Uva");

TextField

O componente TextField é usado para implementar entrada e ediçãode uma linha de texto.

Hierarquia

java.lang.Object | +--java.awt.Component | +--java.awt.TextComponent | +--java.awt.TextField

Page 206: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

205

Construtores

Construtor DescriçãoTextField() Constrói um novo TextField.TextField(int cols) Constrói um novo TextField com o número de

colunas especificado.TextField(String txt) Constrói um novo TextField exibindo o texto

especificado.TextField(Stringtxt,int cols)

Constrói um novo TextField com o número decolunas e o texto especificados.

Métodos mais usados

Método Descriçãoint getColumns() Retorna o número de colunas.String getText() Retorna o texto exibido no componente.void setColumns(int cols) Define o número de colunas.void setText(String txt) Define o número o texto a ser editado.

Exemplo

TextField tf;

tf = new TextField("Ola mundo!";

TextArea

O componente TextArea é usado para implementar entrada e ediçãode texto com múltiplas linhas.

Hierarquia

java.lang.Object | +--java.awt.Component |

Page 207: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

206

+--java.awt.TextComponent | +--java.awt.TextArea

Construtores

Construtor DescriçãoTextArea() Constrói um novo TextArea.TextArea(int lin, int cols)

Constrói um novo TextArea com o número de linhase colunas especificados.

TextArea(String txt) Constrói um novo TextArea exibindo o textoespecificado.

TextArea(String txt,intcols)

Constrói um novo TextArea com o número de linhas,colunas e o texto especificados.

Métodos mais usados

Método Descriçãoint getColumns() Retorna o número de colunas.int getRows() Retorna o número de linhas.String getText() Retorna o texto exibido no componente.void setColumns(int cols) Define o número de colunas.void setRows(int lin) Define o número de linhas.void setText(String txt) Define o número o texto a ser editado.

Exemplo

new TextArea("Ola mundo!", 3, 20);

Containers

Containers são componentes usados para conter outros componentes. Umobjeto da classe Container pode conter inclusive outros containers,permitindo assim a construção de interfaces complexas.

Hierarquia

Page 208: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

207

java.lang.Object | +--java.awt.Component | +--java.awt.Container

Construtor

Construtor DescriçãoContainer() Constrói um novo Container.

Métodos mais usados

Método DescriçãoComponent add( Component comp)

Adiciona o componente no final da lista decomponentes deste Container.

Component add( Component comp, int ind)

Adiciona o componente na posição ind dalista de componentes deste Container.

Component findComponentAt( int x, int y)

Retorna o componente visível do Containerque contém a coordenada especificada. Todosos descendentes são examinados (SDK 1.2).

float getAlignmentX() Retorna o alinhamento no eixo x.float getAlignmentY() Retorna o alinhamento no eixo y.Component getComponent( int n)

Retorna o componente na posição n na lista decomponentes deste Container.

Component getComponentAt( int x, int y)

Retorna o componente do Container quecontém a coordenada especificada. Apenas oprimeiro nível de descendência é examinado.

int getComponentCount() Retorna o número de componentes desteContainer.

Component[] getComponents() Retorna todos os componentes desteContainer.

Insets getInsets() Retorna o Insets deste Container.Insets indicam o tamanho da borda doContainer.

LayoutManager getLayout() Retorna o Layout deste Container.booleanisAncestorOf(Component c)

Indica se o componente está contido nesteContainer.

void list(PrintStream out, int indent)

Imprime uma lista com o conteúdo desteContainer.

void paint(Graphics g) Pinta o este Container. Este método deveser sobrescrito se o programador deseja

Page 209: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

208

desenhar no Container. Neste casosuper.paint(g) deve ser invocado.

void remove(Component comp) Remove o componente deste Container.void remove(int index) Remove o componente com o índice

especificado deste Container.void removeAll() Remove todos os componentes deste

Container.void setFont(Font f) Define o fonte deste Container.void setLayout(LayoutManagermgr)

Define o layout deste Container.

Panel

Esta classe é o Container mais simples. O Panel fornece um espaçoonde podem ser colocados outros componentes, inclusive outros objetos do tipoPanel.

Hierarquia

java.lang.Object | +--java.awt.Component | +--java.awt.Container | +--java.awt.Panel

Construtor

Construtor DescriçãoPanel() Constrói um novo Panel.Panel(LayoutManager layout) Constrói um novo Panel usando o LayoutManager

especificado.

Método

Método Descriçãovoid addNotify() Cria um par (peer) para o Panel. O par permite modificar o

Page 210: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

209

Panel sem alterar a sua aparência.

Exemplo

Ver exemplo VI.XX.

Frame

Um Frame é uma janela com título e borda. A área do Frame inclui aárea destinada para a borda. As dimensões da borda pode ser obtida por meio dométodo getInsets().

Hierarquia

java.lang.Object | +--java.awt.Component | +--java.awt.Container | +--java.awt.Window | +--java.awt.Frame

Construtores

Construtor DescriçãoFrame() Constrói um novo Frame.Frame(String title) Constrói um novo Frame com o título especificado.

Métodos mais usados

Método Descriçãostatic Frame[] getFrames() Retorna todos os frames criados pela aplicação.Image getIconImage() Retorna a imagem usada pelo Frame quando

Page 211: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

210

minimizado.MenuBar getMenuBar() Retorna a barra de menu deste Frame.int getState() Retorna o estado deste Frame.String getTitle() Retorna o título deste Frame.boolean isResizable() Indica se o tamanho deste Frame pode ser

mudado.void setIconImage(Image im) Define a imagem a ser usada como ícone para

este Frame.void setMenuBar(MenuBar mb) Define o menu a ser usada como ícone para

este Frame.void setResizable(boolean r) Define se o tamanho deste Frame pode ser

mudado.void setState(int state) Define o estado deste Frame.void setTitle(String title) Define o título deste Frame.

Exemplo

Ver exemplo VI.XX.

###Exemplo

import java.awt.*;import java.awt.event.*;

class testeFrame3 extends FrameX { Button b; class SymMouse extends MouseAdapter {

public void mouseClicked(MouseEvent event){ Object object = event.getSource(); if (object == b) b.setLabel("Clik");}

} public testeFrame3 (String Titulo) {

super(Titulo);b = new Button("ola");b.addMouseListener(new SymMouse());this.add(b);setSize(100,80);

} public static void main(String args[])

Page 212: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

211 { testeFrame3 t = new testeFrame3("Teste 3"); t.show(); }}

public class testeFrame4 extends FrameX {public testeFrame4(String titulo) {

super(titulo);setLayout(new GridLayout(1,2));textField1 = new TextField(20);add(textField1);button1 = new Button("Duplica");add(button1);button1.addMouseListener(new SymMouse());

}

public synchronized void show() {move(50, 50);setSize(200,50);super.show();

}

TextField textField1;Button button1;

class SymMouse extends java.awt.event.MouseAdapter { public void mouseClicked(java.awt.event.MouseEvent

event){ Object object = event.getSource(); if (object == button1) { int i = Integer.parseInt(textField1.getText());

textField1.setText(""+i*2); } }}

public static void main(String args[]){ new testeFrame4("Teste 4").show(); }}

public class testeFrame5 extends FrameX { public testeFrame5(String titulo) { super(titulo); setSize(220,70); setLayout(null); textField1 = new TextField();

Page 213: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

212 textField1.setBounds(10,30,100,25); add(textField1); button1 = new Button("Duplica"); button1.setBounds(110,30,100,25); button1.addMouseListener(new SymMouse()); add(button1); }

public class testeFrame6 extends FrameX {public testeFrame6(String titulo) {

super(titulo);setSize(200,250);move(50, 50);

theImage = tk.getImage("skisor.gif");}

private static Toolkit tk = Toolkit.getDefaultToolkit(); private Image theImage;

public void paint(Graphics g) { g.drawImage(theImage, 20, 20, getSize().width-20, getSize().height-20, this); } public static void main(String args[]){ new testeFrame6("Teste 6").show(); }}

O objeto Toolkit oferece recursos para carregar imagens da formacorreta para cada plataforma. O método paint() é responsável por desenhar afigura. Ele é chamado toda vez que ocorre um evento sobre o componente, demodo que a figura será sempre redesenhada.

Agenda Eletrônica versão Gráfica 1.0

/**AgendaIntInterface Gráfica da agenda.

*/

import java.awt.*;import java.awt.event.*;import java.io.*;import java.util.*;

Page 214: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

213public class AgendaInt extends FrameX{

Agenda ag;

TextArea textArea1 = new TextArea();TextField txtNome = new TextField();TextField txtEnd = new TextField();TextField txtTel = new TextField();Button btCarregar = new Button();Button btGravar = new Button();Button brInserir = new Button();Button btListar = new Button();Button btConsultar = new Button();Label label1 = new Label();Label lbStatus = new Label();Label label2 = new Label();Label label3 = new Label();

public AgendaInt(){

ag = new Agenda();

setLayout(null);setBackground(new Color(112,170,192));setSize(400,320);setVisible(false);add(textArea1);textArea1.setBackground(Color.white);textArea1.setBounds(12,120,372,168);btCarregar.setLabel("Carregar");add(btCarregar);btCarregar.setBackground(Color.lightGray);btCarregar.setBounds(12,12,72,24);btGravar.setLabel("Gravar");add(btGravar);btGravar.setBackground(Color.lightGray);btGravar.setBounds(84,12,72,24);brInserir.setLabel("Inserir");add(brInserir);brInserir.setBackground(Color.lightGray);brInserir.setBounds(156,12,72,24);btListar.setLabel("Listar");add(btListar);btListar.setBackground(Color.lightGray);btListar.setBounds(228,12,84,24);btConsultar.setLabel("Consultar");add(btConsultar);btConsultar.setBackground(Color.lightGray);btConsultar.setBounds(312,12,72,24);

Page 215: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

214add(txtNome);txtNome.setBackground(Color.white);txtNome.setBounds(60,48,144,24);label1.setText("Nome:");add(label1);label1.setFont(new Font("Serif", Font.BOLD, 12));label1.setBounds(12,48,48,24);add(lbStatus);lbStatus.setBackground(Color.lightGray);lbStatus.setForeground(Color.red);lbStatus.setBounds(0,300,396,16);label2.setText("Telefone:");add(label2);label2.setFont(new Font("Serif", Font.BOLD, 12));label2.setBounds(216,48,60,24);add(txtTel);txtTel.setBackground(Color.white);txtTel.setBounds(276,48,108,24);label3.setText("Endereço:");add(label3);label3.setFont(new Font("Serif", Font.BOLD, 12));label3.setBounds(12,84,48,24);add(txtEnd);txtEnd.setBackground(Color.white);txtEnd.setBounds(72,84,312,24);setTitle("Agenda Eletônica");

// REGISTRA OS LISTENERSSymWindow aSymWindow = new SymWindow();this.addWindowListener(aSymWindow);SymMouse aSymMouse = new SymMouse();btGravar.addMouseListener(aSymMouse);btCarregar.addMouseListener(aSymMouse);btListar.addMouseListener(aSymMouse);brInserir.addMouseListener(aSymMouse);btConsultar.addMouseListener(aSymMouse);

}

public AgendaInt(String title){

this();setTitle(title);

}

class SymWindow extends WindowAdapter{

public void windowClosing(WindowEvent event){

Object object = event.getSource();

Page 216: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

215if (object == AgendaInt.this)

AgendaIntAwt_WindowClosing(event);}

}

void AgendaIntAwt_WindowClosing(WindowEvent event){

setVisible(false);}

class SymMouse extends MouseAdapter{

public void mouseClicked(MouseEvent event){

Object object = event.getSource();if (object == btGravar)

btGravar_MouseClicked(event);else if (object == btCarregar)

btCarregar_MouseClicked(event);else if (object == btListar)

btListar_MouseClicked(event);else if (object == btConsultar)

btConsultar_MouseClicked(event);else if (object == brInserir)

brInserir_MouseClicked(event);}

}

void btGravar_MouseClicked(MouseEvent event){

gravar();

}

void btCarregar_MouseClicked(MouseEvent event){

carregar();}

void btListar_MouseClicked(MouseEvent event){

Exibirlista();}

void btConsultar_MouseClicked(MouseEvent event){

String nome = txtNome.getText(); if (nome.length()>0) exibirPessoa(nome);

Page 217: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

216 else lbStatus.setText("É necessário preencher o campo

Nome!");}

void brInserir_MouseClicked(MouseEvent event){

String nome = txtNome.getText(); String tel = txtTel.getText(); String end = txtEnd.getText();

if (nome.length()>0) ag.inserir(new Pessoa(nome,tel,end));

else lbStatus.setText("É necessário preencher o campoNome!");

}

/**gravar

*/public void gravar(){ ObjectOutputStream fout;

try {fout = new ObjectOutputStream( new FileOutputStream("agenda.dat"));fout.writeObject(ag);fout.close();

} catch(FileNotFoundException e) { System.out.println("Arq. Não encontrado");}

catch(IOException e){System.out.println("Erro nagravação!");}

}/**

carregar*/public void carregar(){ ObjectInputStream fin; try {

fin = new ObjectInputStream( new FileInputStream("agenda.dat"));ag = (Agenda) fin.readObject();fin.close();

} catch(FileNotFoundException e) { System.out.println("Arq. Não encontrado");} catch(Exception e) {System.out.println("Erro naleitura!");}

}

Page 218: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

217

/**Exibirlista

*/public void Exibirlista(){ Pessoa p; textArea1.setText(""); for (Enumeration e = ag.getPessoas();

e.hasMoreElements();) {

p = (Pessoa) e.nextElement();textArea1.append("\nNome:"+p.getNome()+"\nTelefone:" +p.getTel()+"\nEndereço:"+p.getEnd()+"\n");

} }

// mainpublic static void main(String args[]){ (new AgendaIntAwt("Agenda")).setVisible(true);}

/**exibirPessoa

*/public void exibirPessoa(String nome){ Pessoa p = ag.getPessoa(nome); if (p!=null) {

txtTel.setText(p.getTel()); txtEnd.setText(p.getEnd());

} else textArea1.setText("Pessoa não cadastrada!");

}}

Exercícios

Faça um programa para converter Graus Celcius em Farenheit

Page 219: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

218

Capítulo IX - AppletsApplets são aplicações Java projetadas para serem executadas por

navegadores da World Wide Web (WWW). Isto é feito através de chamadasespeciais dentro do código HTML (Hyper Text Markup Language) das páginas.A possibilidade de desenvolver páginas HTML com a capacidade de invocarprogramas em Java foi uma das razões para o sucesso inicial, inédito em termosde linguagem de programação, de Java. Até então, as páginas HTML erambasicamente objetos passivos, com capacidade limitada de interação, a não serpor meio de CGI (Common Gateway Interface), que implementa a interatividadecom o uso de códigos executáveis (geralmente escritos em Perl) rodados noservidor. Esse tipo de arquitetura onera muito o servidor uma vez qualquerprocessamento tem que ser efetuado nele.

Figura VII.1 – Interação via CGI.

A idéia do uso de Java é enviar código para o lado cliente através darede, para que parte do processamento seja realizado no próprio cliente,liberando o servidor para tarefas mais importantes. Claro que isto será razoávelse o código puder trafegar pela rede rapidamente. Os programas em Bytecodesocupam pouco espaço e podem ser compactados antes de serem enviados pelarede, o que reduz bastante o tempo de transmissão.

Cliente com browserServidor

Requisição de página Web

Página Web construídapelo programa CGI

O servidor Webexecuta o programaCGI que constrói apágina Web.

800

APO

Page 220: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

219

Figura VII.2 – Interação via Java.

No entanto, é preciso ter cuidado quando se trata de enviar código pelarede para se executado em uma máquina cliente. Existe um grande potencialpara o desenvolvimento acidental ou proposital de programas que podem atuarnocivamente nas máquinas clientes, seja pela leitura de dados privados, seja pordestruição não autorizada de informações e programas. Preocupados com o isso,os projetistas da linguagem Java determinaram que, no caso de Applets, amáquina virtual impede que o programa tenha acesso limitado aos recursos damáquina. Nessa forma de execução o programa é dito estar sendo executadodentro de uma “caixa de areia” (Sand Box). Esta solução é em alguns casos pordemais restritiva e tem sido relaxada nas últimas versões de Java para permitir oacesso aos recursos das máquinas clientes a Applets digitalmente assinados,denominados de Trusted (confiáveis).

Outro benefício do uso de Java é possibilidade da produção de páginaspara a WWW com animação. Inicialmente, as páginas em HTML não possuíamrecurso para animação, a não ser por meio de GIFs animadas. Com Java épossível desenvolver animações bem mais sofisticadas.

Para desenvolver um Applet é preciso criar uma subclasse da classe classejava.applet.Applet. Abaixo é mostrada forma geral de um código queimplementa um Applet:

import java.awt.*;import java.applet.Applet;

Cliente com browserServidor

Requisição de página Web

Página Web e bytecodes

O servidor Webenvia páginaWeb e códigoem bytecodes

Executa ocódigo embytecodes

800

APO

Page 221: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

220

public class indentificador extends Applet{

corpo do applet}

A figura VII.3 mostra a hierarquia de classes para a classe Applet.

Figura VII.3 – Hierarquia de classes.

O exemplo VII.1 mostra o código de um Applet que exibe o texto “olamundo!” quando executado.

import java.awt.*;import java.applet.*;

public class Applet1 extends Applet{

Label label1 = new Label();

public void init(){

setLayout(null);setSize(150,87);label1.setText("Ola Mundo!");add(label1);label1.setBounds(24,12,84,48);

java.awt.Component

java.lang.Object

java.awt.Container

java.awt.Panel

java.applet.Applet

Page 222: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

221}

}

Exemplo VII.1 – Applet simples.

O leitor pode observar algumas diferenças do código do exemplo VII.1para o código do exemplo III.1 que implementava um programa que exibia “olaMundo” na console. A primeira diferença é que não existe um método main().Isto ocorre porque os Applets foram projetados para serem executados por outraaplicação: um navegador Web. A aplicação é responsável por criar umainstância da subclasse da classe Applet e chamar os métodos de acordo com anecessidade. No exemplo acima será executado o método init(), que é oprimeiro método executado em um Applet e é executado apenas uma vez.

Para executarmos o Applet, além de ser necessário compilá-lo, é precisocriar um arquivo com código HTML com um link para o código em bytecode.Isto é necessário já que o Applet vai ser executado por um navegador. Oexemplo VII.2 mostra o código HTML que possui um link para a classe Applet1.O link para o código em bytecodes pode possuir vários parâmetros. No exemploVII.2 são mostrados apenas os parâmetros que indicam a largura e altura que oApplet ocupará na página. Os outros parâmetros serão abordados mais adiante.

<html><applet code=Applet1.class

width=400 height=300>

</applet></html>

Exemplo VII.2 – HTML simples.

Para executar o código basta direcionar o navegador para o HTML doexemplo VII.2. O SDK possui também uma aplicação capaz de executarApplets. É o appletviewer. A linha de comando abaixo mostra comoexecutar o Applet por meio do appletviewer. Note que é preciso passar onome do arquivo HTML como parâmetro:

appletviewer applet1.html

Page 223: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

222

A figura VII.4 mostra o resultado da execução do Applet1 por meio doappletviewer.

Figura VII.4 – Execução do Applet1.

Descrição do código HTML

Não entraremos em detalhes da codificação em HTML. Abordaremosaqui apenas os parâmetros relacionados com o link para o código em bytecode.A forma geral de um link deste tipo é mostrada abaixo.

<html><applet..code= ... width=... height=... archive=... codebase=... align=... alt=... name=... hspace=... vspace=... mayscript=... ><param name=“...” value=“...”>...<param name=“...” value=“...”></applet></html>

O link HTML possui vários parâmetros, sendo a maioria deles opcionais.A tabela abaixo descreve cada um dos parâmetros.

Parâmetro Descrição

Page 224: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

223code Nome da classe em bytecode. Por exemplo: Applet1.class.width Largura que o Applet vai ocupar na página HTML.height Altura que o Applet vai ocupar na página HTML.archive Opcional. Se a classe estiver armazenada em um arquivo JAR (Java

Archive), então este parâmetro indica o nome do arquivo. Porexemplo: minhasclasses.jar.

codebase Opcional. URL onde está localizada o Applet.align Alinhamento do Applet na página. (left, right, top,

texttop, middle, absmiddle, baseline, bottom eabsbottom).

alt Mensagem alternativa caso o navegador não seja capaz de executarbytecodes.

name Nome do Applet. Pode ser usado por outros Applets na mesmapágina para comunicação.

hspace Define o número de pixels livres nos lados direito e esquerdo doApplet.

vspace Define o número de pixels livres acima e abaixo do Applet.mayscript Valor booleano que indica se um Applet pode interagir com código

Javascript.param Opcional. É usado para passar parâmetros para o Applet. Cada

entrada param possui dois subparâmetros, name e value,indicando o nome do parâmetro e o valor respectivamente. Maisadiante será mostrado como o código Java recebe esses parâmetros.

Tabela VII.1 – Parâmetros do link para o código em bytecodes.

Métodos da Classe Applet

A classe Applet define um número razoável de métodos. No entanto, namaioria das aplicações, o programador sobrescreverá um pequeno subconjuntodeste métodos. A tabela VII.2 descreve os métodos mais utilizados naimplementação de Applets.

Método Descriçãoinit É o primeiro método executado e é executado apenas uma vez. É utilizado

para as inicializações do Applet.start É executado toda vez que o Applet aparece no navegador. É utilizado para

iniciar a operação normal do Applet.stop É executado toda vez que o Applet passa a não ser exibido pelo navegador.

É usado para terminar operações caras em termos computacionais.destroy É executado quando o navegador não precisa mais do Applet. É usado para

liberar recursos.paint É executado toda vez que o Applet aparece no navegador. Recebe uma

Page 225: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

224

instância da classe Graphics. O usuário pode solicitar a sua invocação pormeio de uma chamada ao método repaint(). Neste caso o métodopaint() não será chamado imediatamente, e sim escalado para serexecutado em um tempo menor do que 100msec.

Tabela VII.2 –Principais métodos da classe Applet.

Esses métodos são invocados pelo navegador conforme as situações descritasacima. A motivação por trás dos métodos start() e stop() é que não fazsentido desperdiçar ciclos de processador com um Applet que não está sendovisto.

O método que talvez possa causar mais dúvidas quanto a sua utilidade é ométodo paint(). O método paint() é na verdade um método herdado daclasse container e é utilizado para desenhar em um objeto. O objeto da classeGraphics, recebido pelo método, representa a superfície onde podem serfeitos os desenhos e possui um conjunto de métodos para desenhar. Para ilustraro uso do paint() o exemplo VII.3 mostra o código de um Applet que desenhaum quadrado na tela que segue o mouse.

import java.awt.*;import java.applet.*;import java.awt.event.*;

public class Applet2 extends Applet { int x=0, y=0; public void init(){ setLayout(null); setSize(426,266); this.addMouseMotionListener(new SymMouseMotion()); }

public void paint(Graphics g) { if (x>0)g.drawRect(x, y, 30, 30); }

class SymMouseMotion extends MouseMotionAdapter{ public void mouseMoved(MouseEvent event){ if (event.getSource()== Applet2.this) { x = event.getX();

y = event.getY();repaint();

} }

Page 226: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

225 }}

Exemplo VII.3 – Applet que desenha um quadrado que acompanha o mouse.

Note que o método paint() não é chamado diretamente pelo métodomouseMoved(). O que ocorre é que o método repaint() solicita amáquina virtual para chamar o método update() que por sua vez chama ométodo paint(). A máquina virtual não executa imediatamente o métodoupdate(). Ela escala o método update() para ser executado em pelo menos100 milisegundos. Se antes deste período ocorrer outra solicitação ela seráignorada. O diagrama da figura VII.5 ilustra o ciclo repaint-update-paint.

Figura VII.5 – Ciclo repaint-update-paint.

Ao executar o Applet do exemplo VII.3 o leitor notará que apenas umquadrado permanece desenhado, apesar de existir código apenas para desenhar enenhum para apagar. A pergunta é: o que ocorre com os quadrados desenhadosanteriormente? Acontece que o método update() sempre apaga os desenhosque feitos anteriormente desenhando um retângulo com o tamanho da área dedesenho preenchido com a cor de fundo. É possível sobrescrever o métodoupdate() para alterar esse comportamento, como veremos no capítulo sobreanimação, no entanto é necessário sempre repintar todos os desenhos queprecisam permanecer a cada ciclo, até por que eles podem ser afetados pelamovimentação ou encobrimento da área de desenho. No exemplo VII.3utilizamos um método do objeto da classe Graphics para desenhar um quadrado.Essa classe possui vários métodos semelhantes para desenho de figuras e texto.A tabela VII.3 descreve alguns métodos desta classe.

Método DescriçãodrawArc desenha um arco elíptico.drawChars desenha o texto especificado por um array de bytesdrawline desenha uma linha entre dois pontos.drawRect desenha um retângulo.drawRoundRect desenha um retângulo com bordas arredondadas.drawImage desenha um imagem

repaint() update(Graphics g)

escala (dentro de 100 ms)

paint(Graphics g)Chama

Page 227: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

226draw3Drect desenha um retângulo 3D.drawOval desenha um oval.drawPolygon desenha um polígono usando um vetor de pontos.drawString desenha um string.fillRect desenha um retângulo preenchido.fillRoundRect desenha um retângulo com bordas arredondadas preenchido.fill3Drect desenha um retângulo 3D preenchido.fillOval desenha um oval preenchido.fillPolygon desenha um polígono usando um vetor de pontos preenchido.getColor obtém a cor corrente.setColor define a cor corrente.getFont obtém a fonte corrente.setFont define a fonte corrente.

Tabela VII.3 –Principais métodos da classe Graphics.

O exemplo VII.4 mostra os uso de alguns métodos da classe Graphics. Oprograma, ao ser executado, mostra uma figura com um texto ao usuário e cadavez que o usuário pressiona o mouse a figura muda.

import java.awt.*;import java.awt.event.*;import java.applet.*;

public class Applet3 extends Applet{ private int i =0; private static final int x[] = {10,100,105,80,20}; private static final int y[] = {10,15,70,40,65};

public void init() {

setLayout(null);setSize(200,150);this.addMouseListener(new SymMouse());

}

public void paint(Graphics g) {

switch(i){

case 0: g.setColor(Color.green);g.fillRect(10,10,100,100);g.setColor(Color.black);g.drawString("Quadrado",30,50);break;

case 1: g.setColor(Color.red);

Page 228: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

227g.fillOval(10,10,100,70);g.setColor(Color.black);g.drawString("Oval",50,50);break;

case 2: g.setColor(Color.blue);g.fillPolygon(x,y,5);g.setColor(Color.black);g.drawString("Poligono",40,30);break;

}i = (i+1)%3;

}

class SymMouse extends MouseAdapter {

public void mouseClicked(MouseEvent event){

if (event.getSource()== Applet3.this) repaint();}

}}

Exemplo VII.4 – Applet que desenha várias figuras na tela.

Exibindo uma imagem

Um dos métodos mais interessantes desta classe Graphics é o métododrawImage(), que permite exibir uma imagem. O exemplo VII.5 contém ocódigo de um applet que mostra uma imagem que muda quando o mouse épressionado. A imagem é carregada no exemplo está codificada no formato jpeg.Os tipos de imagens suportadas dependem do navegador sendo utilizado. Afigura VII.6 mostra o resultado da execução do Applet.

import java.awt.*;import java.awt.event.*;import java.applet.*;

public class Applet4 extends Applet{ Image img[]; private static int i=0;

public void init() {

img = new Image[2];

Page 229: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

228img[0] = getImage(getDocumentBase(),"baleia1.jpg");img[1] = getImage(getDocumentBase(),"baleia2.jpg");this.addMouseListener(new SymMouse());

}

public void paint(Graphics g) {

g.drawImage(img[i],0,0,this);i=i==0?1:0;

} class SymMouse extends MouseAdapter {

public void mouseClicked(MouseEvent event){

if (event.getSource() == Applet4.this) repaint();}

}}

Exemplo VII.5 – Applet que exibe imagens.

Primeiramente foi necessário obter objetos to tipo Image. Para issoutilizamos o método getImage() que possui dois parâmetros. O primeiro éuma URL que indica a localização do arquivo contendo a figura e o segundo é onome do arquivo da figura, que pode conter informação de diretório relativo àURL. Se o arquivo estiver no mesmo diretório de onde foi carregado o arquivoHTML então basta usar a método getDocumentBase(), como no exemploVII.5. Se o Se o arquivo estiver no mesmo diretório de onde foi carregado oApplet então basta usar o método getCodeBase().

Figura VII.6 – Saídas do Applet4.

Page 230: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

229

O método getImage() retorna null se o arquivo não foi encontrado,caso contrário um objeto do tipo Image é retornado. A carga de uma imagempode ser muito demorada, dependendo do tamanho é formato dearmazenamento, principalmente em se tratando de imagens transmitidas atravésde uma rede com alto trafego de dados. Além disso, no caso de Applets, ousuário pode mudar de página antes mesmo de uma imagem ser completamenteexibida. Por essas razões, o método getImage() foi projetado para retornarimediatamente, antes mesmo da carga da imagem, de modo que a tarefa decarregar a imagem é iniciada no momento em que a imagem é usada e é feita emparalelo com a execução do programa por outra linha (Thread) de execução.Threads são descritos em detalhes no capítulo VIII. Por ora basta visualizá-loscomo um tipo de processo leve que compartilha o mesmo espaço deendereçamento com outros Threads.

Uma vez de posse de um objeto tipo Image podemos exibi-lo por meiodo método:

Graphics.drawImage(Image img,int x,int y, ImageObserver O)

O primeiro parâmetro é o objeto tipo Image. Os segundo e terceirodefinem a posição dentro Applet. O quarto parâmetro do tipoImageObserver é o que necessita ser melhor descrito. O objeto passadocomo quarto parâmetro deve implementar a interface ImageObserver, o queo habilita a receber notificações sobre a carga da imagem. Como a classeComponent implementa esta interface, então qualquer subclasse da classeComponent também a implementa, portanto, podemos passar o próprio Appletcomo parâmetro, usando a palavra chave this.

O método drawImage() desenha a imagem no estágio em que elaestiver. Deste modo, se apenas metade da imagem tiver sido carregada entãoapenas metade será mostrada. Em alguns casos o programador pode quererexibir uma imagem apenas quando ela for completamente carregada. Isto podeser feito por meio de um objeto da classe MediaTracker. A classeMediaTracker é usada para acompanhar o status de objetos de mídia. Umobjeto de mídia pode ser imagens ou sons, no entanto, no momento apenasimagens são suportadas. O exemplo XX.XX mostra o uso de um objeto destaclasse para monitorar o status de uma imagem.

public void init() {

Page 231: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

230MediaTracker tr = new MediaTracker(this);im = getImage(getDocumentBase(),”img.gif”);tr.addImage(im,0);

try {tr.waitForID(0);

}catch (InterruptedException excep) {}

}

Exemplo XX.XX – Uso do MediaTracker.

No exemplo XX.XX é criado uma instância da classe MediaTracker e osobjetos que devem ser monitorados são adicionados à instância por meio dométodo addImage(). Além da imagem também é atribuído um identificadorúnico que será usado para controlar a ordem de prioridade de carga do objeto.Também pode ser usado para identificar subconjuntos imagens. As imagens comnúmero menor possuem maior prioridade no processo de carga em relação asimagens com número maior. O início da carga da imagem é feita por meio dométodo:

public void waitForID(int id) throwsInterruptedException

O identificador da imagem (ou do subconjunto de imagens) é passado porparâmetro para o método. Este método espera até que todas as imagens com oidentificador sejam carregadas. Se ocorrer algum erro na carga a imagem éconsiderada carregada. O programador deve usar os métodos isErrorAny()e isErrorID() para detectar a ocorrência de erros.

Áudio

O versão JDK1.0 oferece suporte para execução de arquivos de áudioapenas no formato AU. No entanto, o SDK1.2 estendeu este suporte paraarquivos de áudio no formato AIFF, WAV, MIDI (tipo 0 e 1) e RMF. Java podemanipular dados de áudio em 8 e 16bits. A classe usada tratamento de áudio é aAudioClip, que contém os seguintes métodos:

• play() – Inicia a execução do audio clip.• loop() – Executa o audio clip em um loop.

Page 232: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

231

• stop() – Para a execução do audio clip.

Para se criar uma instância da classe AudioClip pode-se usar o métodogetAudioClip() da classe Applet:

getAudioClip(URL url, String nome)

O método retorna imediatamente mesmo que o arquivo de áudio nãoexista. O arquivo será carregado quando o programa tentar usá-lo. O ExemploVII.xx mostra um Applet que faz uso de um objeto AudioClip.

import java.lang.*;import java.net.URL;

public class ExSom extends java.applet.Applet{

AudioClip som; public void init()

{som = getAudioClip(getDocument(),”ola.au”);

} public void start() {som.play();}}

Exemplo VII.XX – Applet que executa um arquivo de audio.

Obtendo parâmetros

Na seção XX comentamos o formato do link HTML que faz referência aum arquivo em bytecodes. Comentamos também a existência de marcadores noformato

<param name=“...” value=“...”>

que são usados para passagem de parâmetros do HTML para o programa embytecodes. Nesta seção é mostrado o código Java necessário para capturar essesparâmetros. De modo a facilitar a explicação faremos uso de um exemplo. Oexemplo VII.7 mostra o código HTML que passa dois valores e o exemplo VII.8mostra um código em Java que recebe os parâmetros.

<HTML>

Page 233: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

232

<applet code=“Applet5.class” width=400 height=250><param name=“numero” value=“5”><param name=“nome” value=“Ana”></APPLET></HTML>

Exemplo VII.7 – Código HTML passando valores.

import java.awt.*;

public class Applet5 extends java.applet.Applet{

Label label1 = new Label();

public void init(){

setLayout(null);int i = Integer.parseInt(getParameter(“numero”));setSize(150,87);label1.setText(getParameter(“nome”)+ “:”+i);add(label1);label1.setBounds(24,12,84,48);

}

}

Exemplo VII.8 – Applet que recebe parâmetros.

Os valores são recebidos por meio do método getParameter() querecebe como argumento o nome do parâmetro definido no código HTML. Osvalores são retornados como objetos do tipo String. Se não existir um parâmetrocom o nome passado para o método getParameter() o retorno será null.

O programador também pode definir o método getParameterInfo(),cuja única ação é retornar um array de duas dimensões, contendo as informaçõessobre os parâmetros. As informações armazenadas são o nome, tipo e descriçãode cada parâmetro. Este método pode ser usado pelos navegadores Web paraajudar ao usuário a definir os valores a serem passados para o Applet.

public String[][] getParameterInfo(){String[][] info = {{“numero”,”int”,”number qualquer”}, {“nome”,”string”,”nome de alguem”}};

Page 234: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

233return info;

}

Exemplo VII.9 – Definindo informações sobre os parâmetros .

Executando um Applet como aplicação

Algumas vezes desejamos desenvolver um programa que possa funcionarcomo aplicação e como Applet. Podemos atingir este objetivo criando ummétodo main() dentro da subclasse Applet que está sendo implementada. Ométodo main() deve criar uma instância da classe Frame e adicionar a ele umobjeto da subclasse do Applet. O exemplo VII.10 mostra como criar um métodomain() para o Applet do exemplo VII.1.

import java.awt.*;import java.applet.*;

public class Applet6 extends Applet{

Label label1 = new Label();

public void init(){

setLayout(null);setSize(150,87);label1.setText("Ola Mundo!");add(label1);label1.setBounds(24,12,84,48);

}static public void main(String[] args){

FrameX frame = new FrameX("OLA");Applet6 applet = new Applet6();frame.add("Center", applet);frame.setSize(200,100);frame.setVisible(true);applet.init();applet.start();

}}

Exemplo VII.10 – Applet com método main.

Preparando Applets para produção e arquivos JARs

Page 235: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

234

Após o desenvolvimento e teste do Applet chega o momento de colocá-loem produção. Isto é feito colocando a página HTML que faz referência aoarquivo em bytecodes, resultante da compilação do Applet, em um diretórioacessado por um servidor Web. Você já deve ter notado que cada classe Javagera um arquivo em bytecodes. Deste modo, um arquivo contendo várias classesem Java gerará, após a compilação vários arquivos de bytecodes, um para cadaclasse. No caso de Applets com um tamanho razoável pode ser gerado umgrande número de arquivos. Isto pode ser um problema em se tratando de umaaplicação que é projetada para ser transmitida em uma rede de longa distânciapor meio do protocolo HTTP, já que cada classe irá gerar uma transação HTTPquando for referenciada pela primeira vez. Além disso, apesar do código embytecodes ser menor do que o código gerado pela compilação da maioria dosprogramas escritos em outras linguagens de programação seria importantediminuir o máximo possível o tamanho dos arquivos, de modo a minimizar otráfego na rede. Para solucionar esses e outros problemas foi introduzido a partirda versão 1.1 da linguagem Java o formato de arquivo JAR (Java Archive). Oformato de arquivo JAR permite o agrupamento de vários arquivos em um únicoarquivo. Além disso, o formato JAR permite a compressão de dados de modootimizar o armazenamento e a transmissão de dados. O principais benefícios douso do formato JAR são os seguintes:

• Menor tempo de carga de Applets: Se todos os arquivos relacionados comum Applet estão agrupados em um único arquivo JAR, apenas uma transaçãoHTTP será necessária para carregar o Applet. Este tempo será ainda menorse os arquivos estiverem compactados.

• Segurança: o conteúdo do arquivos JAR podem ser assinados digitalmente.Deste modo, os usuários que reconhecerem a sua assinatura podem concederprivilégios para acessar recursos que não estariam disponíveis, casocontrário.

• Portabilidade: a API para manipulação dos arquivos JAR é parte integrantedo núcleo da biblioteca de classes de Java, o que a torna independente deplataforma.

Outros benefícios foram adicionados com o lançamento da versão 1.2 doSDK, como por exemplo, informações sobre versão.

Os arquivos contidos em um arquivo JAR podem ser de tipos variados como,como bytecodes, imagens e sons, podendo pertencer a um Applet, aplicação ousimplesmente a uma biblioteca de classes. Além disso, um arquivo JAR podeconter uma descrição dos arquivos armazenados, chamada de manifest. O SDK

Page 236: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

235

vem com uma ferramenta para criação e manutenção de arquivos JAR. Oformato mais comum de invocação do programa é:

jar [opções] destino arquivo(s)-de-entrada

onde destino é o nome do arquivo, arquivo(s)-de-entrada representa onome dos arquivos que serão incluídos no arquivo JAR e opções é umacoleção de letras com o seguinte significado:

Opções Descriçãoc Cria um arquivo novo.t Lista o conteúdo.x Extrai todos os arquivos.x file Extrai o arquivo especificado.f Indica que o nome do arquivo de saída, caso seja a criação de um arquivo, ou

de entrada caso contrário, será especificado. Sem essa opção o programa jarassume que saída ou a entrada será a padrão.

m Indica que o primeiro argumento será o nome de um arquivo manifest criadopelo usuário.

v Gera saída com os detalhes da execução.O Não comprime os arquivos. Usada para criar arquivos JAR que podem ser

colocados no classpath.M Não cria o arquivo manifest.

Se um subdiretório for incluído nos arquivos de entrada então osubdiretório será automaticamente inserido no arquivo JAR, incluindo os seussubdiretórios. As informações sobre o caminho até o arquivo é tambémarmazenada.

Para invocar um Applet inserido em um arquivo JAR utilize a palavrachave archive no arquivo HTML. O exemplo VII.11 mostra como invocar umApplet desta forma.

<applet code=meuApplet.class archive=meuarquivo.jar width=width height=height></applet>

Exemplo VII.10 – Applet com método main.

No caso de uma aplicação é necessário passar o arquivo JAR comoparâmetro. Na versão JDK1.1 é preciso usar o comando jre no lugar do

Page 237: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

236

comando java. Por exemplo, suponha que armazenamos um aplicação, cujaclasse principal é Mainclass, em um arquivo arq.jar. Para executá-labasta digitar o comando:

jre -cp arq.jar Mainclass

onde a opção cp indica que o arquivo arq.jar deve ser anexado aoclasspath. Já na versão SDK1.2 usa-se o comando java, sendo que oarquivo JAR deve conter um manifest indicando a classe principal:

java -jar arq.jar

A tabela VII.4 mostra alguns exemplos do uso do utilitário que geraarquivos JAR.

jar cf meuarq.jar *.class Cria um arquivo JAR com o nome meuarq.jar contendo todosos arquivos de classes do diretório corrente. Um arquivomanifest é gerado automaticamente.

jar cmf meuarq.jarmeuManifest.mf *.class

Como o exemplo anterior, porém o arquivo manifestmeuManifest.mf é adicionado.

jar tf meuarq.jar Lista o conteúdo do arquivo meuarq.jar.

jar xf meuarq.jar Extrai todos os arquivos contidos em meuarq.jar.

Tabela VII.4 –Exemplos do uso do comando jar.

Criando os próprios arquivos manifest

A opção m da ferramenta para criação de arquivos JAR permite adicionarinformações ao arquivo manifest default. É necessário que o usuário crie umarquivo contendo as adições que devem ser feitas. O formato básico do comandoé:

jar cmf arq_adições arq_jar arquivo(s)

O arquivo de adições é simplesmente um arquivo texto é composto porum conjunto de declarações. Por exemplo se o usuário quiser especificar que aclasse que deve ser usada como ponto de entrada é a classe Mainclass, entãobasta inserir a seguinte linha no arquivo de adições:

Main-Class: Mainclass

Page 238: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

237

Exercícios

Faça uma calculadora com o seguinte layout:

Agenda Eletrônica versão Applet 1.0

0 . =

3 2 1

6 5 4

9 8 7

/

*

-

+

Page 239: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

238

Capítulo X JavaBeanO que é um JavaBean?

A API JavaBeans é a especificação que torna possível escrevercomponentes de software na linguagem Java. Componentes são peças desoftware, análogas a bloquinhos de montar, reutilizáveis, auto-contidas e quepodem ser usadas para comporem visualmente outros componentes, Applets,aplicações e Servlets usando um ambiente de desenvolvimento que suporte aespecificação de JavaBeans. Componentes JavaBean são conhecidos comoBeans.

Diferente de outras ferramentas de programação, como Delphi ou VB, osuporte ao desenvolvimento de componentes foi acrescentado, de formaelegante, na linguagem Java sem alterá-la.

JavaBeans são classes Java comuns que seguem na sua construção umaespecificação que permite o seu uso visual em ambientes RAD.

JavaBeans foram projetados para trabalhar em conjunto com ferramentasde desenvolvimento "JavaBeans-enabled".

JavaBeans e ferramentas RAD

As ferramentas de desenvolvimento expõem as características públicas doBean visualmente. Eles obtêm as características do Bean (propriedades, métodose eventos) em um processo conhecido como introspection. A introspection podeser feita de duas maneiras:

• Através da utilização de Reflection para o obtenção dos métodos, e do usodas convenções para determinação dos eventos e propriedades.

• Por uso de uma class de informações denominada BeanInfo. Uma classeBeanInfo implementa a interface BeanInfo. Uma classe BeanInfoexplicitamente lista todas as características do Bean que devem ser expostaspara o ambiente de desenvolvimento.

As tão faladas propriedades são características do Bean que podem sermudadas durante a programação. O ambiente de desenvolvimento faz a

Page 240: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

239

introspeção em um Bean para descobrir as propriedade e expo-las paramanipulação.

Os Beans utilizam eventos para se comunicarem com outros Beans. Osambientes de desenvolvimento pode examinar os Beans e determinarem queeventos um determinado Bean pode disparar (fire) ou que eventos ele podemanipular (receive).

Os métodos das classes que compõem um Bean são métodos Java simples,que podem ser chamados por qualquer outras classes.

JavaBean é um padrão desenhado para ser utilizado por um ambientes dedesenvolvimento RAD. E todas as suas características foram projetas parapermitir o uso fácil por programadores sem modificar a linguagem Java. Nospróximos tópicos veremos as convenções de nomes e o funcionamento eutilização dessa poderosa especificação.

Propriedades

Em JavaBeans propriedade é um atributo público simples que pode ser deleitura/escrita, apenas leitura ou apenas escrita. Existem quatro tipos depropriedades: simples, indexada, ligada (bound), e restrita (constrained).

Simples

Representa um valor simples (Ex.: int, float, Object, ...). Pode serdefinida com um par de métodos getXxx/setXxx, onde xxx é o nome dapropriedade. Se for definido os dois métodos para a propriedade, esta será deleitura/escrita, caso seja definido apenas o método getXxx a propriedade seráapenas leitura, e finalmente se for definida apenas o método setXxx será apenasescrita.

Quando uma propriedade for booleana, a convenção e modificada paraisXxx ou invés de getXxx (no desenho dessa característica resolveram aderir amáxima “toda regra possui uma exceção”).

Abaixo temos o exemplo de uma classe que define uma propriedade:

Page 241: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

240

Class Pessoa{ private String nome; private String telefone; private String endereço;

public Pessoa(String n, String t, String e) { nome = n; telefone = t; endereço = e; }

public void setNome(String n) { nome=n; }

public void setTelefone(String t) telefone = t; }

public void setEndereço(String e) { endereço = e; }

public String getNome() { return nome; }

public String getTelefone() { return telefone; }

public String getEndereço() { return endereço; }}

A classe acima define as propriedades simples: telefone, nome eendereço, sendo todas as três propriedades de leitura/escrita.

Indexada

Representa um array de valores (ex.: int[], float[], Object[] , ...). Osmétodos getXxx/setXxx que definem a propriedade devem ter como parâmetroum inteiro que será o índice de acesso ao array. A propriedade pode tambémsuportar getXxx/setXxx para todo o array.

O exemplo abaixo trás a definição parcial de uma classe agenda:

Public class Agenda{

private Pessoa pessoas[];

.

.

.

Page 242: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

241

public Pessoa[] getPessoas(){return pessoas;}public void setPessoas(Pessoa[] i){

this.pessoas = i;}public Pessoa getPessoas(int indice){

return pessoas[indice];}public void setPessoas(int indice, Pessoa p){

pessoas[indice] = p;}

.

.

.}

Neste exemplo, definimos uma propriedade indexada pessoas, que podeser acessada tanto na forma de uma array completo, quanto nos seus elementos,através dos seus índice.

Ligada (Bound)

Uma propriedade bound notifica outros objetos quando o seu valor ealterado. Toda vez que o valor de uma propriedade bound é modificado, apropriedade dispara um evento PropertyChange que contém o nome, o novoe o velho valores da propriedade.

Class Pessoa { private String nome; private String telefone; private String endereço; Private PropertyChangeSupport changes = New PropertyChangeSupport(this);

public Pessoa(String n, String t, String e) {nome = n; telefone = t; endereço = e;}

public void addPropertyChangeListener(PropertyChangeListener l){ changes.addPropertyChangeListener(l); }

public

Page 243: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

242

void removePropertyChangeListener(PropertyChangeListener l) { changes.removePropertyChangeListener(l); }

public void setNome(String n) { String nomevelho = nome; Nome = n; Changes.firePropertyChange(“nome”, nomevelho, nome); }

public void setTelefone(String t) { String telefonevelho = telefone; telefone = t; Changes.firePropertyChange(“telefone”, telefonevelho,telefone); }

public void setEndereço(String e) { String endereçovelho = endereço; endereço = e; Changes.firePropertyChange(“endereço”, nomeendereço,endereço); }

public String getNome() { return nome; }

public String getTelefone() { return telefone; }

public String getEndereço() { return endereço; }}

A classe Pessoa já foi implementada anteriormente neste capítulo, asmodificações introduzidas tornaram as propriedades nome, telefone e endereçoligadas, i. e., sempre que elas sofrerem alterações, os listener que implementamPropertyChangeListener e estão registrados como ouvintes da nossainstância da classe, serão notificados.

Além das alterações no corpo dos métodos setXxx, que adicionou ocódigo que dispara o evento PropertyChange, nosso Bean também ganhouum novo objeto changes e dois métodos que cuidam do registro e exclusão delistener.

Restringidas(Constrained)

Um objeto com propriedade restrita permite que outros objetos vetem aalteração do valor dessa propriedade. listener de propriedades restritas podem

Page 244: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

243

vetar uma mudança de valor da propriedade através de uma exceçãoPropertyVetoException que é levantada. Geralmente, apesar de não serobrigatório, as propriedades restringidas também são ligadas.

class CartãoCrédito{ private String número; private PropertyChangeSupport changes = new PropertyChangeSupport(this); private VetoableChangeSupport vetos = new VetoableChangesSupport(this);

public addVetoableChangeListener(VetoableChangeListener l){ vetos.addVetoableChangeListener(l); }

public removeVetoableChangeListener(VetoableChangeListener l){ vetos.removeVetoableChangeListener(l); } . . . public void setNúmero(String n) { String numeroVelho = numero; Vetos.fireVetoableChange(número,numeroVelho,n); número = n; changes.firePropertyChange(número,numeroVelho,numero);} . . .}

No exemplo acima definimos parcialmente uma classe com o nomeCartãoCrédito, esta classe possui uma propriedade de nome número que é umapropriedade restringida. Para implementamos esta característica, primeirointroduzimos uma novo objeto, veto, que nos dá o suporte ao registro doslistener que terão poder de veto sobre a propriedade.

Em seguida aparecem dois métodos que cuidam apropriadamente,repassando para VetoableChangeSupport, do registro dos listener quepodem vetar alterações.

Page 245: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

244

A parte mais interessante fica por conta do método setNúmero, ele é muitoparecido com um método de uma propriedade ligada, mas acrescenta uma linhaantes de alterar o valor da variável número. Sendo assim, a alteração só serárealizada, se o evento disparado com fireVetoableChange não levantarnenhuma exceção. Depois disso tudo, as coisa voltam a funcionar como em umapropriedade ligada convencional.

Eventos

Sempre que estudamos algo, inicialmente obtemos uma grandequantidade de informações e depois começamos a fazer generalizaçõestransformando o estudado em conhecimento. Bem, até agora vimos queJavaBeans é um padrão que nos permite utilizar um ambiente de programaçãoRAD, e vimos algumas características de classes que seguem este padrão.

Mas além desse padrão definir como as classes interage com o ambientede programação, ele também define como objetos destas classes interagem entresi. Aparece agora o conceito de eventos, que já vimos em capítulo anterior eagora veremos com as convenções de nossa API de componentes.

Um bom lugar para começarmos é: o que é um evento? Para nossospropósitos um evento é um objeto que encapsula dados a respeito de algumacoisa que ocorreu. Por exemplo, o mouse foi movido, uma tecla foi digitada,chegou um pacote UDP pela rede. Todas estas ocorrências podem ser modeladascomo eventos e informações sobre o que aconteceu podem ser inclusas no objetoevento.

Só para relembrar, no novo modelo de eventos da biblioteca de classesJava, um evento e “escutado” por classes que estão “capacitadas” para tratá-los,estas classes são chamadas de EventListener, e são um mecanismo geral decomunicação entre objetos sem a utilização de herança.

Nesta seção, devemos nos preocupar apenas com as convenções denomes de eventos e classes relacionadas para utilização na construção de Beans.Suponhamos que nos desejamos construir um Bean de nome Timer. Nossoevento teria o nome TimerEvent, e nosso Listener para este eventoTimerEventListener.

Page 246: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

245

Na próxima seção veremos como juntar todos estes conceitos e o queaprendemos ate agora em um exemplos de Bean completo um não-visual, umBean visual será mostrado no capítulo sobre MVC.

Um Bean para ser visual deve ser subclasse de java.awt.Component ou declasses que herdem java.awt.Component.

Desenvolvimento do exemplo

O Bean de exemplo que estudaremos agora é um componente que disparaum evento periodicamente em um intervalo de tempo definido pelo seuutilizador, este componente e semelhante ao componente Timer do Delphi e aoActiveX Timer do VB. Suas aplicações incluem atualizar o display de umrelógio ou acionar o método que mostra o próximo frame de uma animação.

Nosso primeiro Bean será composto das seguintes classes:

TimerBean - A classe principal do Bean;TimerEvent - A classe do evento disparado pelo Bean;TimerEventListener - A interface “ouvinte” para o evento do Bean;

TimerEventListener

A classe TimerEventListener implementa a interface que será utilizada para queo nosso Bean notifique seus listeners sobre cada evento.

Package timer;

public interface TimerEventListener extends java.util.EventListener{ void timerEventDisparado(TimerEvent te);}

Todos os listeners para JavaBeans devem herdar java.util.EventListenerou de alguma subclasse dela. O nome da interface deve ser XxxxListener, ondeXxxx corresponde ao nome do evento que esta interface habilita a tratar. Nonosso exemplo temos o evento TimerEvent e consequentemente a interface sechama TimerEventListener.

Page 247: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

246

Uma interface listener pode declarar quantos métodos seu desenvolvedordesejar. Normalmente estes métodos têm como parâmetro um objeto event. Nonosso caso declaramos somente um método.

TimerEvent

A classe TimerEvent implementa o evento que será passado para cadaTimerEventListener.

package timer;

public class TimerEvent extends java.util.EventObject{

public TimerEvent(Object source) {

super(source); }}

Todos eventos JavaBeans devem herdar java.util.EventObject e seu nomedeve obedecer ao padrão XxxxEvent, onde Xxxx é arbitrário. No nosso casoficamos com o nome TimerEvent.

Nosso construtor para a classe TimerListener tem como parâmetro umobjeto do tipo Object, e quando este construtor for chamado passaremos areferência para o objeto que o esta chamando.

Eventos, por serem classes comuns, também podem carregar informaçõesadicionais, o que não é o nosso caso.

TimerBean

Esta é a nossa classe principal, e é onde realmente implementamos nossoBean.

package timer;

import java.util.*;

Page 248: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

247import java.beans.*;

public class TimerBean implements java.io.Serializable, Runnable{ protected long intervalo = 1000; transient protected Thread th; protected java.util.Vector listeners = newjava.util.Vector(); private boolean ativo = false;

private java.beans.PropertyChangeSupport mudancas = new java.beans.PropertyChangeSupport(this);

public TimerBean() { super(); th = new Thread(this); th.start(); }

public void addPropertyChangeListener( PropertyChangeListener l) {

mudancas.addPropertyChangeListener(l); }

public void addTimerEventListener(TimerEventListener tl) {

listeners.addElement(tl); }

public void disparaEvento(TimerEvent e) { Vector v; synchronized (this) { v = (Vector) listeners.clone(); } for (int elem = 0; elem < v.size(); elem++) { ((TimerEventListener)v.elementAt(elem)).timerEventDisparado(e); } }

public long getIntervalo() {

return intervalo;

Page 249: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

248 }

public synchronized void inicia() {

ativo = true; }

public synchronized void para() {

ativo = false; }

public void removePropertyChangeListener(PropertyChangeListener l) {

mudancas.removePropertyChangeListener(l); }

public void removeTimerEventListener(TimerEventListener tl) {

listeners.removeElement(tl); }

public void run() { try { while (true) { th.sleep(intervalo); if (ativo) { TimerEvent evento = new TimerEvent(this); disparaEvento(evento); } } }catch (Exception e) {e.printStackTrace(); } }

public void setIntervalo(long interv) { long valorVelho = intervalo; intervalo = interv; mudancas.firePropertyChange("intervalo", new Long(valorVelho), new Long(intervalo)); }

}

Page 250: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

249

Comecemos pelo princípio. Todos os Beans devem ser serializáveis, esteé o mecanismo que é normalmente utilizado para armazenar aplicaçõesJavaBeans. Para tornarmos nossa classe serializável declaramos que estaimplementa a interface java.io.Serializable e marcamos nossos campos que nãosão serializáveis como transient ou providenciarmos métodos de serializaçãocustomizados.

Nossa classe também implementa Runnable para podermos utilizá-la emum thread. Em nossa classe possuímos os campos:

1. intervalo: que armazena de quanto em quanto tempo desejamos que umevento seja disparado. Através dos métodos getIntervalo() esetIntervalo(long) implementamos uma propriedade bound de nome“intervalo”.

2. th: Este campo é transient, isto é, quando esta classes for serializada estainformação não será gravada. Para nosso Bean th é o thread queperiodicamente dispara eventos para seus listeners.

3. listeners: Um Vector armazena a lista de listeners que estão registrados nesteBean para receber os eventos. Novos métodos são colocados em nossaclasses para registrar ou remover listeners, este métodos tem nomes queseguem o padrão JavaBeans e têm as formas addXxxx e removeXxxx,onde Xxxx é o nome do tipo de listener que deve ser registrado ou removido.No nosso exemplo, temos addTimerEventListener eremoveTimerEventListener.

4. ativo: este campo é utilizado para indicar para o Bean se ele deve ou nãodisparar eventos para os seus listeners. Ativo não é acessado diretamente, esim através dos métodos sincronizado para() e inicia().

Os métodos que merecem destaque são:1. run(): método que implementa o thread, em nosso caso ele contém

um laço infinito e dentro do laço, depois de fazer nosso thread“dormir”, com sleep, ele verifica se deve disparar um evento. Se devedispará-lo, um evento e criado e o método disparaEvento e chamado.

2. disparaEvento(TimerEvent e): inicialmente este método cria dentrode uma seção sincronizado uma cópia do Vector listener. Em seguidaatravés de um laço for, percorre este Vector chamando o métodotimerEventDisparado para cada listener registrado.

Page 251: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

250

Temos agora um exemplo completo de um JavaBeans. Mas esta tecnologia tempouca ou nenhuma utilidade se não a utilizarmos com ferramentas deprogramação visual como Visual Age, Visual Café, BDK e tantos outros.

Como o BDK é de graça, nós o utilizaremos para mostrar nosso Bean emação.

Instalando o Beans Development Kit (BDK)O Beans Development Kit (BDK) é uma aplicação Java pura, portanto só

depende do SDK para rodar. O BDK possui suporte para a API JavaBeans e umcontainer de teste (BeanBox), que manipula Beans visualmente.

Para instalar o BDK basta ter na maquina o SDK instalado (acima do1.1.4), entrar na pagina http://www.javasoft.com e fazer download edescompactá-lo. Pronto, e só rodar. Acompanhando o BDK temos tambémdocumentação e JavaBeans com código fonte para serem explorados.

Testando exemplo no BDK

Para rodar o BDK utilizamos o arquivo run.bat ou run.sh, dependendo doseu sistema operacional. Quando o aplicativo e inicializa sua área de trabalhafica parecido com a figura abaixo. O BDK é composto de 3 janelas:

• BeanBox: que é a janela onde os Beans são manipuladosvisualmente;

• ToolBox: uma lista de Beans que podem ser usados;• Properties: um janela que se altera dependendo do Bean que esta

selecionado no BeanBox. Ela mostra as propriedades do Beanselecionado e através dela o desenvolvedor pode alterar estaspropriedade no Componente;

Page 252: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

251

Com o BDK rodando nosso próximo passo e criar um arquivo jarcontendo o nosso Bean compilado.

Para criarmos um jar contendo Beans, devemos informar para aferramenta na qual este Bean será utilizado, quais classes são Beans. Para issoutilizamos o arquivo de manifesto do jar. Que ficaria assim para o nosso caso:

Nome do arquivo: manifest.mfManifest-Version: 1.0

Name: timer/TimerBean.classJava-Bean: True

Name: timer/TimerEventListener.class

Name: timer/TimerEvent.class

Para criar o arquivo jar, dentro do diretório que contenha o diretóriotimer, que é onde estão nossas classes compiladas, digite:

jar cvfm timer.jar manifest.mf .

Page 253: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

252

Com nosso jar criado temos agora que apresenta-lo ao BDK. Para issodevemos utilizar a opção File->LoadJar do menu da Janela BeanBox.Escolhemos então o arquivo jar que geramos, e o BDK irá carrega-lo. Apóscarregar nosso Bean a lista de Beans do ToolBean será adicionada de um entradachamada TimerBean, como mostrado na figura abaixo:

Agora é tudo mais divertido, acabou a parte chata!!!

Vamos começar a colocar os Beans na janela BeanBox para criarmosuma aplicação. Devemos colocar os seguintes Beans:

Page 254: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

253

Bean Propriedade(mudada) Novo valorOurbutton label IniciarOurbutton label PararTimerBean intervalo 2000EventMonitor

A posição dos Beans deve ser como na figura abaixo:

Depois de colocar todos os Beans no lugar e mudarmos suaspropriedades, devemos conectar os eventos nos métodos corretos de cada Bean.Para ligar um evento disparado por um Bean a um método de outro, devemosselecionar o primeiro e clicarmos em Edit->Events, escolhermos o evento eclicarmos no Bean alvo. Um dialogo aparecerá com os métodos que podem serescolhidos para serem chamados.

Page 255: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

254

Bean fonte Evento Bean alvo MétodoTimerBean TimerEvent-

timerEventDisparadoEventMonitor InitiateEventSourceMonito

ring()OurButton(iniciar)

action-actionPerformed TimerBean inicia()

OurButton(parar)

action-actionPerformed TimerBean para()

A figura abaixo mostra parte da operação.

Depois de tudo ligado, para testar basta clicar no botão de iniciar, entãoeventos serão disparados e aparecerão no Monitor de eventos. Depois clique nobotão parar parar para que os eventos deixem de ser disparados pela instância deTimerBean . Uma opção interessante para teste no BDK e clicarmos na opção demenu View->Disable Design Mode.

A figura abaixo mostra o teste do Bean.

Page 256: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

255

Page 257: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

256

Capítulo XI - ConcorrênciaUm sistema operacional é dito concorrente se permite que mais que uma

tarefa seja executada ao mesmo tempo. Na prática a concorrência real ouparalelismo só é possível se o hardware subjacente possui mais de umprocessador. No entanto, mesmo em computadores com apenas um processadoré possível obter um certo tipo de concorrência fazendo com o processadorcentral execute um pouco de cada tarefa por vez, dando a impressão de que astarefas estão sendo executadas simultaneamente.

Dentro da nomenclatura empregada, uma instância de um programa emexecução é chamada de processo. Um processo ocupa um espaço em memóriaprincipal para o código e para as variáveis transientes (variáveis que sãoeliminadas ao término do processo). Cada processo possui pelo menos uma linhade execução (Thread). Para ilustrarmos o que é uma linha de execução suponhaum determinado programa prog1. Ao ser posto em execução é criado umprocesso, digamos A, com uma área de código e uma área de dados e é iniciadaa execução do processo a partir do ponto de entrada. A instrução inicial assimcomo as instruções subsequentes formam uma linha de execução do processo A.Portanto, um thread nada mais é que uma sequência de instruções que está emexecução de acordo com que foi determinado pelo programa. O estado correnteda linha de execução é representada pela instrução que está sendo executada. Afigura IX.1 mostra a relação entre estes elementos.

arquivo prog1 Memória Principal

Figura IX.1 – Relação entre Programa, Processo e Thread.

É possível existir mais de uma linha de execução em um único processo.Cada linha de execução pode também ser vista como um processo, com a

101001101010110010010101100100011101

100101010101001010

Área de dados

Área de códigoLinha de execução(thread)

Processo

101001101010110010010101100100011101

Page 258: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

257

diferença que enquanto cada processo possui sua área de código e dadosseparada de outros processos, os threads em um mesmo processo compartilhamo código e a área de dados. O que distingue um thread de outro em um mesmoprocesso é a instrução corrente e uma área de pilha usada para armazenar ocontexto da sequência de chamadas de cada thread. Por isso os threads tambémsão chamados de processos leves (light process). A figura IX.2 mostraesquematicamente a diferença entre processos e threads.

Memória Processo

Figura IX.2 – (a) Processos; (b) Threads.

Sistemas monotarefas e monothreads como o DOS possuem apenas umprocesso em execução em um determinado instante e apenas um thread noprocesso. Sistemas multitarefas e monothreads como o Windows 3.1 permitemvários processos em execução e apenas um thread por processo. Sistemasmultitarefas e multithread como o Solaris, OS/2, Linux e Windows 95/98/NTpermitem vários processos em execução e vários threads por processo.

Como os threads em um mesmo processo possuem uma área de dados emcomum, surge a necessidade de controlar o acesso a essa área de dados, de modoque thread não leia ou altere dados no momento que estão sendo alterados poroutro thread. A inclusão de instruções para controlar o acesso a áreascompartilhadas torna o código mais complexo do que o código de processosmonothreads.

Uma pergunta pode surgir na mente do leitor: se a inclusão de mais deum thread torna o código mais complexo porque razão eu deveria projetarcódigo multithread. Processos com vários threads podem realizar mais de uma

10100010011100101010

10100111

10100010011100101010

10100111

10100010011100101010

10100111

AB

C

101000100111001010101010101010000101101101010001010101010110110010101010100101010101001010101010010000001010101010101

1010011100101010101010101010101010101010100011110101010

Thread 1

Thread 2Código

DadosÁrea de pilha do thread1

Área de pilhado thread2

Page 259: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

258

tarefa simultaneamente. São úteis na criação de processos servidores, criação deanimações e no projeto de interfaces com o usuário que não ficam travadasdurante a execução de alguma função. Por exemplo, imagine um processoservidor a espera de requisições de serviços, podemos projetá-lo de modo que aosurgir uma solicitação de um serviço por um processo cliente ele crie um threadpara atender a solicitação enquanto volta a esperar a requisição de novosserviços. Com isto os processos clientes não precisam esperar o término doatendimento de alguma solicitação para ter sua requisição atendida.

O mesmo pode ser dito em relação ao projeto de interfaces com ousuário. O processo pode criar threads para executar as funções solicitadas pelousuário, enquanto aguarda novas interações. Caso contrário, a interface ficariaimpedida de receber novas solicitações enquanto processa a solicitação corrente,o que poderia causar uma sensação de travamento ao usuário.

Outra aplicação para processos multithread é a animação de interfaces.Nesse caso cria-se um ou mais threads para gerenciar as animações enquantooutros threads cuidam das outras tarefas como por exemplo entrada de dados.

A rigor todas as aplicações acima como outras aplicações de processosmultithread podem ser executados por meio de processos monothreads. Noentanto, o tempo gasto na mudança de contexto entre processos na maioria dossistemas operacionais é muito mais lenta que a simples alternância entre threads,uma vez que a maior parte das informações contextuais são compartilhadas pelosthreads de um mesmo processo.

Mudança de Contexto (task switch)É o conjunto de operações necessárias para gravar o estado atual do processo corrente e

recuperar o estado de outro processo de modo a torná-lo o processo corrente.

Mesmo que você não crie mais de um thread todo processo Java possuivários threads: thread para garbage collection, thread para monitoramento deeventos, thread para carga de imagens, etc.

Criando threads em Java

Processos Multithread não é uma invenção da linguagem Java. É possívelcriar processos multithread com quase todas as linguagens do mercado, comoC++, e Object Pascal. No entanto Java incorporou threads ao núcleo básico dalinguagem tornado desta forma mais natural o seu uso. Na verdade o uso de

Page 260: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

259

threads está tão intimamente ligado a Java que é quase impossível escrever umprograma útil que não seja multithread.

A classe Thread agrupa os recursos necessários para a criação de umthread. A forma mais simples de se criar um thread é criar uma classe derivadada classe Thread. Por exemplo:

class MeuThread extends Thread {...}

É preciso também sobrescrever o método run() da classe Thread. Ométodo run() é o ponto de entrada do thread, da mesma forma que o métodomain() é ponto de entrada de uma aplicação. O exemplo IX.1 mostra umaclasse completa.

public class MeuThread extends Thread { String s; public MeuThread (String as) { super(); s = new String(as); } public void run() { for (int i = 0; i < 5; i++) System.out.println(i+” “+s); System.out.println("FIM! "+s); }}

Exemplo IX.1 – Subclasse da classe Thread.

No exemplo IX.1foi inserido um atributo para identificar o thread, apesarde existir formas melhores de se nomear um thread como veremos mais adiante.O método run() contém o código que será executado pelo thread. No exemploIX.1 o thread imprime cinco vezes o atributo String. Para iniciar a execução deum thread cria-se um objeto da classe e invoca-se o método start() doobjeto. O método start() cria o thread e inicia sua execução pelo métodorun(). Se o método run() for chamado diretamente nenhum thread novo serácriado e o método run() será executado no thread corrente. O exemplo IX.2mostra uma forma de se criar um thread usando a classe definida no exemploIX.1.

Page 261: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

260public class TesteThread1 { public static void main (String[] args) { new MeuThread("Linha1").start(); }}

Exemplo IX.2 – Criação de um Thread.

No exemplo acima apenas um thread, além do principal é criado. Nadaimpede que sejam criados mais objetos da mesma classe para disparar umnúmero maior de threads. O exemplo IX.3 mostra a execução de dois threadssobre dois objetos de uma mesma classe.

public class TesteThread2 { public static void main (String[] args) { new MeuThread("Linha1").start(); new MeuThread("Linha2").start(); }}

Exemplo IX.3 – Criação de dois Threads.

Cada thread é executado sobre uma instância da classe e, porconsequência, sobre uma instância do método run(). A saída gerada pelaexecução do exemplo IX.3 depende do sistema operacional subjacente. Umasaída possível é a seguinte:

0 Linha20 Linha11 Linha21 Linha12 Linha22 Linha13 Linha23 Linha14 Linha24 Linha1FIM! Linha2FIM! Linha1

A saída acima mostra que os threads executam intercaladamente. Noentanto, em alguns sistemas operacionais os threads do exemplo IX.3executariam um após o outro. A relação entre a sequência de execução e osistema operacional e dicas de como escrever programas multithread com

Page 262: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

261

sequência de execução independente de plataforma operacional serão em umaseção mais adiante neste mesmo capítulo.

Criando threads por meio da interface Runnable

Algumas vezes não é possível criar uma subclasse da classe Threadporque a classe já deriva outra classe, por exemplo a classe Applet. Outrasvezes, por questões de pureza de projeto o projetista não deseja derivar a classeThread simplesmente para poder criar um thread uma vez que isto viola osignificado da relação de classe-subclasse. Para esses casos existe a interfaceRunnable. A interface Runnable possui apenas um método para serimplementado: o método run(). Para criar um thread usando a interfaceRunnable é preciso criar um objeto da classe Thread, passando para oconstrutor uma instância da classe que implementa a interface. Ao invocar ométodo start() do objeto da classe Thread, o thread criado, inicia suaexecução no método run() da instância da classe que implementou a interface.O exemplo IX.4 mostra a criação de um thread usando a interface Runnable.

public class TesteThread2 implements Runnable{ private String men; public static void main(String args[]) {

TesteThread2 ob1 = new TesteThread2 (“ola”);Thread t1 = new Thread(ob1);t1.start();

} public TesteThread2 (String men) {this.men=men;} public void run() { for(;;) System.out.println(men); }}

Exemplo IX.4 – Criação de um thread por meio da interface Runnable.

Note que agora ao invocarmos o método start() o thread criadoiniciará a execução sobre o método run() do objeto passado como parâmetro, enão sobre o método run() do objeto Thread.

Page 263: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

262

Nada impede que seja criado mais de um thread executando sobre omesmo objeto:

Thread t1 = new Thread(ob1);Thread t2 = new Thread(ob1);

Neste caso alguns cuidados devem ser tomados, uma vez que existe ocompartilhamento das variáveis do objeto por dois threads. Os problemas quepodem advir de uma situação como esta serão tratados mais adiante.

A classe Thread

A classe Thread é extensa, possuindo vários construtores, métodos evariáveis públicas. Aqui mostraremos apenas os mais usados.

Hierarquia

A classe Thread deriva diretamente da classe Object.

java.lang.Object

java.lang.Thread

Construtores

Construtor DescriçãoThread(ThreadGroup g, String nome) Cria um novo thread com o nome

especificado dentro do grupo g.Thread(Runnable ob, String nome) Cria um novo thread para executar

sobre o objeto ob, com o nomeespecificado.

Thread(ThreadGroup g, Runnable ob, String nome)

Cria um novo thread para executarsobre o objeto ob, dentro do grupog, com o nome especificado.

Thread(String nome) Cria um novo thread com o nomeespecificado.

Thread() Cria um novo thread com o nomedefault.

Thread(Runnable ob) Cria um novo thread para executar

Page 264: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

263

sobre o objeto ob.Thread(ThreadGroup g, Runnable ob) Cria um novo thread para executar

sobre o objeto ob, dentro do grupog.

Tabela IX.1 – Construtores da classe Thread.

A tabela X.1 mostra os principais construtores da classe Thread.Podemos notar que é possível nomear os threads e agrupá-los. Isto é útil paraobter a referência de threads por meio do seu nome.

Métodos

Método DescriçãocurrentThread() Retorna uma referência para o thread corrente em

execução.destroy() Destroi o thread sem liberar os recursos.dumpStack() Imprime a pilha de chamadas do thread corrente.enumerate(Thread[] v) Copia para o array todos os thread ativos no

grupo do thread.getName() Obtém o nome do thread.getPriority() Obtém a prioridade do thread.getThreadGroup() Retorna o grupo do thread.resume() Reassume a execução de um thread previamente

suspenso.run() Se o thread foi construído usando um objeto

Runnable separado então o método do objetoRunnable é chamado. Caso contrário nadaocorre.

setName(String name) Muda o nome do thread.setPriority(int newPriority) Muda a prioridade do thread.sleep(long millis) Suspende o thread em execução o número de

milisegundos especificados.sleep(long millis, intnanos)

Suspende o thread em execução o número demilisegundos mais o número de nanosegundosespecificados.

start() Inicia a execução do thread. A máquina virtualchama o método run() do thread.

stop() Força o encerramento do thread.suspend() Suspende a execução de um thread.yield() Faz com que o thread corrente interrompa

permitindo que outro thread seja executado.

Tabela IX.2 – Métodos da classe Thread.

Page 265: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

264

A tabela X.2 apresenta os principais métodos do classe Thread. Algunsmétodos muito usados nas versões anteriores do SDK1.2 foram depreciados naversão atual por serem considerados inseguros ou com tendência a causaremdeadlock . Os métodos depreciados são: stop(), suspend(), resume() edestroy().

DeadlockTravamento causado pela espera circular de recursos em um conjunto de threads. O

travamento por deadlock mais simples é o abraço mortal onde um thread A espera que um threadB libere um recurso, enquanto que o thread B só libera o recurso esperado por A se obter umrecurso mantido por A. Desta forma os dois threads são impedidos indefinidamente deprosseguir.

Existem alguns métodos da classe Object que são importantes para ocontrole dos threads. O leitor pode estar se perguntando porque métodosrelacionados threads estão na superclasse Object que é “mãe” de todas asclasse em Java. A razão disso é que esses métodos lidam com um elementoassociado a todo objeto e que é usado para promover o acesso exclusivo aosobjetos. Esse elemento é chamado de monitor. Na seção que aborda asincronização os monitores serão discutidos mais detalhadamente. Os métodosherdados relacionados com controle dos threads estão descritos na tabela IX.3.

Método Descriçãonotify() Notifica um thread que está esperando sobre

um objeto.notifyAll() Notifica todos os threads que está esperando

sobre um objeto.wait() Espera para ser notificado por outro thread.wait(long timeout, int nanos) Espera para ser notificado por outro thread.wait(long timeout) Espera para ser notificado por outro thread.

Tabela IX.3 – Métodos da classe Object relacionados com threads.

Variáveis públicas

As variáveis públicas da classe Thread definem valores máximo, mínimoe default para a prioridade de execução dos threads. Java estabelece dez valoresde prioridade. Como essas prioridades são relacionadas com as prioridades do

Page 266: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

265

ambiente operacional depende da implementação máquina virtual e podeinfluenciar no resultado final da execução do programa. Mais adianteabordaremos a influência do ambiente operacional na execução de programasmultithread.

Variável Descriçãostatic final int MAX_PRIORITY A prioridade máxima que um thread pode ter.static final int MIN_PRIORITY A prioridade mínima que um thread pode ter.static final int NORM_PRIORITY A prioridade default associado a um thread.

Tabela IX.4 – Variáveis públicas.

Ciclo de Vida dos Threads

Um thread pode possuir quatro estados conforme mostra a figura IX.3.Podemos observar que uma vez ativo o thread alterna os estados em execução esuspenso até que passe para o estado morto. A transição de um estado paraoutro pode ser determinada por uma chamada explícita a um método ou devida aocorrência de algum evento a nível de ambiente operacional ou de programa.

Estados Ativos

Figura IX.3 – Estados de um thread.

A transição de um thread do estado novo para algum estado ativo ésempre realizada pela invocação do método start() do objeto Thread. Já astransições do estado em execução para o estado suspenso e vice-versa e dessespara o estado morto podem ser disparadas tanto pela invocação de variadosmétodos como pela ocorrência de eventos. O exemplo IX.5 mostra as ocorrênciade transição em um código.

threadnovo

thread emExecução

threadmorto

threadsuspenso

Page 267: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

266

public class TesteThread3 extends Thread{ public TesteThread3 (String str) {super(str);} public void run() { for (int i = 0; i < 10; i++) { System.out.println(i + " " + getName()); try { // Comando para suspender o thread por // 1000 milisegundos (1 segundo) // Transição do estado em execução para o // estado suspenso sleep(1000); } catch (InterruptedException e) {} // Evento: fim do tempo de suspensão // Transição do estado em suspenso para o // estado em execução } System.out.println("FIM! " + getName()); // Evento: fim da execução do thread // Transição do estado ativo suspenso para o // estado morto } public static void main(String args[]) {

TesteThread3 t1 = new TesteThread3(args[0]);t1.start(); // Transição para um estado ativo

}}

Exemplo IX.5 – Alguns comandos e eventos que acarretam transição deestados.

sleep(), yield(), join(), destroy(), stop(), suspend() eresume().

Agora que vimos os estados que podem ser assumidos por um thread emseu ciclo de vida vamos examinar mais detalhadamente alguns dos métodosresponsáveis pela mudança de estado de um thread.

Page 268: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

267

sleep()

O método sleep()é um método estático e possui as seguintesinterfaces:

static void sleep(long ms) throws InterruptedException

oustatic void sleep(long ms, int ns) throws InterruptedException

Onde ms é um valor em milisegundos e ns é um valor em nanosegundos.O método sleep() faz com que o thread seja suspenso por um

determinado tempo, permitindo que outros threads sejam executados. Como ométodo pode lançar a exceção InterruptedException, é preciso envolver achamada em um bloco try/catch ou propagar a exceção. O exemplo IX.6define uma espera mínima de 100 milisegundos entre cada volta do loop. Noteque o tempo de suspensão do thread pode ser maior que o especificado, uma vezque outros threads de maior ou mesmo de igual prioridade podem estar sendoexecutados no momento em que expira o tempo de suspensão solicitado.

public class ThreadComYield extends Thread { String s; public ThreadComYield(String as) { super(); s = new String(as); } public void run() { for (int i = 0; i < 5; i++) { System.out.println(i+” “+s); try{ Thread.sleep(100); catch(InterruptedException e){} } System.out.println("FIM! "+s); }}

Exemplo IX.6 – Uso do método sleep().

Outro problema com o sleep() é que a maioria dos SistemasOperacionais não suportam resolução de nanosegundos. Mesmo a resolução anível de unidade de milisegundo não é suportada pela maioria dos SOs. No casodo SO não suportar a resolução de tempo solicitada, o tempo será arredondadopara a nível de resolução suportado pela plataforma operacional.

Page 269: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

268

yield()

O método yield() é um método estático com a seguinte interface:

static void yield()

Uma chamada ao método yield() faz com que o thread corrente libereautomaticamente a CPU para outro thread de mesma prioridade. Se não houvernenhum outro thread de mesma prioridade aguardando, então o thread correntemantém a posse da CPU. O exemplo IX.7 altera o exemplo IX.1 de modo apermitir que outros threads de mesma prioridade sejam executados a cada voltado loop.

Public class ThreadComYield extends Thread { String s; public ThreadComYield(String as) { super(); s = new String(as); } public void run() { for (int i = 0; i < 5; i++) { System.out.println(i+” “+s); Thread.yield(); } System.out.println("FIM! "+s); }}

Exemplo IX.7 – Uso do método yield().

join()

O método join() é um método de instância da classe Thread e éutilizado quando existe a necessidade do thread corrente esperar pela término daexecução de outro thread. As versões do método join() são as seguintes:

public final void join();public final void join(long millisecond);public final void join(long millisecond, int nanosecond);

Page 270: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

269

Na primeira versão o thread corrente espera indefinidamente peloencerramento da execução do segundo thread. Na segunda e terceira versão othread corrente espera pelo término da execução do segundo thread até nomáximo um período de tempo prefixado. O exemplo IX.8 mostra o como usar ométodo join().

class ThreadComJoin extends Thread { String s; public ThreadComJoin(String as) { super(); s = new String(as); } public void run() { for (int i = 0; i < 10; i++) System.out.println(i+” “+s); System.out.println("Fim do thread!"); }}

public class TestaJoin{ public static void main(String args[]) {

ThreadComJoin t1 = new ThreadComJoin(args[0]);t1.start(); // Transição para um estado ativot1.join(); // Espera pelo término do threadSystem.out.println("Fim do programa!");

}}

Exemplo IX.8 – Uso do método join().

stop(), suspend(), resume() e destroy()

A partir da versão 1.2 do SDK os métodos stop(), suspend(), andresume() tornaram-se deprecated uma vez que a utilização desses métodostendia a gerar erros. No entanto, devido a grande quantidade de código que aindautiliza estes método, acreditamos que seja importante mencioná-los.

O método stop() é um método de instância que encerra a execução dothread ao qual pertence. Os recursos alocados ao thread são liberados. Érecomendável substituir o método stop() pelo simples retorno do métodorun().

Page 271: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

270

O método suspend() é um método de instância que suspende aexecução do thread ao qual pertence. Nenhum recurso é liberado, inclusive osmonitores que possuir no momento da suspensão (os monitores serão vistos maisadiante e servem para controlar o acesso à variáveis compartilhadas). Isto fazcom que o método suspend() tenda a ocasionar deadlocks. O métodoresume() é um método de instância que reassume a execução do thread ao qualpertence. Os métodos suspend() e resume() devem ser substituídosrespectivamente pelos métodos wait() e notify(), como veremos maisadiante.

O método destroy() é um método de instância que encerra a execuçãodo thread ao qual pertence. Os recursos alocados ao thread não são liberados.Não é um método deprecated mas é recomendável substituí-lo pelo simplesretorno do método run().

Daemon Threads

Daemon threads são threads que rodam em background com a função deprover algum serviço mas não fazem parte do propósito principal do programa.Quando só existem threads do tipo daemon o programa é encerrado. Umexemplo de daemon é o thread para coleta de lixo.

Um thread é definido como daemon por meio do método de instânciasetDaemon(). Para verificar se um thread é um daemon é usado o método deinstância isDaemon(). O exemplo IX.9 mostra o como usar esses métodos.

import java.io.*;class ThreadDaemon extends Thread{ public ThreadDaemon() { setDaemon(true); start(); } public void run() { for(;;) yield(); }}

public class TestaDaemon{

Page 272: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

271

public static void main(String[] args) { Thread d = new ThreadDaemon(); System.out.println("d.isDaemon() = " + d.isDaemon()); BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Digite qualquer coisa"); try { stdin.readLine(); } catch(IOException e) {} }}

Exemplo IX.9 – Uso dos métodos relacionados com daemons.

No exemplo IX.9 o método main() da classe TestaDaemon cria umobjeto da classe ThreadDaemon. O construtor da classe ThreadDaemondefine o thread como daemon por meio do método setDaemon() e inicia aexecução do thread. Como é apenas um thread de demonstração o método run()da classe ThreadDaemon não faz nada, apenas liberando a posse da CPU todavez que a adquire. Após a criação da instância da classe ThreadDaemon nométodo main() é testado se o thread criado é um daemon, utilizando para essefim o método isDaemon(). Depois disso o programa simplesmente espera ousuário pressionar a tecla <enter>. O programa termina logo em seguida aoacionamento da tecla, mostrando dessa forma que o programa permanece ativoapenas enquanto existem threads não daemons ativos.

Influência do Sistema Operacional no Comportamentodos Threads

Apesar da linguagem Java prometer a construção de programasindependentes de plataforma operacional, o comportamento dos threads pode serfortemente influenciado pelo sistema operacional subjacente. Portanto, oprogramador deve tomar alguns cuidados se deseja construir programas quefuncionem da mesma forma, independente do ambiente onde está sendoexecutado.

Page 273: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

272

Alguns sistemas operacionais não oferecem suporte a execução dethreads. Neste caso, cada processo possui apenas um thread. Mesmo em sistemasoperacionais que oferecem suporte a execução de múltiplos threads por processoo projetista da máquina virtual pode optar por não usar o suporte nativo athreads. Deste modo, é responsabilidade da máquina virtual criar um ambientemultithread. Threads implementados desta forma, a nível de usuário, sãochamados de green-threads.

As influências da plataforma operacional podem agrupadas em doistipos:

1) Forma de escalonamento de threads. O ambiente pode adotar umescalonamento não preemptivo ou preemptivo. No escalonamentonão preemptivo (também chamado de cooperativo) um thread emexecução só perde o controle da CPU (Central Processing Unit) se aliberar voluntariamente ou se necessitar de algum recurso que aindanão está disponível. Já no escalonamento preemptivo, além dasformas acima um thread pode perde o controle da CPU por eventosexternos, como o fim do tempo máximo definido pelo ambiente paraa execução contínua de um thread (fatia de tempo) ou porque umthread de mais alta prioridade está pronto para ser executado.Exemplos de sistemas operacionais não preemptivos são Windows3.1 e IBM OS/2. Exemplos de sistemas operacionais preemptivos sãoWindows 95/98/NT e Linux, QNX, e muitos outros. Alguns sistemasoperacionais adotam uma abordagem híbrida, suportando tanto omodelo cooperativo como o preemptivo, como o Solaris da Sun.

2) Relacionamento entre os níveis de prioridades definidas nalinguagem Java e os níveis de prioridades definidas nos SistemasOperacionais. Em um SO preemptivo um thread de umadeterminada prioridade perde a posse da CPU para um thread deprioridade mais alta que esteja pronto para ser executado. Alinguagem Java prevê dez níveis de prioridades que podem seratribuídas aos threads. No entanto, cada SO possui um número deprioridades diferente e o mapeamento das prioridades da linguagemJava para as prioridades do SO subjacente pode influenciar ocomportamento do programa.

Forma de escalonamento de threads

Page 274: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

273

A especificação da máquina virtual Java determina que a forma deescalonamento de threads seja preemptiva. Portanto, mesmo em ambienteoperacionais cooperativos a máquina virtual deve garantir um escalonamentopreemptivo. No entanto, um escalonamento preemptivo não obriga a preempçãopor fim de fatia de tempo. Podemos ter um escalonamento preemptivo onde umthread de mais alta prioridade interrompe o thread que tem a posse da CPU masnão existe preempção por fim de fatia de tempo. Um escalonamento ondethreads de mesma prioridade intercalam a posse da CPU por força do fim dafatia de tempo é chamado de escalonamento Round-Robin. A especificação damáquina virtual Java não prevê o escalonamento Round-Robin, mas também nãoo descarta, abrindo uma possibilidade de implementações distintas de máquinavirtual e introduzindo o não determinismo na execução de programasmultithread. Por exemplo, o exemplo IX.3 poderia ter uma saída distinta daapresentada anteriormente caso seja executado por uma máquina virtual que nãoimplementa o escalonamento Round-Robin. Nesse caso a saída seria a seguinte:

0 Linha21 Linha22 Linha23 Linha24 Linha2FIM! Linha20 Linha11 Linha12 Linha13 Linha14 Linha1FIM! Linha1

Neste caso, se o programador deseja que a execução de threads seprocesse de forma alternada, independentemente da implementação da máquinavirtual, então é necessário que ele insira código para a liberação voluntária daCPU. Isso pode ser feito com o método yield() ou com o método sleep().

Relacionamento entre os níveis de prioridades definidas nalinguagem Java e os níveis de prioridades definidas nos SistemasOperacionais.

Como já dissemos a linguagem Java prevê dez níveis de prioridades quepodem ser atribuídas aos threads. Na verdade são onze prioridades, mas aprioridade nível 0 é reservada para threads internos. As prioridades atribuídas

Page 275: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

274

aos threads são estáticas, ou seja não se alteram ao longo da vida do thread, anão ser que por meio de chamadas a métodos definidos para esse propósito. Aclasse thread possui variáveis públicas finais com valores de prioridadepredefinidos, como mostrado na tabela IX.4. No entanto, os sistemasoperacionais podem possuir um número maior ou menor de níveis deprioridades. Vamos citar um exemplo: o MSWindows 95/98/NT. Este sistemapossui apenas sete níveis de prioridades e estes sete níveis devem ser mapeadospara os onze níveis de prioridades especificados em Java. Cada máquina virtualfará este mapeamento de modo diferente, porém a implementação comum émostrada na tabela IX.5.

Prioridades Java Prioridades MSWindows0 THREAD_PRIORITY_IDLE1(Thread.MIN_PRIORITY) THREAD_PRIORITY_LOWEST2 THREAD_PRIORITY_LOWEST3 THREAD_PRIORITY_BELOW_NORMAL4 THREAD_PRIORITY_BELOW_NORMAL5(Thread.NORM_PRIORITY) THREAD_PRIORITY_NORMAL6 THREAD_PRIORITY_ABOVE_NORMAL7 THREAD_PRIORITY_ABOVE_NORMAL8 THREAD_PRIORITY_HIGHEST9 THREAD_PRIORITY_HIGHEST10(Thread.MAX_PRIORITY) THREAD_PRIORITY_TIME_CRITICAL

Tabela IX.5 –Mapeamento das prioridades de Java para MSWindows.

Note que nesta implementação níveis de prioridades diferentes em Javaserão mapeados para um mesmo nível de prioridade em MSWindows. Isto podelevar a resultados inesperados caso o programador projete uma aplicaçãoesperando, por exemplo, que um thread de prioridade 4 irá interromper umthread de prioridade 3. Para evitar este tipo de problema o programador podeadotar dois tipos de abordagem:

1) utilizar, se for possível, apenas as prioridades Thread.MIN_PRIORITY,Thread.NORM_PRIORITY e Thread.MAX_PRIORITY para atribuir prioridadesaos threads; ou

2) não se basear em níveis de prioridades para definir o escalonamento dethreads, utilizando, alternativamente, primitivas de sincronização que serãoabordadas na próxima seção.

Page 276: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

275

Compartilhamento de Memória e Sincronização

Como já foi dito, mais de um thread pode ser criado sobre um mesmoobjeto. Neste caso cuidado especiais devem ser tomados, uma vez que os threadscompartilham as mesmas variáveis e problemas podem surgir se um thread estáatualizando uma variável enquanto outro thread está lendo ou atualizando amesma variável. Este problema pode ocorrer mesmo em threads que executamsobre objetos distintos, já que os objetos podem possuir referências para ummesmo objeto. O exemplo IX.8 mostra a execução de dois threads sobre ummesmo objeto. O nome do thread é usado para que o thread decida que açãotomar. O thread de nome “um” ontem um número de 0 a 1000 geradoaleatoriamente e o coloca na posição inicial de um array de dez posições. Asoutras posições do array são preenchidas com os nove números inteirosseguintes ao número inicial. O thread de nome “dois” imprime o conteúdo dovetor. Obviamente o programa é apenas ilustrativo, não possuindo aplicaçãoprática. A intenção inicial do projetista é obter na tela sequências de deznúmeros inteiros consecutivos iniciados aleatoriamente. No entanto, como osdois threads compartilham o mesmo objeto e não existe qualquer sincronismoentre sí, é pouco provável que o projetista obtenha o resultado esperado.

public class CalcDez implements Runnable{ private int vetInt[];

public CalcDez () {vetInt=new int[10]; } public void run() { if (Thread.currentThread().getName().equals(”um”)) for (;;) { vetInt[0] = (int)(Math.random() * 1000); for (int i=1;i<10;i++) vetInt[i]= vetInt[0]+i; } else for (;;) { System.out.println(“Serie iniciada por”+ vetInt[0]); for (int i=1;i<10;i++) System.out.println(vetInt[i]+ “ “); }

} public static void main(String args[]) {

Page 277: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

276CalcDez ob = new CalcDez();Thread t1 = new Thread(ob,”um”);Thread t2 = new Thread(ob,”dois”);t1.start();t2.start();

}}

Exemplo IX.8 – Dois threads executando sobre o mesmo objeto.

Se a máquina virtual não implementar um escalonamento Round-Robinapenas um thread será executado, visto que os dois threads possuem a mesmaprioridade.

Já no caso da máquina virtual implementar um escalonamento Round-Robin a alternância da execução dos threads produzirá resultados imprevisíveis.Um trecho de uma das saídas possíveis pode ser visto na figura IX.4. Ele foiobtido em Pentium 100MHz executando a máquina virtual da Sun, versão 1.2,sob o sistema operacional MSWindows 95.

258259Serie iniciada por573574575576577578579580581582Serie iniciada por808182

Figura IX.4 – Saída do exemplo IX.8.

Podemos notar as sequências estão misturadas, mostrando que cadathread interrompe o outro no meio da execução da tarefa especificada. O mesmoproblema pode mesmo em threads que executam sobre objetos diferentes,bastando que cada thread possua referência para um mesmo objeto. O exemploIX.9 mostra a execução de dois threads sobre objetos distintos.

Page 278: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

277

class Compartilhada{ private int vetInt[]; public Compartilhada() {vetInt=new int[10];} public void setVal() { for (;;) { vetInt[0] = (int)(Math.random() * 1000); for (int i=1;i<10;i++) vetInt[i]= vetInt[0]+i; } } public int getVal(int i) {return vetInt [i];}}

public class CalcDez2 extends Thread{ private Compartilhada obj; private int tipo;

public CalcDez2 (Compartilhada aObj, int aTipo) { obj = aObj; tipo = aTipo;} public void run() { for (;;) if (tipo==1) obj.setVal(); else { System.out.println(“Serie iniciada por”+ obj.getVal(0)); for (int i=1;i<10;i++) System.out.println(obj.getVal(i)+ “ “); }

} public static void main(String args[]) { Compartilhada obj = new Compartilhada();

CalcDez2 t1 = new CalcDez2(obj,1);CalcDez2 t2 = new CalcDez2(obj,2);t1.start();t2.start();

}}

Exemplo IX.9 – Dois threads executando sobre objetos distintos.

Page 279: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

278

É importante que o leitor não confunda o exemplo IX.9 com o exemploIX.8 achando que nos dois exemplos os dois threads executam sobre o mesmoobjeto, uma vez que a etapa da criação dos threads é bem parecida. No entanto,no exemplo IX.9 foi declarada uma subclasse da classe Thread e não umaclasse que implementa a interface Runnable. Apesar de parecer que noexemplo IX.9 ambos os threads executaram sobre um mesmo objeto da classeCompartilhada que é passado como argumento, na verdade cada threadexecutará sobre sua própria instância da classe CalcDez2, sendo que o objetoda classe Compartilhada é referenciado pelos dois threads. Ocomportamento do código do exemplo IX.9 é semelhante ao do exemplo IX.8,com a diferença que no primeiro a sequência de inteiros é encapsulado peloobjeto da classe Compartilhada.

Este tipo de situação, onde o resultado de uma computação depende daforma como os threads são escalonados, é chamada de condições de corrida(Race Conditions). É um problema a ser evitado uma vez que o programa passaa ter um comportamento não determinístico.

Atomicidade de Instruções e Sincronização do Acesso à SessõesCríticas

A condição de corrida ocorre porque os acesso à áreas de memóriacompartilhada não é feita de forma atômica, e nem de forma exclusiva. Porforma atômica queremos dizer que o acesso é feito por meio de várias instruçõese pode ser interrompido por outro thread antes que toda as instruções quecompõem o acesso sejam executadas. Por forma exclusiva queremos dizer queum thread podem consultar/atualizar um objeto durante a consulta/atualização domesmo objeto por outros threads. Poucas operações são atômicas em Java. Emgeral, as atribuições simples, com exceção dos tipos long e double, sãoatômicas, de forma que o programador não precisa se preocupar em serinterrompido no meio de uma operação de atribuição. No entanto, no caso deoperações mais complexas sobre variáveis compartilhadas é preciso que oprogramador garanta o acesso exclusivo a essas variáveis. Os trechos de códigoonde é feito o acesso às variáveis compartilhadas são chamados de SeçõesCríticas ou Regiões Críticas.

Uma vez determinada uma região crítica como garantir o acessoexclusivo? A linguagem Java permite que o programador garanta o acessoexclusivo por meio utilizando o conceito de monitor. O conceito de monitor foiproposto por C. A. R. Hoare em 1974 e pode ser encarado como um objeto que

Page 280: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

279

garante a exclusão mútua na execução dos procedimentos a ele associados. Ouseja, apenas um procedimento associado ao monitor pode ser executado em umdeterminado momento. Por exemplo, suponha que dois procedimentos A e Bestão associados a um monitor. Se no momento da invocação do procedimento Aalgum o procedimento B estiver sendo executando o processo ou thread queinvocou o procedimento A fica suspenso até o término da execução doprocedimento B. Ao término do procedimento B o processo que invocou oprocedimento A é “acordado” e sua execução retomada.

O uso de monitores em Java é uma variação do proposto por Hoare. nalinguagem Java todo objeto possui um monitor associado. Para facilitar oentendimento podemos encarar o monitor como um detentor de um “passe”.Todo thread pode pedir “emprestado” o passe ao monitor de um objeto antes derealizar alguma computação. Como o monitor possui apenas um passe, apenasum thread pode adquirir o passe em um determinado instante. O passe tem queser devolvido para o monitor para possibilitar o empréstimo do passe a outrothread. A figura IX.5 ilustra essa analogia.

Page 281: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

280

Instante 1: o thread t1 solicita Instante 2: o thread t2 solicita o passe ao monitor o passe ao monitor do objeto x. do objeto x e é

bloqueado.

Instante 3: o thread t1 libera Instante 4: o thread t2 recebe o passe. o passe do monitor

do objeto x.

Figura IX.5 – Uma possível sequência na disputa de dois threads pelaautorização de um monitor.

Nos resta saber como solicitar o passe ao monitor. Isto é feito por meioda palavra chave synchronized. Existem duas formas de se usar a palavrachave synchronized: na declaração de métodos e no início de blocos. Oexemplo IX.10 mostra duas versões da classe FilaCirc que implementa umafila circular de valores inteiros: uma com métodos synchronized e outracom blocos synchronized. Um objeto desta classe pode ser compartilhadopor dois ou mais threads para implementar o exemplo clássico de concorrênciado tipo produtor/consumidor.

Objeto x

Monitor de x$passe

thread t1 $

$

thread t2

Monitor de x$

Monitor de x

Monitor de x

Objeto x

Objeto x Objeto x

Page 282: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

281

a) Versão com métodossynchronized

b) Versão com blocossynchronized

class FilaCirc{ private final int TAM = 10; private int vetInt[]; private int inicio, total;

public FilaCirc() { vetInt=new int[TAM]; inicio=0; total =0; } public synchronized void addElement(int v) throws Exception { if (total == TAM) throw new Exception("Fila cheia!"); vetInt[(inicio+total)%TAM] = v; total++; } public synchronized int getElement() throws Exception { if (total == 0 ) throw new Exception("Fila vazia!"); int temp = vetInt[inicio]; inicio = (++inicio)%TAM; total--; return temp; }}

class FilaCirc{ private final int TAM = 10; private int vetInt[]; private int inicio, total;

public FilaCirc() { vetInt=new int[TAM]; inicio=0; total =0; } public void addElement(int v) throws Exception { synchronized(this) { if (total == TAM) throw new Exception("Fila cheia!"); vetInt[(inicio+total)%TAM] = v; total++; } } public int getElement() throws Exception { synchronized(this) { if (total == 0 ) throw new Exception("Fila vazia!"); int temp = vetInt[inicio]; inicio = (++inicio)%TAM; total--; } return temp; }}

Exemplo IX.10 – Duas versões de uma classe que implementa uma fila circularde inteiros.

A palavra chave synchronized na frente dos métodos de instânciasignifica que o método será executado se puder adquirir o monitor do objeto aquem pertence o método4. Caso contrário o thread que invocou o método serásuspenso até que possa adquirir o monitor. Este forma de sincronização éabordada no exemplo IX.10.a. Portanto, se algum thread chamar algum métodode um objeto da classe FilaCirc nenhum outro thread que compartilha omesmo objeto poderá executar um método do objeto até que o método chamado 4 Não usaremos mais a analogia com a aquisição do passe do monitor. Ela foi usada apenas parafacilitar o entendimento do leitor. Quando se trata de monitores os termos mais usados são:“adquirir o monitor” e “liberar o monitor”.

Page 283: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

282

pelo primeiro thread termine. Caso outro thread invoque um método do mesmoobjeto ficará bloqueado até que possa adquirir o monitor.

O leitor pode estar se perguntando sobre a necessidade de sincronizar osmétodos da classe FilaCirc uma vez que ocorrem apenas atribuições simplesa elementos individuais de um vetor e as atribuições de inteiros são atômicas. Defato o problema ocorre não na atribuição dos elementos e sim na indexação doarray. Por exemplo, a instrução

inicio = (++inicio)%TAM;

do método getElement() não é atômica. Suponha que a os métodos daclasse FilaCirc não são sincronizados e que as variáveis inicio e totalpossuem os valores 9 e 1 respectivamente. Suponha também que thread invocouo método getElement() e foi interrompido na linha de código mostradaacima após o incremento da variável inicio mas antes da conclusão da linhade código. Nesse caso o valor de inicio é 10. Se neste instante outro threadexecutar o método getElement() do mesmo objeto ocorrerá uma exceçãoIndexOutOfBoundsException ao atingir a linha de código

int temp = vetInt[inicio];

Se alterarmos a linha de código para

inicio = (inicio+1)%TAM;

evitaremos a exceção, mas não evitaremos o problema de retornar mais de umavez o mesmo elemento. Por exemplo, se um thread for interrompido no mesmolocal do caso anterior, outro thread pode obter o mesmo elemento, uma vez queos valores de inicio e total não foram alterados. Na verdade o número desituações problemáticas, mesmo para esse exemplo pequeno, é enorme eperderíamos muito tempo se tentássemos descreve-las em sua totalidade.

Em alguns casos pode ser indesejável sincronizar todo um método, oupode-se desejar adquirir o monitor de outro objeto, diferente daquele a quempertence o método. Isto pode ser feito usando a palavra chave synchronizedna frente de blocos. Este forma de sincronização é mostrada no exemploIX.10.b. Neste modo de usar a palavra-chave synchronized é necessárioindicar o objeto do qual tentara-se adquirir o monitor. Caso o monitor sejaadquirido o bloco é executado, caso contrário o thread é suspenso até que possaadquirir o monitor. O monitor é liberado no final do bloco.

Page 284: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

283

No exemplo IX.10.b o monitor usado na sincronização é o do próprioobjeto do método, indicado pela palavra chave this. Qualquer outro objetoreferenciável no contexto poderia ser usado. O que importa que os grupos dethreads que possuem áreas de código que necessitam de exclusão mútua usem omesmo objeto.

No exemplo IX.10 não existe vantagem da forma de implementação a)sobre a forma de implementação b) ou vice-versa. Isso ocorre principalmentequando os métodos são muito pequenos ou não realizam computações muitocomplexas. No entanto, se o método for muito longo ou levar muito tempo paraser executado, sincronizar todo o método pode “travar” em demasia a execuçãoda aplicação. Nesses casos, a sincronização somente das seções críticas é maisindicada. Outra vantagem da segunda forma de sincronização é a liberdade nouso de monitores qualquer objeto referenciável. Isto permite a implementaçãosincronizações mais complexas como veremos mais adiante.

O exemplo IX.11 mostra como pode ser usado um objeto da classeFilaCirc.

public class TestaFilaCirc extends Thread { private FilaCirc obj; private int tipo;

public TestaFilaCirc (FilaCirc aObj, int aTipo) { obj = aObj; tipo = aTipo;} public void run() { for (;;) try { if (tipo==1){ int i = (int)(Math.random() * 1000); System.out.println("Elemento gerado:"+i); obj.addElement(i); } else System.out.println("Elemento obtido:"+obj.getElement()); } catch(Exception e) {System.out.println(e.getMessage());} } public static void main(String args[]) { FilaCirc obj = new FilaCirc(); TestaFilaCirc t1 = new TestaFilaCirc(obj,1); TestaFilaCirc t2 = new TestaFilaCirc(obj,2); t1.start(); t2.start(); }}

Exemplo IX.11 – Uso da fila circular de inteiros.

Um trecho possível da saída obtida na execução do programa do exemploIX.11 seria o seguinte:...Elemento obtido:154

Page 285: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

284

Elemento gerado:725Fila vazia!Elemento gerado:801Elemento obtido:725Elemento gerado:204Elemento obtido:801...

É importante observar que o monitor em Java por si só não implementa aexclusão mútua. Ele é apenas um recurso que pode ser usado pelo programadorpara implementar o acesso exclusivo à variáveis compartilhadas. Cabe aoprogramador a responsabilidade pela uso adequado deste recurso. Por exemplose o programador esquecer de sincronizar um bloco ou método que necessita deexclusão mútua, de nada adianta ter sincronizado os outros métodos ou blocos.O thread que executar o trecho não sincronizado não tentará adquirir o monitor,e portanto de nada adianta os outros threads terem o adquirido.

Outro ponto que é importante chamar a atenção é ter o cuidado de usar apalavra chave synchronized com muito cuidado. A sincronização custamuito caro em se tratando de ciclos de CPU. A chamada de um métodosincronizado é por volta de 10 vezes mais lenta do que a chamada de um métodonão sincronizado. Por essa razão use sempre a seguinte regra: não sincronize oque não for preciso.

Comunicação entre Threads: wait() e notify()

O exemplo IX.10 não é um modelo de uma boa implementação deprograma. O thread que adiciona elementos à fila tenta adicionar um elemento àcada volta do laço de iteração mesmo que a fila esteja cheia. Por outro lado, othread que retira os elementos da fila tenta obter um elemento a cada volta dolaço de iteração mesmo que a fila esteja vazia. Isto é um desperdício de tempode processador e pode tornar o programa bastante ineficiente.

Alguém poderia pensar em uma solução onde o thread testaria se acondição desejada para o processamento ocorre. Caso a condição não ocorra othread poderia executar o método sleep() para ficar suspenso por algumtempo para depois testar novamente a condição. O thread procederia desta formaaté que a condição fosse satisfeita. Este tipo de procedimento economizariaalguns ciclos de CPU, evitando que a tentativa incessante de executar oprocedimento mesmo quando não há condições. O nome desta forma de ação,

Page 286: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

285

onde o procedimento a cada intervalo de tempo pré-determinado testa se umacondição é satisfeita é chamado de espera ocupada (pooling ou busy wait).

No entanto, existem alguns problemas com este tipo de abordagem.Primeiramente, apesar da economia de ciclos de CPU ainda existe apossibilidade de ineficiência, principalmente se o tempo não for bem ajustado.Se o tempo for muito curto ocorrerá vários testes inúteis. Se for muito longo, othread ficará suspenso além do tempo necessário. Porém, mais grave que isto éque o método sleep() faz com que o thread libere o monitor. Portanto, se otrecho de código for uma região sincronizada, como é o caso do exemplo IX.10,de nada adiantará o thread ser suspenso. O thread que é capaz de realizar acomputação que satisfaz a condição esperada pelo primeiro thread ficaráimpedido de entrar na região crítica, ocorrendo assim um deadlock: o thread quedetém o monitor espera que a condição seja satisfeita e o thread que podesatisfazer a condição não pode prossegui porque não pode adquirir o monitor.

O que precisamos é um tipo de comunicação entre threads quecomunique que certas condições foram satisfeitas. Além disso, é preciso que, aoesperar por determinada condição, o thread libere o monitor. Esta forma deinteração entre threads é obtido em Java com o uso dos métodos de instânciawait(), notify() e notifyAll(). Como vimos anteriormente, essesmétodos pertencem à classe Object e não à classe Thread. Isto ocorre porqueesses métodos atuam sobre os monitores, que são objetos relacionados a cadainstância de uma classe Java e não sobre os threads.

Ao invocar o método wait() de um objeto o thread é suspenso einserido em uma fila do monitor do objeto, permanecendo na fila até receberuma notificação. Cada monitor possui sua própria fila. Ao invocar o métodonotify() de um objeto, um thread que está na fila do monitor do objeto énotificado. Ao invocar o método notifyAll() de um objeto, todos os threadsque estão na fila do monitor do objeto são notificados.

A única exigência é que esses métodos sejam invocados em um threadque detenham a posse do monitor do objeto a que pertencem. Essa exigência fazsentido uma vez que eles sinalizam a threads que esperam na fila dessesmonitores. Devido a essa exigência a invocação desses métodos ocorre emmétodos ou blocos sincronizados. O exemplo IX.12 mostra as formas maiscomuns de chamadas desses métodos.

Note que o thread deve possuir o monitor do objeto ao qual pertence ométodo. Por isso, nos exemplo IX.12 b e c, o objeto sincronizado no bloco é omesmo que invoca os métodos notify() e notifyAll().

a) b)class X class Y

Page 287: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

286{ ... public synchronized int ma() { ... // Espera uma condição while(!cond) wait(); // Prossegue com a // condição satisfeita ... } ...}

{ X ob; ... public int mb() { ... synchronized (ob) { // Notifica algum thread ob.notify(); ... } ...}

c)class Z{ X ob; ... public int mc() { ... synchronized (ob) { // Notifica todos os threads que esperam na fila // do monitor de ob ob.notifyAll(); ... } ...}

Exemplo IX.12 – Exemplos de chamadas dos métodos wait(), notify() enotifyAll().

Outra observação importante é que o thread que invoca o métodowait() o faz dentro de um laço sobre a condição de espera. Isto ocorre porqueapesar de ter sido notificado isto não assegura que a condição está satisfeita. Othread pode ter sido notificado por outra razão ou entre a notificação e aretomada da execução do thread a condição pode ter sido novamente alterada.

Uma vez notificado o thread não retoma imediatamente a execução. Épreciso primeiro retomar a posse do monitor que no momento da notificaçãopertence ao thread que notificou. Mesmo após a liberação do monitor nada

Page 288: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

287

garante que o thread notificado ganhe a posse do monitor. Outros threads podemter solicitado a posse do monitor e terem preferência na sua obtenção.

O exemplo IX.12 mostra apenas um esquema para uso dos métodos paranotificação. O exemplo IX.13 é uma versão do exemplo IX.10a que usa osmétodos de notificação para evitar problemas como a espera ocupada. Oexemplo IX.11 pode ser usado sem modificações para testar essa versão.

class FilaCirc{ private final int TAM = 10; private int vetInt[]; private int inicio, total;

public FilaCirc() { vetInt=new int[TAM]; inicio=0; total =0; } public synchronized void addElement(int v) throws Exception { while (total == TAM) wait(); vetInt[(inicio+total)%TAM] = v; total++; notify(); } public synchronized int getElement() throws Exception { while (total == 0 ) wait(); int temp = vetInt[inicio]; inicio = (++inicio)%TAM; total--; notify(); return temp; }}

Exemplo IX.13 – Classe que implementa uma fila circular de inteiros comnotificação.

A necessidade de se testar a condição em loop pode ser observada nafigura IX.6 que mostra a evolução da execução de três threads sobre objetos quecompartilham uma instância da classe FilaCirc. O thread 3 executa o métodoaddElement(), no entanto, em virtude da condição total==TAM éobrigado a invocar o método wait() e esperar uma notificação. O próximo

Page 289: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

288

thread a assumir a CPU é o thread 1 que executa o método getElement(), queestabelece a condição total<TAM e executa um notify(). No entanto, opróximo thread a assumir a CPU é o thread 2 e não o thread 3. O thread 2executa o método addElement(), o qual estabelece novamente a condiçãototal==TAM. Quando o thread 3 assumi novamente a CPU, uma vez que foinotificado, testa a condição e invoca novamente o método wait() para esperara condição favorável à execução. Caso não testasse a condição em um loop othread 3 tentaria inserir um elemento em uma fila cheia.

O método notify() não indica que evento ocorreu. No caso doexemplo IX.13 existem dois tipos de eventos (a fila não está cheia e a fila nãoestá vazia), no entanto, podemos observar que não existe a possibilidade de umthread ser notificado em decorrência de um evento diferente do que estáaguardando.

Tempo

Figura IX.6 – Uma possível sequência na execução de três threads.

Porém, existem alguns casos mais complexos onde podem existir váriosthreads aguardando em um mesmo monitor mas esperando por evento diferentes.Neste caso podemos usar o notifyAll() para notificar todos os threads queesperam em um único monitor que um evento ocorreu. Cada thread, a medidaque fosse escalado, testaria se ocorreu condição para a execução e em casopositivo prosseguiria na execução e em caso contrário voltaria a aguardar nomonitor.

O exemplo IX.14 mostra o código de um gerenciador de mensagens. Eleé responsável por receber mensagens destinadas à vários threads. As mensagens

thread 3

thread 2

thread 1

Método: addElement() condição: total == TAM

Método: getElement()

Método: addElement()condição: total < TAM

Executando Esperando CPU Esperando notificação

Page 290: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

289

de cada thread são colocadas em uma fila implementada por um objeto da classeVector. Cada fila é por sua vez colocada em uma tabela hash onde a chave éum nome associado ao thread a que as mensagens se destinam. As filas sãocriadas na primeira tentativa de acesso, tanto na leitura quanto noarmazenamento. Não existe bloqueio devido à fila cheia, uma vez que as filassão implementadas por objetos da classe Vector que crescem conforme anecessidade. Portanto, o único evento que necessita ser notificado é a chegada dealguma mensagem. Como todos os threads aguardam sobre o mesmo monitor éusado o método notifyAll() para notificar todos os threads.

import java.util.*;

class GerenteMen { private Hashtable tamMen;

public GerenteMen() {tamMen=new Hashtable(); }

// Método para adicionar uma mensagem à fila de // um destinatário public synchronized void addMen(String dest, String men){ if (dest==null || men==null) return; Vector listaMen = (Vector) tamMen.get(dest); if (listaMen==null) listaMen = new Vector(); listaMen.addElement(men); tamMen.put(dest, listaMen); notifyAll(); }

// Método para obtenção da mensagem public synchronized String getMen(String dest) throws Exception { if (dest==null) return null; Vector listaMen = (Vector) tamMen.get(dest);

// Se não existe a fila para esse thread cria uma vazia if (listaMen==null) { listaMen = new Vector(); tamMen.put(dest, listaMen); } // A fila está vazia, portanto thread deve esperar // a chegada de mensagens while(listaMen.size()==0) wait(); String temp = (String) listaMen.firstElement();

Page 291: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

290 // A mensagem é removida da fila listaMen.removeElementAt(0); return temp; }}

Exemplo IX.14 – Gerenciador de mensagens.

O exemplo IX.15 mostra como pode ser usado o gerente de filas doexemplo IX.14. Devido o uso da classe ThreadGroup assim como vários deseus métodos, resolvemos numerar as linhas de código do exemplo IX.15 paramelhor podermos explicar o seu funcionamento.

12345678910111213141516171819202122232425262728293031323334353637383940414243

class Receptor extends Thread{ private GerenteMen ger; public Receptor(ThreadGroup tg, String nome, GerenteMen aGer) { super(tg,nome); ger = aGer; } public void run() { String nome = Thread.currentThread().getName(); for (;;) try { String men = ger.getMen(nome); if (men.equals("fim")) return; System.out.println(nome+">Mensagem recebida:"+men); } catch(Exception e) {System.out.println(e.getMessage());} }}

class Gerador extends Thread{ private GerenteMen ger; public Gerador(ThreadGroup tg, String nome, GerenteMen aGer) { super(tg,nome); ger = aGer; } public void run() { String nome = Thread.currentThread().getName(); ThreadGroup tg = Thread.currentThread().getThreadGroup(); Thread[] tl=null; for (int i=0;i<100;i++) { if (tl==null || tl.length!=tg.activeCount()) tl= new Thread[tg.activeCount()]; tg.enumerate(tl); int n = (int)(Math.random() * 1000)%tl.length; if (tl[n]!= Thread.currentThread()) { System.out.println(nome+">Mensagem enviada para "+ tl[n].getName()+":mensagem "+i); ger.addMen(tl[n].getName(),"mensagem "+i); }

Page 292: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

291444546474849505152535455565758596061626364

} tl= new Thread[tg.activeCount()]; tg.enumerate(tl); for (int i=0;i<tl.length;i++) if (tl[i]!= Thread.currentThread()) ger.addMen(tl[i].getName(),"fim"); }}

public class TestaGerenteMen { public static void main(String args[])throws Exception { GerenteMen ger = new GerenteMen(); ThreadGroup tg = new ThreadGroup("tg"); Receptor r1 = new Receptor(tg,"r_um",ger); Receptor r2 = new Receptor(tg,"r_dois",ger); Gerador g = new Gerador(tg,"g",ger); r1.start(); r2.start(); g.start(); }}

Exemplo IX.15 – Uso do gerenciador de filas.

Um objeto da classe ThreadGroup agrupa um conjunto de threads.Um ThreadGroup pode possuir como membros outros objetos daThreadGroup formando assim uma árvore onde todos os grupos, exceto oprimeiro possui um grupo pai. O objetivo de se agrupar os threads em conjuntosé facilitar a sua manipulação. No caso do exemplo IX.15 usaremos esseagrupamento para poder acessar cada thread.

As linhas 1 a 18 definem a classe que será usada para criação de objetosreceptores de mensagens. Na linha 3 é declarada a variável que irá referenciarum objeto do tipo GerenteMen. As linhas 4 a 8 contém o código do únicoconstrutor da classe. Ele recebe uma referência para o grupo de threads ao qualdeve se associar, o nome que deve ser atribuído ao thread e a referência aogerente de filas. Na linha 6 os primeiros dois parâmetros são passados aoconstrutor da superclasse. Na linha 7 a referência ao gerente de filas é atribuída àvariável da instância. As linhas 9 a 17 contém o código do método run() que éo método de entrada do thread. Na linha 10 é invocado o método

Thread.currentThread().getName();

para se obter o nome do thread corrente. O nome do thread é usado parareferenciar a fila de mensagens do thread. Entre as linhas 11 e 16 é executadoum laço infinito onde o thread recebe e imprime as mensagens recebidas. Nalinha 14 o thread testa se a mensagem recebida é igual a “fim”. Neste caso othread encerra sua execução.

Page 293: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

292

As linhas 20 a 51 definem a classe que será usada para criação do objetogerador de mensagens. Este exemplo foi projetado para lidar com apenas umthread gerador de mensagem. Modificações devem ser realizadas para tratar deaplicações com mais de um thread gerador de mensagens. Na linha 22 édeclarada a variável que irá referenciar um objeto do tipo GerenteMen. Aslinhas 23 a 27 contém o código do único construtor da classe. Ele recebe umareferência para o grupo de threads ao qual deve se associar, o nome que deve seratribuído ao thread e a referência ao gerente de filas. Na linha 25 os primeirosdois parâmetros são passados ao construtor da superclasse. Na linha 26 areferência ao gerente de filas é atribuída à variável da instância. As linhas 28 a50 contém o código do método run() que é o método de entrada do thread. Nalinha 29 é obtido o nome do thread corrente que será usado na impressão demensagens. Na linha 30 o método

Thread.currentThread().getThreadGroup();

obtém uma referência para o grupo de threads ao qual pertence o thread corrente.Na linha 31 é declarada uma variável que irá referenciar um vetor contendoreferências a todos os threads ativos do grupo. Entre as linhas 32 e 44 éexecutado um laço com 100 iterações que produz e armazena as mensagens. Nalinha 34 é realizado um teste para a verificação da necessidade de criar o vetorque irá conter as referências para os threads ativos. Ele deve ser criado aprimeira vez e toda vez que a capacidade do vetor for diferente do número dethreads ativos do grupo. O tamanho do vetor é determinado pelo método deinstância activeCount() da classe ThreadGroup. A linha 36 contém ocódigo

tg.enumerate(tl);

que atribui as referencias aos threads no vetor. O comando

int n = (int)(Math.random()*1000)%tl.length;

da linha 37 calcula um número que será usado para acessar o thread dentro dovetor de referências. O teste da linha 38 impede que seja enviada uma mensagempara o próprio gerador. Essas mensagens são descartadas. As linhas 40 a 42tratam da impressão e envio da mensagem construída. Já fora da iteração, aslinhas 45 a 49 tratam da do envio da mensagem “fim” para todos os threadsreceptores, o que fará com que encerrem sua execução.

Page 294: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

293

As linhas 53 a 64 definem a classe que será usada como ponto de entradada aplicação. Ela é responsável pela criação dos objetos e disparos dos threads.No exemplo, além do thread gerador apenas dois threads receptores são criados.É interessante notar que não é preciso indicara para o thread gerador asreferências para os threads receptores. Elas são obtidas dinamicamente por meiodo grupo de threads.

Um trecho possível da saída obtida na execução do programa do exemploIX.15 seria o seguinte:

...g>Mensagem enviada para r_dois:mensagem 88r_um>Mensagem recebida:mensagem 87g>Mensagem enviada para r_dois:mensagem 90r_dois>Mensagem recebida:mensagem 88g>Mensagem enviada para r_um:mensagem 91r_dois>Mensagem recebida:mensagem 90g>Mensagem enviada para r_um:mensagem 93r_um>Mensagem recebida:mensagem 91g>Mensagem enviada para r_um:mensagem 95r_um>Mensagem recebida:mensagem 93g>Mensagem enviada para r_um:mensagem 96r_um>Mensagem recebida:mensagem 95g>Mensagem enviada para r_um:mensagem 97r_um>Mensagem recebida:mensagem 96g>Mensagem enviada para r_dois:mensagem 99r_um>Mensagem recebida:mensagem 97r_dois>Mensagem recebida:mensagem 99Pressione qualquer tecla para continuar . . .

Otimizando a Programação Multithread

Existe um problema óbvio com a abordagem do exemplo IX.14: amensagem é dirigida a apenas um thread mas todos serão notificados,sobrecarregando o sistema, uma vez que todos os threads precisaram testar se amensagem é destinada a eles. Para contornar esses problema é necessáriovislumbrar uma forma de notificar apenas o thread destinatário.

Essa solução pode ser obtida se cada thread esperar em um monitor deum objeto diferente. Não importa o tipo do objeto desde que seja referenciávelpelo thread receptor e pelo thread que irá armazenar a mensagem. Um candidatonatural é a fila de mensagem de cada thread. Existe uma fila para cada thread e o

Page 295: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

294

thread que armazena a mensagem tem acesso a todas a filas por meio da tabelahash. O exemplo IX.16 mostra uma versão do exemplo IX.14 que utiliza estatécnica para criar uma aplicação multi-thread mais otimizada.

import java.util.*;

class GerenteMen { private Hashtable tamMen;

public GerenteMen() {tamMen=new Hashtable(); }

// Método para adicionar uma mensagem à fila de // um destinatário public void addMen(String dest, String men){ if (dest==null || men==null) return; Vector listaMen = (Vector) tamMen.get(dest); if (listaMen==null) listaMen = new Vector(); synchronized (listaMen) { listaMen.addElement(men); tamMen.put(dest, listaMen); listaMen.notify(); }; }

// Método para obtenção da mensagem public String getMen(String dest) throws Exception { if (dest==null) return null; Vector listaMen = (Vector) tamMen.get(dest);

// Se não existe a fila para esse thread cria uma vazia if (listaMen==null) { listaMen = new Vector(); tamMen.put(dest, listaMen); } // A fila está vazia, portanto thread deve esperar while(listaMen.size()==0) synchronized (listaMen) {listaMen.wait();} String temp = (String) listaMen.firstElement();

// A mensagem é removida da fila listaMen.removeElementAt(0); return temp; }}

Page 296: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

295

Exemplo IX.16 – Gerenciador de mensagens otimizado.

Note que os métodos wait() e notify() invocados pertencem à filarelacionada com cada thread. O exemplo IX.15 pode ser usado semmodificações para testar essa versão.

Criando outros mecanismos de sincronização

Existem várias propostas de primitivas de sincronização. Dentre as maiscomuns podemos citar os semáforos, mutex, variáveis condicionais, monitores eencontros (rendevouz). Cada uma dessas primitivas é mais adequada a umdeterminado propósito. A implementação de monitores na linguagem Java,juntamente com os métodos wait() e notify() que formam um tipo devariáveis condicionais podem ser combinadas para implementar muitas dessasoutras primitivas, de modo a atender objetivos específicos. Para exemplificaressa possibilidade mostraremos como implementar um semáforo usando asprimitivas de sincronização da linguagem Java.

Um semáforo é uma variável inteira sobre a qual pode-se realizar asseguintes operações:

Operação Descriçãoinicializar Um valor inteiro maior ou igual a zero é atribuído ao semáforo.P Se o semáforo é maior que zero, o semáforo é decrementado. Caso

contrário, o thread é suspenso até que o semáforo contenha umvalor maior que zero.

V Incrementa o semáforo e acorda os threads que estiverembloqueados na fila de espera do semáforo.

Tabela IX.6 –Operações sobre um semáforo.

Semáforo é um mecanismo de sincronização muito utilizado quandoexiste a necessidade de comunicação entre dois ou mais processos, como no casode sistemas do tipo produtor/consumidor. Por exemplo, suponha dois processosonde um coloca mensagens em buffer e outro retira as mensagens. Os processospodem usar dois semáforos para sincronizar o acesso ao buffer de mensagens:um para controlar a entrada na região crítica e outro para contar o número demensagens. A figura IX.xx mostra os esquemas dos processos. A implementaçãodos semáforos em Java pode ser visto no exemplo IX.xx e o uso dos semáforos

Page 297: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

296

em uma situação como a ilustrada pela figura IX.xx pode ser visto no exemploIX.xx.

Produtor Consumidor

s=1; n=0;

início loop início loop

Produz mensagem P(n) // Verifica se existe mensagens

P(s) // Verifica se pode entrar na região

// crítica

P(s) // Verifica se pode entrar na região

//crítica

Coloca mensagem no buffer Retira mensagem

V(n) // incrementa no, de mensagens V(s) // sai da região crítica

V(s) // sai da região crítica Consome Mensagem

fim loop fim loop

Figura IX.xx – Comunicação entre processos usando semáforos.

public class Semaforo{ private int cont;

public Semaforo(){cont =0;} public Semaforo(int i){cont =i;}

public synchronized void P() throws InterruptedException { while(cont <=0) this.wait(); cont--; }

public synchronized void V() { cont++; notifyAll(); }}

Exemplo IX.XX – Implementação de um Semáforo.

Page 298: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

297

import java.util.Vector;

class Consumidor extends Thread{ private Vector buff; private Semaforo s,n;

public Consumidor(Vector aBuff, Semaforo as, Semaforo an) { super(); buff = aBuff; s = as; n = an; } public void run() { for (;;) try { n.p(); // Verifica se existe mensagens s.p(); // Verifica se pode entrar na região crítica String men = (String)buff.firstElement(); buff.removeElementAt(0); s.v(); if (men.equals("fim")) return; System.out.println("Mensagem recebida:"+men); } catch(Exception e) {System.out.println(e.getMessage());} }}

class Produtor extends Thread{ private Vector buff; private Semaforo s,n; public Produtor(Vector aBuff, Semaforo as, Semaforo an) { super(); buff = aBuff; s = as; n = an; } public void run() { for (int i=0;i<11;i++) { try { s.p();// Verifica se pode entrar na região crítica if (i<10) { buff.addElement(""+i);

Page 299: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

298 System.out.println("Mensagem enviada: "+ i); } else buff.addElement("fim"); n.v(); // incrementa o número de mensagens s.v(); // abandona a região crítica Thread.yield(); } catch(Exception e) {System.out.println(e.getMessage());} } }}

public class TestaSemaforo{ public static void main(String args[])throws Exception { Vector buff = new Vector(); Semaforo s = new Semaforo(1); Semaforo n = new Semaforo(0); Produtor t1 = new Produtor(buff,s,n); Consumidor t2 = new Consumidor (buff,s,n); t1.start(); t2.start(); }}

Exemplo IX.XX – Uso de semáforos por dois threads.

Page 300: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

299

Capítulo XII - AnimaçãoAnimação é exibir uma figura que muda com o tempo. No momento o

suporte a animação da API central do Java é limitado. Espera-se para o final de1997 uma API que dê suporte avançado para animação. A animação pode sercontrolado por um thread que é executado em um certo intervalo pré-definido.

Exemplo básico de animação “in-place”.

import java.awt.*; import java.applet.Applet;

public class exemplo10 extends Applet implements Runnable{ Image imgs[]; int ind=0; Thread t1;

public void init(){imgs = initImgs(); t1=new Thread(this); t1.start();}

public void paint(Graphics g){g.draw.Image(imgs[ind],0,0,this);}

public void start() {if (t1 == null) { t1 = new Thread(this);

t1.start();} }

public void stop() {if (t1 != null) {t1.stop();t1 = null;}

}

public void run() {while (true){ try {Thread.sleep(100};} catch(InterruptedException ex){} repaint(); ind=++ind % imgs.length;}

}}

Problemas com o exemplo

Page 301: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

300

Ele não permite interromper a animação. O repaint() chama oupdate() default que repinta todo o fundo, o que causa “flicker” na animação.Existe um problema relacionado com a integridade da variável ind. A variável éatualizada pelo Thread t1 (run) e lida pelo Thread update (paint).

permitir interromper a animação.

boolean pause = false;

public boolean mouseDown(Event e, int x, int y){ if (pause) {t1.resume();}

else {t1.suspend();}pause = !pause;return true;

}

Eliminar o “flicker”

Default

public void update(Graphics g){

g.setColor(getBackground());g.fillRect(0,0,width, height);g.setColor(getForeground());paint(g);

}

Mudança

public void update(Graphics g) {paint(g);}

Eliminando conflitos

public synchronized void paint(Graphics g){

g.draw.Image(imgs[ind],0,0,this);}

public synchronized void mudaInd()

Page 302: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

301

{ind = ++ind % imgs.length;

}

Copiando a figura

public void drawStickFigure (Graphics g, int nX, int nY){ g.drawOval (nX + 10, nY + 20, 20, 40); g.drawLine (nX + 20, nY + 60, nX + 20, nY + 100); g.drawLine (nX + 10, nY + 70, nX + 30, nY + 70); g.drawLine (nX + 10, nY + 150, nX + 20, nY + 100); g.drawLine (nX + 20, nY + 100, nX + 30, nY + 150);}public void paint (Graphics g, Applet Parent){ if (bFirstTime) { bFirstTime = false; drawStickFigure (g, nX, nY); } else { g.copyArea (nX, nY, 35, 155, 5, 0);}}

Double-buffer

offScreenImage = createImage (nWidth, nHeight);offScreenGraphic = offScreenImage.getGraphics();

...offScreenGraphic.setColor (Color.lightGray);offScreenGraphic.fillRect (0, 0,nWidth, nHeight);offScreenGraphic.setColor (Color.black);

...offScreenGraphic. drawOval(10,10,20,20); ...g.drawImage (offScreenImage, 0, 0, this);

Ticker-Tape

class TextScrolling extends AnimationObject{ String pcMessage; // The message int nXPos; // The location of the message int nYPos; // The location of the message int nAppletWidth; // The width of the applet int nMessageWidth; // The width of the message

public TextScrolling (String pcMsg, int nWide)

Page 303: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

302{

pcMessage = pcMsg;nAppletWidth = nWide;nMessageWidth = -1;nYPos = -1;nXPos = 0;

}

public void paint (Graphics g, Applet parent){ if (nYPos < 0) {

nYPos = (g.getFontMetrics ()).getHeight ();

char pcChars []; pcChars = new char [pcMessage.length() + 2]; pcMessage.getChars(0, pcMessage.length()- 1, pcChars, 0); nMessageWidth = (g.getFontMetrics ()).charsWidth (pcChars, 0, pcMessage.length()); }

g.drawString (pcMessage, nXPos, nYPos);}public void clockTick (){ if (nMessageWidth < 0) return;

// Move Right nXPos -= 10; if (nXPos < -nMessageWidth)

nXPos = nAppletWidth - 10;}public void run(){ int ndx = 0;

Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

while (size().width > 0 && size().height > 0&& kicker != null)

{AnimatedObjects[0].clockTick ();

repaint(); try {Thread.sleep(nSpeed);}

catch (InterruptedException e){} }}

Page 304: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

303

Capítulo XIII - Programação emrede

Diferentemente das linguagens mais populares atualmente, Java foiprojetada na era da Internet, e por isso mesmo ferramentas para comunicaçãodentro da Grande Rede foram incorporadas à linguagem desde a sua concepção.Classes para manipulação de URLs e dos protocolos que constituem a Internetfazem parte do núcleo básico da linguagem. Isto facilita muito a tarefa dedesenvolver aplicações que para a Internet ou outras redes que fazem uso domesmo conjunto de protocolos. Esta é uma das principais forças da linguagemJava. De modo a entendermos como desenvolver aplicações em rede com Java éimportante o compreensão de alguns conceitos básicos sobre protocolos decomunicação.

Conceitos Sobre Protocolos Usados na Internet

Um protocolo de comunicação é um conjunto de formatos e regrasusadas para transmitir informação. Computadores distintos devem obedecerestas regras e formatos de modo que se possam comunicar. Podemos encarar oprotocolo como a definição de uma linguagem comum de modo a possibilitar acomunicação entre diferentes entidades.

Visando diminuir a complexidade de implementação e uso do protocolo,ele é divido e organizado em forma de camadas de protocolos, onde a camadarelativamente inferior na pilha a outra estabelece as regras para a camadasuperior sobre a utilização de seus serviços. As camadas inferiores fornecemserviços mais básicos de transmissão de dados, enquanto que as camadassuperiores oferecem serviços de mais alto nível. Esta forma de organizaçãohierárquica de protocolos é também chamada de pilha de protocolos.

A principal pilha de protocolo sobre o qual a Internet se organiza é oTCP/IP. Por simplicidade chamaremos a pilha de protocolos TCP/IP apenascomo protocolo TCP/IP ou TCP/IP. A figura XI.1 mostra como se organizamalguns dos protocolos que fazem parte do TCP/IP.

Page 305: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

304

A camada física é a responsável pela transporte efetivo dos dados sobre omeio físico. A camada de rede é responsável pela interface lógica entre oscomputadores. A camada de transporte provê transferência de dados a nível deserviço, e a camada de aplicação provê comunicação a nível de processos ouaplicações. Exemplos de protocolos a nível de aplicação são: FTP, usado paratransferência de arquivos; HTTP, usado para transmissão de páginas Web;TELNET provê capacidade de log-on remoto; SMTP provê serviços básicos decorreio eletrônico; SNMP usado para gerência da rede; e MIME que é umaextensão do SMTP para lidar com mensagens com conteúdos diversos.

Figura XI.1 –Alguns protocolos da pilha TCP/IP.

No processo de transmissão de dados sobre uma rede TCP/IP os dadossão divididos em grupos chamados de pacotes. Cada camada adiciona um algunsdados a mais no início de cada pacote para permitir que o pacote chegue aodestino. Os dados adicionados são chamados de headers.

Ethernet, X.25, Token RingCamada física

IPCamada de rede

UDPTCPCamada de Transporte

SNMPFTP HTTP SMTP TELNET

MIME

Camada de Aplicação

FTP - File Transfer Protocol SMTP - Simple Mail Transfer ProtocolHTTP - Hypertext Transfer Protocol SNMP - Simple Network Management ProtocolIP - Internet Protocol TCP - Transmission Control ProtocolMIME - Multi-purpose Internet Mail Extensions UDP - User Datagram Protocol

Page 306: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

305

Figura XI.2 –Headers adicionados a cada camada de protocolo.

Na camada de transporte existem dois protocolos que fazem uso doprotocolo IP: o protocolo TCP/IP e o UDP.

TCP

O protocolo TCP é um protocolo orientado a conexão que provê umfluxo confiável de dados entre dois computadores. Por protocolo orientado aconexão queremos dizer que é estabelecido um canal de comunicação ponto-a-ponto onde os dados podem trafegar em ambas as direções. O TCP garante queos dados enviados em uma ponta cheguem ao destino, na mesma ordem queforam enviados. Caso contrário, um erro é reportado. Protocolos como HTTP,FTP e TELNET exigem um canal de comunicação confiável e a ordem derecebimento dos dados é fundamental para o sucesso dessas aplicações.

UDP

No entanto, nem todas as aplicações necessitam destas características doprotocolo TCP e o processamento adicional exigido para garantir aconfiabilidade e a ordenação dos dados podem inviabilizá-las. Para esses casosexiste o protocolo de transporte UDP. UDP é um protocolo para envio de

DadosTCPHeader

Dados

Dados Aplicação

DadosTCPHeader

Transporte

TCPHeader

IPHeader

Rede

IPHeader

EthernetHeader

Física

Page 307: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

306

pacotes independentes de dados, chamados de datagramas, de um computador aoutro, sem garantias sobre a chegada dos pacotes. O protocolo UDP não éorientado a conexão.

IDENTIFICAÇÃO DE HOSTS (Número IP)

Cada computador conectado a uma rede TCP/IP é chamado de Host e éidentificado por um único número de 32 bits, denominado de número IP. Onúmero IP é representado por quatro grupos de 8 bits, limitando desta forma ovalor numérico de cada grupo ao valor máximo de 255. Um exemplo de númeroIP é 200.65.18.70. Uma vez que é muito difícil lembrar e atribuir significado anúmeros existe uma forma alternativa de identificar os computadores da rede pormeio de nomes. Um ou mais computadores da rede fazem o papel deresolvedores de nomes, mantendo bases de dados que associam o nomes doHosts à seus números IP. Desta forma é possível um computador comunicar comoutro computador por meio do nome lógico e não por meio do número IP. Afigura XI.3 ilustra a comunicação entre dois computadores. A Internet érepresentada como uma nuvem devido a complexidade da rede.

Figura XI.3 –Representação da comunicação entre dois computadores.

O representação dos nomes dos computadores na Internet é feita porsubstrings separadas por ‘.’ e obedecem uma regra de nomeação que define queo primeiro substring representa o nome da máquina, e os restantes representa odomínio onde está inserida a máquina. Um domínio é um agrupamento decomputadores que pertencem a uma instituição, órgão, empresa, ou umaorganização qualquer. Assim, no exemplo da figura XI.3 o computadormeucomp pertence ao domínio com.br. No Brasil a FAPESP (Fundação de

Host meucomp.com.brIP: 200.18.46.12

Host outrocomp.eduIP: 205.50.30.75

Page 308: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

307

Amparo à Pesquisa do Estado de São Paulo) responsável pela gerência dosnomes dos domínios na Internet.

Identificação de Processos (Portas)

A comunicação entre dois processos em uma rede TCP/IP é assimétrica,no sentido um processo faz o papel de servidor, oferecendo um serviço e outrofaz o papel de cliente do serviço. Em um único Host vários processos podemestar fazendo o papel de servidor, oferecendo serviços através de um único meiofísico. Portanto, é preciso uma forma de identificar as servidores em um mesmoHost. Isto é feito por meio da associação de um número inteiro, chamado deporta, ao processo servidor. Essa associação é feita pelo processo assim que écarregado, por meio de uma chamada ao sistema. O número da porta pode variarde 1 a 65535, no entanto os números de 1 a 1023 são reservados para serviçosconhecidos como FTP e HTTP. O programador não deve usar estas portas a nãoser que esteja implementando algum desses serviços. Nos ambientes Unix asportas que vão de 6000 a 6999 são usadas pelo gerenciador de Interfaces XWindows e 2000 a 2999 por outros serviços, como o NFS. Nestes ambientes,estas faixas de números de portas também devem ser evitadas. A tabela XI.1mostra o número da porta de alguns dos serviços mais conhecidos.

Protocolo PortaHTTP 80echo 7FTP 20,21SMTP 25Finger 79Daytime 13pop3 110

Tabela XI.1 – Número das portas dos principais serviços.

Uma vez associado a uma porta o serviço pode ser acessado por umaaplicação cliente, bastando para isso que ela indique o nome do Host e o númeroda porta ao se comunicar.

Page 309: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

308

Programação em Rede com Java

O pacote java.net contém as classes e interfaces usadas paraprogramação de sistemas em rede com Java. As classes podem ser enquadradasem três categorias:

1. Classes para comunicação básica em rede. Tratam da comunicaçãoem baixo nível entre aplicações. Outros protocolos podem serimplementados usando como base esta comunicação básica.

2. Classes para comunicação dentro da Web. Estas classes provêemfacilidades para acessar conteúdos por meio de URLs.

3. Classes para tratamento dos formatos estendidos da Web. Utilizadaspara tratar novos protocolos e tipos MIME.

Comunicação Básica Entre Aplicações

As classes Socket, ServerSocket, DatagramSocket,DatagramPacket e InetAddress, fornecem os métodos necessários paraa comunicação básica entre dois processos. A tabela XI.2 descreve sucintamentecada uma das classes.

Classe DescriçãoSocket Provê um socket cliente para comunicação orientada à

conexão via protocolo TCP.ServerSocket Provê um socket servidor para comunicação orientada à

conexão via protocolo TCP.DatagramSocket Provê um socket UDP para comunicação não orientada

à conexão.DatagramPacket Representa um datagrama que pode ser enviado usando

DatagramSocket.InetAddress Representa os dados de um Host (Nome e endereço IP)

Tabela XI.2 – Classes para comunicação básica.

As classes Socket e ServerSocket são utilizadas para comunicaçãoorientada à conexão, enquanto que as classes DatagramSocket eDatagramPacket são utilizadas para comunicação não orientada à conexão.

Page 310: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

309

Comunicação orientada à conexão (cliente)

Para comunicar via protocolo TCP é preciso que a aplicação cliente crieum objeto Socket. É preciso passar o nome ou número IP do Host e o númeroda porta onde o servidor está esperando as solicitações de serviço. A ClasseSocket possui os métodos getInputStream() egetOutputStream(), que são usados para obter Streams associados aoSocket. Deste modo, a transmissão de dados via Socket é idêntica à leitura eescrita em arquivos via Streams. O exemplo XI.1 mostra o código de um clienteque acessa um servidor de Daytime. O serviço de Daytime é disponibilizado nasplataformas UNIX e é acessado via porta 13. Sua função enviar, aos processosclientes, uma linha de texto contendo a data e a hora corrente .

import java.io.*;import java.net.*;

public class ClienteData {public static void main(String[] args) throws IOException{

Socket socket = null;BufferedReader in = null;

try {socket = new Socket(args[0], 13);in = new BufferedReader(new InputStreamReader(

socket.getInputStream()));}catch (UnknownHostException e){System.err.println("Não achou o host:"+args[0]);

System.exit(1);} catch (IOException e){System.err.println("Erro de I/O."+e.getMessage());

System.exit(1);}

System.out.println("Data: " + in.readLine());}

in.close();socket.close();

}}

Exemplo XI.1 – Cliente para o serviço de Daytime.

No programa do exemplo XI.1 o usuário precisa passar o nome do Hostservidor pela linha de comando. Você pode testar este programa mesmo que seu

Page 311: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

310

computador não esteja conectado em uma rede, desde que o protocolo TCP/IPesteja instalado. É que você pode passar como parâmetro o nome do seucomputador ou, alternativamente, o nome localhost, ainda o número IP127.0.0.0. O nome localhost e o número IP127.0.0.0 sempre identificam ocomputador local. Note que após a criação do objeto Socket, o métodogetInputStream() é chamado e o objeto retornado é envolvido por umobjeto BufferedReader de modo a comunicar dados via rede da mesma formaque é realizada uma operação de E/S. Ao se terminar a operação é preciso fechartanto a instância BufferedReader quanto o objeto Socket. A instância da Classede E/S sempre deve ser fechada primeiro.

Os Hosts que utilizam as variações do sistema operacional UNIXpossuem o serviço de Daytime, no entanto, outros sistemas operacionais podemnão implementar este serviço. O programador pode resolver este problemaimplentando ele mesmo um servidor de Daytime. A próxima seção mostrarácomo isto pode ser feito.

Comunicação orientada à conexão (servidor)

Para criar um processo servidor é preciso associá-lo à uma porta. Isto éfeito ao se criar uma instância da classe ServerSocket. Se estamos criando umnovo serviço é preciso associar a uma porta com valor maior que 1023. Seestamos implementando um serviço já estabelecido é preciso obedecer asespecificações definidas para o serviço. O exemplo XI.2 mostra o código de umservidor do serviço Daytime. Como não queremos substituir o serviço padrão deDaytime utilizaremos o número de porta 5013 no lugar do número 13. Para setestar este servidor com o programa cliente do exemplo X.1 é preciso alterar onúmero da porta no código do cliente.

Page 312: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

311

import java.util.*;import java.io.*;import java.net.*;

public class ServerData {public static void main(String[] args) throws IOException{

SeverSocket ssocket = null;Socket socket = null;BufferedWriter out = null;

ssocket = new SeverSocket (5013,5);for(;;){

socket = ssocket.accept();out = new BufferedWriter (new OuputStreamWriter (

socket.getOuputStream()));out.write((new Date()).toString()+”\n”);

}

out.close();socket.close();

}}

Exemplo XI.2 – Servidor de Daytime.

Ao criar uma instância da classe ServerSocket o programador podeindicar o tamanho da fila de solicitações de conexão. As conexões são colocadasna fila até que o servidor possa atende-las. Se chegar alguma conexão e nãohouver espaço na fila a conexão será recusada. No nosso exemplo passamoscomo parâmetro o valor 5. Após criar o objeto ServerSocket o servidor deveindicar que está disposto a receber conexões. Isto é feito por meio da execuçãodo método accept() do objeto ServerSocket. Ao executar este método oprocesso passa para o estado bloqueado até que alguma conexão seja solicitada.Quando a conexão é solicitada o método accept() retorna um objeto Socketigual ao do processo cliente, que será usado para obter os Streams onde seráefetuada a comunicação. O Stream obtido do objeto Socket é encapsulado emobjeto BufferedWriter que será encarregado de enviar a cadeia de caracterescontendo a data e a hora para o cliente. O Servidor em implementa um laçoinfinito, recebendo e tratando solicitações de serviços.

Page 313: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

312

O servidor implementado acima trata uma solicitação de serviço por vez.Isto pode ser problemático quando existem vários clientes solicitando serviçosao mesmo tempo e o servidor leva um longo tempo tratando cada solicitação.Nesta situação o cliente pode ficar um longo tempo a espera de atendimento. Istopode ser remediado por meio da implementação de servidores Multithreaded.Apesar do serviço implementado pelo exemplo XI.2 não exigir um servidorMultithreaded, uma vez que o cliente é atendido rapidamente, o servidorDaytime foi alterado para exemplificar a implementação de um servidorMultithreaded. O exemplo XI.3 mostra o código da versão Multithreaded doservidor.

import java.util.*;import java.net.*;import java.io.*;

public class ServerData{

public static void main(String args[]){

ServerSocket ssocket=null;

try { ssocket = new ServerSocket(pt); }catch(Exception e) {System.err.println(e);

System.exit(1);}

while(true){

try{ Socket socket = ssocket.accept(); (new serversec(socket)).start();}catch(Exception e) {System.err.println(e);}

}}

}

class serversec extends Thread{

Socket socket;

public serversec(Socket aSocket) {socket = aSocket;}

public void run(){

Page 314: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

313try{

BufferedWriter out = new BufferedWriter (newOuputStreamWriter ( socket.getOuputStream()));

out.write((new Date()).toString()+”\n”);out.flush();out.close();socket.close();

}catch(Exception e) {System.err.println(e);}

}}

Exemplo XI.3 – Servidor de Daytime Multithreaded.

No exemplo XI.3, ao receber uma conexão o servidor cria um Threadpara atender o cliente e fica disponível para receber novas solicitações. Esseexemplo pode ser usado como esqueleto para desenvolvimento de servidoresmais complexos, porém, neste caso é necessário limitar o número de Threadsque podem ser criados.

Comunicação Sem Conexão (UDP)

Como já dissemos na seção anterior, nem sempre é necessário um canalde comunicação confiável entre duas aplicações. Para estes casos existe oprotocolo UDP, que provê uma forma de comunicação onde a aplicação enviapacotes de dados, chamados de datagramas, para outra aplicação, sem garantiasse e quando a mensagem vai chegar, nem se o conteúdo está preservado.

As portas do protocolo UDP obedecem a mesma distribuição das TCPporém são distintas uma da outra, de modo que o programador pode associaruma porta TCP de um determinado número à uma aplicação em um host e omesmo número de porta UDP a outra aplicação no mesmo host.

As classes DatagramPacket e DatagramSocket contém osmétodos necessários para realizar este tipo de comunicação. Para ilustrar o usodestas classes modificaremos os exemplos XI.1 e XI.2 para implementarmosuma aplicação Cliente/Servidor Daytime que usa o protocolo UDP. O ExemploXI.4 mostra o código fonte do cliente e o Exemplo XI.5 mostra o código doservidor.

Page 315: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

314

Analisando o código da aplicação cliente podemos notar que é necessáriocriar um objeto da classe DatagramPacket para representar os Datagrama ondeos dados são armazenados. No nosso exemplo colocamos também os dados doHost e a porta, porém estes dados poderiam ser omitidos na construção doDatagrama e serem passados somente no envio/recepção do pacote ou naconstrução do DatagramSocket. O Datagrama deverá armazenar os dadosenviados pelo servidor e foi dimensionado para conter 64 bytes. O métodoreceive() do objeto DatagramSocket aguarda o recebimento do pacote,tendo como argumento o objeto da classe DatagramPacket. Após o recebimentodo pacote os dados são convertidos para String e exibidos na saída padrão.

O servidor, diferentemente do servidor TCP, precisa saber a quem deveenviar os pacotes, uma vez que não é estabelecida uma conexão. Podíamossimplesmente passar o nome do host pela linha de comando, mas resolvemosadotar uma estratégia de Broadcasting. Nesta abordagem os datagramas sãoenviados a vários computadores e não apenas um. Isto é feito passando-se comoargumento para o método InetAddress.getByName() o endereço deBroadcast da rede.

import java.io.*;import java.net.*;

public class DataClienteUDP{ public static void main(String args[]) throws Exception { if (args.length != 1) { System.err.println("Uso: java DataClienteUDP host"); System.exit(1); } byte [] buff = new byte[64]; DatagramSocket ds = new DatagramSocket(); DatagramPacket dp = new DatagramPacket(buff, buff.length, InetAddress.getByName(args[0]),5013); ds.receive(dp); String s = new String(dp.getData()); System.out.println("Data e hora recebidade”+dp.getAddress()+ " : "+s); }}

Page 316: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

315

Exemplo XI.4 – Cliente Daytime UDP.

import java.io.*;import java.net.*;

public class DataServerUDP{ public static void main(String args[]) throws Exception { DatagramSocket ds; DatagramPacket dp; InetAddress addr = InetAddress.getByName(“255.255.255.0”); ds = new DatagramSocket();

byte [] buff; for (;;) { Thread.sleep(1000); String s = (new Date()).toString(); buff = s.getBytes(); dp = new DatagramPacket(buff, buff.length, addr, 5013); ds.send(dp); } }}

Exemplo XI.5 – Servidor Daytime UDP.

O tipo de endereço de Broadcast depende da classe de endereçamento IPda rede. O endereço usado no exemplo IX.5 funciona para a classe deendereçamento C. Para descobrir que tipo de classe pertence a rede onde está seucomputador olhe o primeiro byte do endereço IP de sua máquina e verifiquejunto a tabela XI.3.

Primeiro byte do endereço IP Classe Endereço de Broadcast0 a 126 A 255.0.0.0128 a 191 B 255.255.0.0192 a 223 C 255.255.255.0

Tabela XI.3 – Classes para comunicação básica.

Page 317: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

316

O envio dos dados é feito pelo método send() do objetoDatagramSocket, tendo como argumento um objeto da classe DatagramPacket.Note que não é necessário um “Socket servidor” uma vez que o servidor enviaos pacotes independentemente de existir clientes solicitando-os.

Comunicação por meio de URL

URLs

Um URL (Uniform Resource Locator) é uma referência (um endereço) aum recurso na Internet. O URL é dividido em partes, sendo que apenas aprimeira parte é obrigatória. A maioria das URLs é dividida em três partes:

Informação sobre o Host

http://dpi.ufv.br/professores.html

A parte do protocolo define o protocolo que deve ser usado para acessaro recurso. Os protocolos mais comuns são FTP, HTTP e file, este últimoindicando que o recurso se encontra no sistema de arquivos local. O protocolo éseguido do caractere “:”.

A parte com informação sobre o Host fornece a informação necessáriapara acessar o Host onde está localizado o recurso. Esta parte é omitida caso orecurso esteja no sistema de arquivos local. A informação sobre o Host éprecedida por duas barras (“//”), no caso de aplicação na Internet e apenas poruma barra (“/”), caso contrário. A informação sobre o Host também pode serdividida em três partes: a) o nome do domínio do Host; b) o nome e senha dousuário para login; e c) o número da porta caso necessário, após o nome do host,precedida pelo caractere “:”. Exemplos:

http://java.sun.com:80/doc/tutorial.htmlhttp://infax.com.br."claudio"."1234"/base/vendas

111122223333

666677778888123

endereço do recurso no HostProtocolo

Page 318: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

317

A última parte de uma URL representa o caminho até o recurso nosistema de arquivos do Host. Esta seção é separada da seção anterior por umabarra simples (“/”).

Manipulando URLs em Java

A linguagem Java fornece as seguintes classes para manipulação deURLs:

Classe DescriçãoURL Representa um URLURLConnection Classe abstrata que representa uma conexão entre uma

aplicação e um URL. Instâncias desta classe podem serusadas para ler e escrever no recurso referenciado pelaURL.

URLEncoder Usada para lidar com o formato MIME.

Tabela XI.3 – Classes para manipulação de URLs.

Um objeto URL é criado passando como parâmetro para o construtor oURL na forma de String:

URL dpi = new URL("http://www.dpi.ufv.br");

Um objeto URL pode ser construído passando como parâmetro outroURL para servir de endereço base. Por exemplo

URL profs = new URL (dpi,”professores.html”);

Isto tem o mesmo efeito que gerar uma instância da classe URL comprimeiro construtor, passando como parâmetro o endereço:

http://www.dpi.ufv.br/professores.html

Os construtores geram a exceção MalformedURLException, se oURL é inválido. Portanto, o programador deve providenciar o código para acaptura e tratamento desta exceção.

Page 319: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

318

De posse de um objeto URL é possível obter um objeto InputStream paraler os dados endereçados pelo URL, utilizando o método openStream() doobjeto URL. O Exemplo XI.4 mostra o código de um programa que pode serusado para listar na saída padrão o conteúdo de um URL passado pela linha decomando.

import java.net.*;import java.io.*;

public class LeURL{ public static void main(String[] args) throws Exception { if (args.length < 1) { System.err.println("uso: java LeURL <URL>..."); System.exit(1); } URL url = new URL(args[0]); BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream()));

String linha;

while ((linha = in.readLine()) != null) System.out.println(linha);

in.close(); }}

Exemplo XI.4 – Leitor de URL.

Comunicando por meio de URLConnection

O programador pode utilizar o método openConnection() do objetoURL para obter uma conexão entre a aplicação é o recurso referenciado pelo oURL. O método openConnection() retorna um objeto URLConnection,que permite que a aplicação escreva e leia através da conexão. Alguns URLs,como os conectados à scripts CGI5 (Common-Gateway Interface), permitem que

5 Common-Gateway Interface (CGI) é um mecanismo para gerar páginas Web dinamicamente.Os dados são obtidos de fórmulários HTML e submetidos a um programa binário no servidor

Page 320: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

319

aplicação cliente escreva informação no URL. A saída do programa CGI podeser interceptada pelo programa Java de modo que possa ser exibida para ousuário. Esta forma de comunicação com scripts CGI é melhor do que por meiode formulários HTML, uma vez que o usuário não precisa navegar entre páginaspara visualizar os formulários e a resposta retornada. O Applet Java se encarregade enviar os dados e exibir o resultado na mesma página. Para ilustrar esta formade comunicação mostraremos um programa que submete uma cadeia decaracteres a um URL para que seja invertido e enviado de volta. O script CGIutilizado, escrito em Perl é exibido no exemplo XI.5 e foi escrito por HassanSchroeder, um membro da equipe de desenvolvimento da linguagem Java. EsteCGI pode ser acessado no URL http://java.sun.com/cgi-bin/backwards.

#!/opt/internet/bin/perlread(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});@pairs = split(/&/, $buffer);foreach $pair (@pairs){ ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; # Stop people from using subshells to execute commands $value =~ s/~!/ ~!/g; $FORM{$name} = $value;}

print "Content-type: text/plain\n\n";print "$FORM{'string'} reversed is: ";$foo=reverse($FORM{'string'});print "$foo\n";exit 0;

Exemplo XI.5 – Script backwards para inverter uma cadeia de caracteres.

O exemplo XI.6 contém o programa que envia uma cadeia de caracteresao URL e recebe de volta outra cadeia de caracteres que é a inversão daprimeira. A ação necessária é codificar a cadeia de caracteres por meio dométodo estático encode() da classe URLEncoder:

que gera a resposta na forma de uma página Web. O programa pode ser escrito em umavariadade delinguagens, como Perl e C.

Page 321: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

320

String string = URLEncoder.encode(args[0]);

Isto é necessário porque a string enviada a um URL necessita de umacodificação particular, como por exemplo, os espaços em branco sãosubstituídos pelo caractere “+”, os campos são separados pelo caractere “&”evalor do campo é separado do nome do campo pelo caracteres “=”.

Em seguida o programa cria um objeto URL relacionado com o endereçoonde se encontra o script, abre uma conexão e define que será usada para entradae saída.

URL url = new URL("http://java.sun.com/cgi-bin/backwards");URLConnection c = url.openConnection();c.setDoOutput(true);

Neste momento o programa está preparado para trabalhar com o URLcomo se fosse um Stream. O Stream para escrever no URL é obtido do objetoURLConnection por meio do método getOutputStream() e o Streampara ler do URL é obtido do objeto URLConnection por meio do métodogetInputStream(). Primeiro o programa submete a cadeia de caracteres aser invertida precedida pelo nome do campo e pelo caractere “=”:

out.println("string=" + string);

import java.io.*;import java.net.*;

public class Inverte{ public static void main(String[] args) throws Exception {

if (args.length != 1) { System.err.println("Uso: java Inverte string"); System.exit(1); }

String string = URLEncoder.encode(args[0]);

URL url = new URL("http://java.sun.com/cgi-

Page 322: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

321bin/backwards"); URLConnection c = url.openConnection(); c.setDoOutput(true);

PrintWriter out = new PrintWriter(c.getOutputStream()); out.println("string=" + string); out.close();

BufferedReader in = new BufferedReader(newInputStreamReader( c.getInputStream())); String retorno;

while ((retorno = in.readLine()) != null) System.out.println(retorno);

in.close(); }}

Exemplo XI.6 – Programa que escreve em um URL.

Após isso o Stream de saída é fechado e o Stream de entrada é aberto. Acadeia de caracteres invertida é lida e exibida no dispositivo de saída padrão.

No exemplo apresentado o script CGI usa o POST METHOD para lerdados enviados pelo cliente. Alguns scripts CGI usam o GET METHOD para lerdados do cliente, no entanto, este último está ficando rapidamente obsoletodevido a maior versatilidade do primeiro.

Page 323: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

322

Capítulo XIV – Computaç ãoDistribuída (RMI)

A RMI (Invocação de métodos remotos) é uma tecnologia que coloca aprogramação com rede em um nível mais alto. RMI torna possível que objetosdistribuídos em uma rede se comuniquem de forma transparente para oprogramador utilizando chamadas de procedimentos remotos.

O principal objetivo da tecnologia RMI é permitir que programadoresdesenvolvam programas distribuídos utilizando a mesma sintaxe e semântica deprogramas Java convencionais. Antes da introdução da RMI no mundo Java, noJDK 1.1, para fazer com que dois objetos em máquinas diferentes secomunicassem o programador deveria definir um protocolo de comunicação eescrever código utilizando socket para implementar este protocolo. Com RMI amaior parte do trabalho quem realiza é a máquina virtual Java.

Existem outras tecnologias, como CORBA (Common Object RequestBrocker Architecture), que também tem como objetivo fazer com que objetosdistribuídos em uma rede se comuniquem. Java também tem suporte a CORBA,mas para projetos em um ambiente Java puro, a RMI é consideravelmente maissimples que a CORBA.

Criando nossa agenda distribuída

De modo exemplificar o uso de RMI modificaremos a agenda distribuídafazendo uso desta tecnologia. Os passos a serem seguidos são:

1. Escrever e compilar a interface que descreve a como serão as chamadasdo cliente ao servidor;

2. Escrever e compilar a classe que implementa a interface do passo 1(objeto servidor);

3. Gerar Stubs e Skeleton do objeto distribuído;4. Desenvolver o código que disponibiliza o objeto;5. Escrever e compilar o código para o cliente RMI; e6. Testar.

Implementar interface do objeto remoto

Page 324: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

323

O primeiro passo quando se deseja criar um objeto Remoto com RMI éimplementar uma interface para este Objeto. Essa interface deve herdar ainterface Remote. É através dessa interface Remote, que não tem métodos, que amáquina virtual Java sabe qual objeto pode ser disponibilizado para acessoremoto. Abaixo temos o exemplo da interface do nosso objeto:

12345678

public interface Agenda extends java.rmi.Remote{ public void inserir(Pessoa p) throws java.rmi.RemoteException; public Pessoa getPessoa(String nome) throws java.rmi.RemoteException; public java.util.Enumeration getPessoas() throws java.rmi.RemoteException;}

Exemplo XX.XX – Interface do objeto remoto.

A interface Remote deve ser herdada pela nossa interface Agenda.

Page 325: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

324

Capítulo XV - Acesso a B anco deDados

No dias de hoje, uma linguagem sem recursos para acesso a sistemas deBanco de Dados está fadada ao fracasso. Pensando nisso a Sun incluiu comoparte do núcleo de bibliotecas de classes da linguagem Java uma API com oobjetivo de preencher esta função, chamada de JDBC (segundo a Sun JDBC éapenas um acronismo, no entanto, muitas pessoas acreditam que é uma siglapara Java Database Connectivity). JDBC é uma API baseada no X/Open SQLCall Level Interface, tendo sido desenvolvida originalmente como um pacoteseparado, porém a partir do JDK1.1 passou a fazer parte do núcleo básico depacotes. Utilizando a API JDBC é possível conectar um programa Java comservidores de Banco de Dados e executar comandos SQL (Structure QueryLanguage). Sendo uma API independente do Sistema Gerenciador de Banco deDados, não é necessário escrever uma aplicação para acessar um Banco deDados Oracle, outra para uma Base de Dados Sybase, outra para o DB2, e assimpor diante.

A idéia de se usar uma camada intermediária entre o Banco de Dados e aaplicação, com o objetivo de isolá-la das particularidades do SGBD, não é nova.O exemplo mais popular deste enfoque é a API ODBC (Open DataBaseConnectivity), proposta pela Microsoft. O leitor pode estar se perguntandoporque a Sun resolveu propor mais uma API em vez de adotar a ODBC. Existemvários motivos, porém o principal é que a API ODBC simplesmente não éadequada para a linguagem Java. Isto ocorre porque ODBC foi desenvolvidapara ser usada na linguagem C e é baseada fortemente no uso de ponteiros,estrutura que não existe em Java.

Modelos de Acesso a Servidores

O modelo mais simples de aplicação Cliente/Servidor é o chamado demodelo de duas camadas, onde a aplicação acessa diretamente o Banco deDados. A figura XIII.1 mostra o esquema para uma aplicação que acessa umBanco de Dados usando o modelo de duas camadas.

Page 326: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

325

Figura XIII.1 – Modelo de acesso a Banco de Dados em duas camadas.

Figura XIII.2 – Modelo de acesso a Banco de Dados em três camadas.

Tipos de Drivers JDBC

Os drivers JDBC devem suportar o nível de entrada do padrão ANSISQL-2. No momento, os drivers JDBC existentes se encaixam em um dos quatrotipos abaixo:

1. Ponte JDBC-ODBC com driver ODBC – o driver JDBC acessa o banco dedados via drivers ODBC. Como ODBC é um código binário e, em algunscasos, compõe o código do cliente, é necessário instalar em cada máquinacliente que usa o driver. Essa é uma solução adequada somente para uma

AplicaçãoJava

DBMS

Aplicação Javaou Applet

DBMS

Aplicação ServidoraJava

JDBC

HHTTTTPP,, RRMMII,, CCOORRBBAA

Page 327: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

326

interna corporativa, ou em aplicações que adotam o modelo de três camadassendo a camada intermediária um servidor Java.

SGBD1

Cliente Ponte SGBD2Java JDBC-ODBC SGBD3

2. Driver Java parcial e Api Nativa – neste caso as chamadas JDBC sãoconvertidas para as chamadas às APIs nativas do SGBD. Como o driverpossui uma parte em código binário é necessário instalar algum código namáquina cliente, como é feito nos drivers do tipo 1.

Protocolo do SGBDCliente JDBC Java & SGBDJava Código Binário

3. Driver puro Java e protocolo de rede – neste caso as chamadas JDBC sãoconvertidas para um protocolo de rede independente do SGBD que é depoistraduzido para as chamadas às APIs nativas do SGBD por um servidor. Estaé uma arquitetura em três camadas, onde o servidor middleware é capaz deconectar seus clientes Java puros com vários SGBDs. Esta solução permite odesenvolvimento de clientes 100% Java, tendo como consequência a nãonecessidade de instalação de qualquer código na máquina cliente.

SGBD1Cliente Servidor de SGBD2Java acesso SGBD3

4. Driver Java Puro e protocolo nativo - neste caso as chamadas JDBC sãoconvertidas para as chamadas às APIs nativas do SGBD pelo driver, que foiescrito totalmente em Java.

Protocolo do SGBDCliente JDBC Java SGBDJava (100% Java)

JDBC DRIVER (100% Java)

Page 328: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

327

Atualmente existe uma maior disponibilidade dos drivers tipo 1 e 2, mas atendência é que estes desapareçam, sendo substituídos pelos drivers do tipo 3 e4.

Obtendo os Drivers JDBC

Informações sobre como obter drivers JDBC podem ser obtidas no sitehttp://www.javasoft.com/products/jdbc. Outra alternativa éacessar as páginas dos fabricantes de SGBD, para verificar se existe driverdisponível.

Preparando um Banco de Dados

Os exemplos deste livro usam a ponte JDBC-ODBC para conectar com oBanco de Dados. Isto facilita para os usuários que possuem um gerenciadorBanco de Dados pessoal como o Access, Paradox, e outros semelhantes. Alémdisso, como driver JDBC-ODBC está incorporado ao SDK, o usuário nãonecessita procurar um driver para testar os exemplos. O lado negativo destaabordagem está na necessidade de configurar o ODBC e no fato de que asaplicações remotas deverão ser desenvolvidas em três camadas. No entanto,nada impede que o leitor use outro driver para rodar os exemplos, bastando paraisso alterar a chamada da carga do driver.

Primeiramente é necessário criar uma base de dados em algum SGBD.Nos exemplos deste livro será usada uma base contendo dados sobre livros,alunos e empréstimos de livros aos alunos. Não trataremos neste livro dosconceitos relacionados com banco de dados relacionais nem sobre a linguagemde consulta SQL. Existem vários textos sobre o assunto onde o leitor podebuscar informação.

As figuras XIII.3 a XII.5 mostram as tabelas que formam a base de dadosusada nos exemplos. O banco de dados é formado por três tabelas. Uma paraarmazenar os dados dos alunos, outra para receber os dados dos livros e umaterceira para conter os dados dos empréstimos.

alunosmatricula nome

1 Railer Costa Freire2 Alexandre Altoé

Page 329: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

328

3 André M. A. Landro4 Ana Maria Freitas5 Claudia Maria6 Alexandra Moreira

Figura XIII.3 – Tabela de alunos

livroscodlivro titulo volume

1 Curso Pratico de Java 12 Curso Pratico de Java 23 Introdução a Compiladores 14 Fundamentos de Banco de Dados 15 Redes de Computadores 16 Redes de Computadores Fácil 27 Lógica matemática 18 Engenharia de Software para Leigos 19 Aprenda Computação Gráfica em duas 1

10 Aprenda Inteligência Artificial em 5 1

Figura XIII.4 – Tabela de livros.

emprestimoscodlivr matricu data_empresti data_devoluc

1 1 01/01/99 10/01/997 3 03/01/99 13/01/999 6 12/01/99 22/01/991 3 20/01/99 30/01/994 2 03/02/99 13/02/99

10 2 12/02/99 22/02/99

Figura XIII.5 – Tabela de empréstimos.

Em um Banco de Dados Relacional cada tabela representa um conjuntode entidades ou relacionamentos entre entidades, e cada linha da tabelarepresenta uma entidade particular ou um relacionamento entre entidades.Assim, cada linha das tabelas alunos e livros representa um aluno e um livrorespectivamente. Já na tabela empréstimos cada linha representa orelacionamento por empréstimo de um livro a um aluno. Para estabelecer este

Page 330: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

329

tipo de relacionamento em um Banco de Dados Relacional é preciso colocar natabela que representa o relacionamento os atributos chaves de cada entidade queparticipa da relação. Atributos chaves são os atributos que identificam cadaentidade. No caso dos alunos é seu número de matrícula, uma vez que podeexistir dois alunos com o mesmo nome. Já no caso de um livro o seu atributochave é o código do livro. Um Banco de Dados Relacional pode ser representadopelo diagrama de classes da UML, como mostrado pela figura XIII.6, onde cadatabela é vista como uma classe.

Figura XIII.6 – Diagrama de Classes do Banco de Dados.

Para criação das tabelas em banco de dados relacional deve-se usarcomandos DDL (Data Definition Language). O exemplo XX.XX mostra oscomandos em DDL para a criação das tabelas do exemplo:

CREATE TABLE ALUNOS (MATRICULA INT PRIMARY KEY, NOME VARCHAR(50) NOT NULL);

CREATE TABLE LIVROS (CODLIVRO INT PRIMARY KEY, TITULO VARCHAR(50) NOT NULL, VOLUME INT NOT NULL);

CREATE TABLE EMPRESTIMOS ( CODLIVRO INT NOT NULL, MATRICULA INT NOT NULL, DATAEMP DATE NOT NULL, DATADEV DATE NOT NULL, CONSTRAINT PK_EMP PRIMARY KEY (CODLIVRO, MATRICULA, DATAEMP), CONSTRAINT FK_EMP1 FOREIGN KEY (CODLIVRO ) REFERENCES LIVROS (CODLIVRO ),

Alunos

matriculanome

livros

codlivrotitulovolume

emprestimos

data_emprestimodata_devolução

Page 331: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

330

CONSTRAINT FK_EMP2 FOREIGN KEY (MATRICULA) REFERENCES ALUNOS (MATRICULA ));

Exemplo XX.XX – Comandos em DDL para criação das tabelas em um SGBDrelacional.

Configurando o ODBC

Como utilizamos nos exemplos a ponte JDBC-ODBC é necessárioconfigurar o ODBC para acessar a base de dados acima. Na plataformaWindows 98 isso é feito da seguinte forma:

1. Execute o programa de configuração do ODBC por meio do ícone“ODBC de 32bits” do painel de controle.

2. Clique na pasta “NFD do sistema” e em seguida no botão de“adicionar...”. O NFD do sistema é escolhido no lugar da opção“NFD do usuário” porque permite o compartilhado à base de dados.

3. Selecione o driver do banco de dados e pressione o botão de concluir.Por exemplo, se você estiver usando o Access selecione a opção“Driver para o Microsoft Access (*.mdb)”.

Page 332: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

331

Figura XIII.7 – Seleção do driver ODBC no Windows.

4. Ao surgir a tela para a entrada seleção do Banco de Dados, utilize atecla “Selecionar...” localizar o arquivo onde está a base de dados epreencha a janela de texto “Nome da fonte de dados” com o nomeque será usado para referenciar a base.

5. Feche o programa de configuração.

A configuração de uma base de dados para ser acessada via ODBCpossui vários outros detalhes que consideramos não ser relevantes para ospropósitos deste livro. A configuração como apresentada acima é a suficientepara se executar os exemplos deste livro.

Exemplo Inicial

O pacote java.sql fornece as classes e interfaces necessárias para aconexão com uma base de dados e a posterior manipulação dos dados. As etapaspara se criar uma aplicação cliente de um SGBD em Java são as seguintes:

1. Carregar o driver JDBC.2. Estabelecer a conexão.3. Criar um objeto Statement.4. Executar o comando SQL por meio de um método do objeto

Statement.5. Receber o resultado, se for o caso.

Para comentar cada uma destas etapas utilizaremos o exemplo XII.1 quemostra o código de uma aplicação que lista no dispositivo de saída padrão onome de todos os alunos.

import java.sql.*;import java.net.URL;

class jdbc{ public static void main(String a[])

Page 333: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

332 { try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection con = DriverManager.getConnection("jdbc:odbc:biblioteca"); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT NOME FROM alunos"); System.out.println("Nome"); while(rs.next()) System.out.println(rs.getString("nome")); stmt.close(); con.close(); } catch(Exception e) {System.out.println(e.getMessage()); e.printStackTrace();} }}

Exemplo XX.XX – Código para listar o nome dos alunos.

Carregando o Driver

A primeira etapa é carregar o driver JDBC. Para isso é usado o métodoestático forName() da classe Class. Em caso de erro este método lança aexceção ClassNotFoundException. O método cria uma instância dodriver e o registra junto ao DriverManager. No exemplo XIII.1 é carregado odriver JDBC-ODBC que vem junto com o SDK.

Estabelecendo a conexão

A segunda etapa é realizada por meio do método estáticogetConnection() da classe DriverManager. Este método, na sua forma maissimples, recebe como parâmetro um URL que faz referência a base de dados eretorna um objeto da classe Connection, que representa a conexão com a base dedados. Já discutimos sobre URLs no capítulo XI. No entanto, existem algumasparticularidades no que refere a URLs que fazem referência à Banco de Dados.O formato padrão deste tipo de URL é o seguinte:

jdbc:<subprotocolo>:<identificador>

onde:

Page 334: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

333

1. jdbc representa o protocolo;

2. <subprotocolo> se refere ao driver ou ao mecanismo de conexão como Banco de Dados, que pode ser suportado por um ou mais drivers.No exemplo XII.1 o nome é utilizada a ponte JDBC-ODBC,representada pela palavra odbc no subprotocolo.

3. <identificador> é a parte onde se identifica o Banco de Dados. Aforma de identificação varia de acordo com o subprotocolo. No nossoexemplo é colocado o mesmo nome usado para identificar a fonte dedados na configuração do ODBC. A sintaxe para o subprotocolo odbcé a seguinte:

jdbc:odbc:<fonte de dados>[;<atributo>=<valor>]*

onde <atributo> e <valor> representam parâmetros a serem passadospara o gerente de conexão do Banco de Dados.

Um banco de dados acessado remotamente requer maiores informações,como o nome do host e a porta. Tanto o uso local como remoto pode requerer aidentificação do usuário, assim como uma senha. Estes dados podem serpassados como parâmetro no método getConnection():

getConnection("jdbc:odbc:contas",”ana”,”sght”);

ou como parte do URL. Alguns exemplos de URLs estão descritos na tabelaXIII.1

URL Descriçãojdbc:odbc:biblioteca Referencia fonte de dados biblioteca via

ponte JDBC-ODBC.jdbc:odbc:bd1;CacheSize=20 Referencia fonte de dados bd1 via ponte

JDBC-ODBC. É definido o tamanho docache.

jdbc:odbc:contas;UID=ana;PWD=sght Referencia fonte de dados contas viaponte JDBC-ODBC. É passado também onome do usuário e a senha.

jdbc:oracle:thin:@sap.dpi.ufv.br:1521:agenda Referencia fonte de dados agenda no hostremoto sap.dpi.ufv.br via subprotocolooracle. É passado também o número daporta usada no acesso.

Page 335: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

334

Tabela.1 – Exemplos de URLs JDBC.

Criando e Executando Comandos

É necessário cria um ou mais objetos da classe Statement, que possui osmétodos necessários para manipular a base de dados. Este objeto é criado pormeio do método createStatement() do objeto da classe Connection.

Statement stmt = con.createStatement();

Podemos então usar o objeto Statement para executar comandos demanipulação do Banco de Dados. No exemplo XIII.1 o objetivo é recuperar snomes dos alunos. Este objetivo é atingido por meio da execução do comandoSQL

SELECT nome FROM alunos

passado como parâmetro para o método executeQuery() do objetoStatement. Este método retorna um objeto que implementa a interfaceResultSet, e que fornece os meios de acesso ao resultado da consulta. Muitasvezes, como no exemplo, o resultado de uma consulta é uma tabela com váriaslinhas. O programador pode utilizar o objeto ResultSet para acessar cada linhada tabela resultante em sequência. Para isso o objeto mantém um apontador paraa linha corrente, chamado de cursor. Inicialmente o cursor é posicionado antesda primeira linha, movimentado para próxima linha por meio de chamadas aométodo next() do objeto ResultSet.

O método executeQuery() é usado apenas para consultas. Alémdesse método, a classe Statement possui o método execute() que retornamúltiplos ResultSets e o método executeUpdate(), para atualização(comandos INSERT, DELETE e UPDATE da linguagem SQL), criação detabelas (comandos CREATE TABLE) e remoção (DROP TABLE). O valor deretorno do método executeUpdate() é um valor inteiro indicando onúmero de linhas afetadas ou zero no caso do DROP TABLE. Um exemplo deum comando para inserir um uma novo aluno na tabela seria:

stmt.executeUpdate("INSERT INTO alunos VALUES(7, 'Anamia')");

Page 336: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

335

Recuperando Valores

O objeto ResultSet possui os métodos necessários para recuperar osvalores de cada coluna da tabela, bastando passar o nome da coluna comoparâmetro. No exemplo XIII.1 é utilizado método getString() pararecuperar o valor da coluna “nome”. Os métodos para recuperação possuem oformato geral getXXX(), onde XXX é o nome de um tipo. A tabela XIII.2mostra qual o método mais indicado para cada tipo SQL.

TINYINT

SMALLINT

INTEGER

BIGINT

REAL

FLOAT

DOUBLE

DECIMAL

NUMERIC

BIT

CHAR

VARCHAR

LONGVARCHAR

BINARY

VARBINARY

LONGVARBINARY

DATE

TIME

TIMESTAMP

getByte X x x x x x x x x x x x xgetShort x X x x x x x x x x x x xgetInt x x X x x x x x x x x x xgetLong x x x X x x x x x x x x xgetFloat x x x x X x x x x x x x xgetDouble x x x x x X X x x x x x xgetBigDecimal x x x x x x x X X x x x xgetBoolean x x x x x x x x x X x x xgetString x x x x x x x x x x X X x x x x x x xgetBytes X X xgetDate x x x X xgetTime x x x X xgetTimestamp x x x x XgetAsciiStream x x X x x xgetUnicodeStream

x x X x x x

Page 337: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

336

getBinaryStream

x x X

getObject x x x x x x x x x x x x x x x x x x x“x” indica que o método pode ser usado para recuperar o valor no tipo SQL especificado.“X” indica que o método é recomendado para ser usado na recuperação do valor no tipo SQL especificado

Tabela XIII.2 – Tabelas com os métodos indicados para recuperação devalores.

É possível recuperar o valor da coluna passando como parâmetro onúmero da coluna no lugar de seu nome. Neste caso a recuperação no nome doaluno no exemplo XIII.1 ficaria na seguinte forma:

rs.getString(1);

Transações e Nível de Isolamento

Transação

Uma Transação é um conjunto de operações realizadas sobre um bancode dados tratadas atomicamente, em outras palavras, ou todas operações sãorealizadas e o seu resultado registrado permanentemente na base de dados ounenhuma operação é realizada. Por default, o banco de dados trata cada operaçãocomo uma transação, realizando implicitamente uma operação de commit ao fimde cada uma delas. A operação de commit registra permanentemente o resultadoda transação na tabela.

No entanto, existem situações onde é necessário tratar como umatransação um conjunto de operações, e não apenas uma transação. Por exemplo,suponha que em um Banco de Dados de uma agência bancária exista uma tabelacom informações sobre a conta de corrente e outra com informações sobrecontas de poupança. Suponha também que um cliente deseje transferir o dinheiroda conta corrente para uma conta de poupança. Essa transação é constituídapelas seguintes operações:

1. Caso exista saldo suficiente, subtração do montante da transferênciado saldo da conta corrente.

2. Adição do montante da transferência ao saldo da conta de poupança.

Page 338: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

337

As operações acima precisam ocorrer totalmente ou o efeito de nenhumadelas deve ser registrado na base de dados. Caso contrário podemos ter umasituação onde o dinheiro sai da conta corrente mas não entra na conta dapoupança. Este estado, onde as informações do banco de dados não reflete arealidade, é chamado de estado inconsistente.

De modo a obter esse controle sobre as transações é necessáriodesabilitar o modo de auto-commit. Isto é feito por meio métodosetAutoCommit() do objeto Connection.

con.setAutoCommit(false);

A partir do momento em que é executado o comando acima, oprogramador é responsável pela indicação do final da transação, por meio daexecução do método commit() do objeto Connection.

con.commit();

Se alguma exceção for levantada durante a execução de qualqueroperação da transação, o programador pode usar o método rollback() paradesfazer as operações já realizadas após o último commit().

con.setAutoCommit(false);try{ Statement stmt = con.createStatement(); stmt.executeUpdate(“UPDATE ...” ); stmt.executeUpdate(“UPDATE ...” ); con.commit(); stmt.close();}catch(Exception e){con.rollback();}finally{ try{ con.setAutoCommit(true);} catch(SQLException sqle) {System.out.prinln(sql.getMessage());}}

Exemplo XX.X – Uso dos métodos commit() e rollback().

Page 339: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

338

Níveis de isolamento

Além da atomicidade outra propriedade desejável em uma transação é oisolamento. A propriedade de isolamento implica que uma transação não éafetada pelas operações realizadas por outras transações que estão sendorealizadas concorrentemente.

O isolamento completo entre transações prejudica muito a execuçãoconcorrente de transações e pode ser desnecessário em determinados tipos deaplicações. Por isso os SGBDs permitem que o programador defina o nível deisolamento entre as transações. De acordo com o relaxamento do isolamentocertos problemas devido a interferência entre as transações podem ocorrer e oprogramador deve estar ciente disso.

O número de níveis de isolamento, sua nomenclatura e característicasdepende do SGBD utilizado. Descreveremos os níveis de isolamento definidosno pacote java.sql. Para exemplificar os problemas que podem ocorrerdevido a interferência entre transações utilizaremos um banco de dados exemplocom a seguinte tabela:

NumCC Saldo10189-920645-7

200,00300,00

• Read uncommitted - É o nível menos restritivo. Pode ocorrer leituras deregistros não committed (Dirty reads). Usados em onde não existeconcorrência ou não existem alterações em registros ou quando essasalterações não são relevantes. Exemplo de problema: Uma transação devetransferir R$50,00 da conta 10189-9 para a conta 20645-7 e uma segundatransação deve somar R$70,00 à conta 10189-9. A figura abaixo mostra oestado inicial e o estado final desejado da tabela:

NumCC Saldo NumCC Saldo10189-920645-7

200,00300,00

10189-920645-7

220,00350,00

Estado desejado após astransações

Estado antes dastransações

Page 340: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

339

Cada transação é divida em operações de leitura e escrita. Suponha que ointercalamento das operações seja feito como mostrado abaixo:

Transação 1 Transação 2leitura do saldo 10189Escrita do Saldo-50,00

leitura do saldo 20645(falha na transação,realizado rollback)

leitura do saldo 10189

Escrita do Saldo+70,00

Como a transação 1 falhou o valor lido pela transação 2 é um valor que nãofoi tornado permanente na tabela. Isto faz com que a transação 2 opere sobreum resultado desfeito. A tabela resultante, mostrada abaixo estará em umestado inconsistente.

NumCC Saldo10189-920645-7

220,00300,00

• Read committed - Somente registros committed podem ser lidos. Evita oproblema de Dirty reads, no entanto duas leituras de um mesmo item emuma mesma transação podem possuir valores diferentes, uma vez que o valorpode ser mudado por outra transação entre duas leituras.

• Repeatable Read - Somente registros committed podem ser lidos, alémdisso impede a alteração de um item lido pela transação. Evita o problema deDirty reads e o problema do non-repeatable Read .

• Serializable - É o nível mais restritivo. Impede Dirty reads e non-repeatablereads. Além disso impede o problema de phantom reads onde um conjuntode registros satisfazendo a condição WHERE é lido enquanto outra transaçãoinsere novos registros que satisfazem a condição.

Para se definir o nível de isolamento na linguagem Java usa-se um objetoDatabaseMetaData que é obtido por meio do objeto getMetaData() doConnection. Primeiro é preciso saber se o SGBD suporta o nível de

Page 341: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

340

isolamento desejado para depois definir o nível. O exemplo XX.X mostra umasequência típica comandos.

DatabaseMetaData meta=con.getMetaData();

if(meta.supportsTransactionIsolationLevel( con.TRANSACTION_READ_COMMITTED)) { con.setTransactionIsolation( con.TRANSACTION_READ_COMMITTED);}else return;

Exemplo XX.X – Exemplo do estabelecimento do nível de isolamento.

A tabela abaixo mostra as constantes relacionadas com os níveis deisolamento da linguagem Java:

ConstanteTRANSACTION_NONETRANSACTION_READ_UNCOMMITTEDTRANSACTION_READ_COMMITTEDTRANSACTION_REPEATABLE_READTRANSACTION_SERIALIZABLE

Tabela XX.X – Tabela com as constantes dos níveis de isolamento.

Prepared Statements

Cada vez que se executa um comando SQL passado por meio de umaString. Este String deve ser analisado pelo processador de SQL do SGBD queirá, no caso da String estar sintaticamente correta, gerar um código binário queserá executado para atender à solicitação. Todo esse processo é caro e suaexecução repetidas vezes terá um impacto significativo sobre o desempenho daaplicação e do SGBD como um todo.

Existem duas abordagens para tentar solucionar esse problema:Comandos preparados (prepared statements) e procedimentos armazenados(stored procedures). Discutiremos primeiramente os prepared statements.

Prepared Statement é indicado nos casos onde um comando seráexecutado várias vezes em uma aplicação. Neste caso é melhor compilar ocomando uma única vez e toda vez que for necessário executá-lo basta enviar o

Page 342: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

341

comando compilado. Além disso, o comando pré-compilado pode serparametrizado, tornando-o mais genérico e, portanto, apto a expressar um maiornúmero de consultas.

Para criar um Prepared Statement é necessário obter um objetoPreparedStatement por meio do método prepareStatement() doobjeto Connection, passando como argumento um comando SQL.

PreparedStatement pstmt = con.prepareStatement( “INSERT INTO alunos(matricula,nome) VALUES(?, ? )”);

O comando anterior insere uma nova linha na tabela alunos com osvalores das colunas matricula e nome passados por parâmetro. O caractere ‘?’representa o parâmetro. Este tipo de comando só possui valor tendo parâmetros,caso contrário teria pouca chance de ser reutilizado. Para executar o comandodevemos especificar o valor dos parâmetros e executar o comando, comomostrado no exemplo abaixo:

pstmt.clearParameters();pstmt.setInt(1,8);pstmt.setString(2,”Clara Maria”);pstmt.executeUpdate();

Antes de especificar os parâmetros é necessário limpar qualquer outroparâmetro previamente especificado. Para especificar os parâmetros sãoutilizados um conjunto de métodos com o nome no formato setXXX(), ondeXXX é o tipo sendo passado. O primeiro parâmetro do método setXXX() é oíndice da ocorrência do caractere ‘?’ que será substituído pelo valor. O segundoparâmetro é o valor que será transmitido.

Procedimentos Armazenados (Stored Procedures)

A maioria dos SGBDs possuem algum tipo de linguagem deprogramação interna, como por exemplo a PL/SQL do Oracle ou mesmo Java eC/C++. Estas linguagens permitem que os desenvolvedores insiram parte docódigo da aplicação diretamente no banco de dados e invoquem este código apartir da aplicação. Esta abordagem possui as seguintes vantagens:

Page 343: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

342

• Reuso de código – o código precisa ser escrito apenas uma vez e usadoem várias aplicações, comunicando com várias linguagens.

• Independencia entre a aplicação e o esquema do BD – se o esquemamudar, provavelmente apenas os procedimentos armazenados.

• Desempenho – os procedimentos são previamente compilados,eliminando esta etapa.

• Segurança – as aplicações possuem privilégio apenas para execução deprocedimentos armazenados, evitando assim acessos não autorizados.

A sintaxe dos procedimentos armazenados depende do SGBD emquestão. Utilizaremos um exemplo em PL/SQL. No exemplo abaixo oprocedimento retorna o nome do aluno a partir de sua matricula.

CREATE OR REPLACE PROCEDURE sp_obtem_nome (id IN INTEGER, Nome_aluno out VARCHAR2)ISBEGIN SELECT nome INTO Nome_aluno FROM alunos WHERE matricula = id;END;

/

Para invocar o procedimento anterior de dentro de uma aplicação Java énecessário obter um objeto CallableStatement por meio do métodoprepareCall() do objeto Connection, passando como argumento umcomando SQL.

CallableStatement cstmt = con.prepareCall("{ CALL sp_obtem_nome(?,?)}");cstmt.registerOutParameter(2, Types.VARCHAR);cstmt.setInt(1, 3);cstmt.execute();System.out.prinln(“O nome do aluno numero 3 :” +cstmt.getString(2);

Page 344: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

343

Agenda Eletrônica versão JDBC

Pessoa

import java.io.*;

public class pessoa implements Serializable{

String Nome;String Tel;

// Construtorpublic pessoa(String n, String t) {Nome = n; Tel = t;}

public String getNome(){return Nome;}public String getTel(){return Tel;}

}

agendaimport java.util.*;import java.io.*;import java.sql.*;import java.net.URL;

public class agenda{ Connection con=null;

// Construtor public agenda()throws Exception { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con=DriverManager.getConnection("jdbc:odbc:agenda"); }

/**CloseAgenda

*/ public void CloseAgenda() { if (con != null) try{con.close();}catch(Exception e){}; }

/**inserir

Page 345: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

344 */ public void inserir(pessoa p) { if (con == null) return;

try { Statement stmt = con.createStatement(); stmt.executeUpdate("INSERT INTO pessoas(nome,telefone)"+ "values('"+p.getNome()+"','"+p.getTel()+"')");

stmt.close(); }catch(Exception e) {System.err.println(e);} }

/**Consultar

*/

/**listar

*/ public Enumeration getLista() { if (con == null) return null;

Vector pessoas = new Vector();

try { Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery ("SELECT Nome, Telefone FROM pessoas"); while(rs.next()) pessoas.addElement(newpessoa(rs.getString("Nome"), rs.getString("Telefone"))); stmt.close(); } catch(Exception e) {System.out.println(e.getMessage()); e.printStackTrace();}

return pessoas.elements(); }}

Servidorimport java.util.*;import java.net.*;import java.io.*;

Page 346: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

345

/**CLASS server*/class server{ public static void main(String args[]) { String oHost="localhost"; ServerSocket ssocket=null; serversec oServersec; int pt = 4444; agenda ag;

try {ag = new agenda();} catch(Exception e){System.err.println(e); return;}; if (args.length > 0) pt = Integer.parseInt(args[0]);

try{ ssocket = new ServerSocket(pt); pt = ssocket.getLocalPort(); oHost =

ssocket.getInetAddress().getHostName().trim();}catch(Exception e) {System.err.println(e);

System.exit(1);}

System.out.println("Porta:"+pt+" Host: "+oHost);

while(true){ try {

Socket clisocket = ssocket.accept();oServersec = new serversec(ag,clisocket);oServersec.start();

} catch(Exception e) {System.err.println(e);}}

}}

/** CLASS serversec*/class serversec extends Thread{ Socket oSocket; BufferedWriter soutput;

Page 347: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

346 BufferedReader cinput; agenda ag;

public serversec(agenda ag, Socket aoSocket) {

this.ag = ag;oSocket = aoSocket;

}

public void run() {

try{

soutput = new BufferedWriter(new

OutputStreamWriter(oSocket.getOutputStream())); cinput = new BufferedReader(new

InputStreamReader(oSocket.getInputStream()));

String losLinha = cinput.readLine(); switch(losLinha.charAt(0)) { case 'i': String Nome = cinput.readLine(); String Tel = cinput.readLine(); ag.inserir(new pessoa(Nome,Tel)); soutput.write("OK\n#\n"); break; case 'l': pessoa p; for (Enumeration e = ag.getLista();e.hasMoreElements() ;) { p = (pessoa) e.nextElement();

soutput.write(p.getNome()+"\n"+p.getTel()+"\n"); } soutput.write("#\n"); break; }

soutput.flush(); Thread.yield(); soutput.close(); oSocket.close();

}catch(Exception e) {System.err.println(e);}

}}

Page 348: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

347

Appletimport java.awt.*;import java.applet.*;import java.util.*;import java.net.*;import java.io.*;

public class agendaapplet extends Applet{ int port = 4444;

TextField txtNome = new TextField(); TextField txtTel = new TextField(); Label label1 = new Label(); Label label2 = new Label(); Button btIns = new Button(); Button btList = new Button(); Button btCons = new Button(); Button btSair = new Button(); TextArea Saida = new TextArea(); Button btLimpar = new Button();

public void init() {

setLayout(null);setSize(376,224);add(txtNome);txtNome.setBounds(108,48,232,24);add(txtTel);txtTel.setBounds(108,84,232,24);label1.setText("Nome");add(label1);label1.setBounds(24,48,60,26);label2.setText("Telefone");add(label2);label2.setBounds(24,84,60,26);btIns.setActionCommand("button");btIns.setLabel("Inserir");add(btIns);btIns.setBackground(java.awt.Color.lightGray);btIns.setBounds(12,12,49,23);btList.setActionCommand("button");btList.setLabel("Listar");add(btList);btList.setBackground(java.awt.Color.lightGray);btList.setBounds(149,12,60,23);btCons.setActionCommand("button");btCons.setLabel("Consultar");add(btCons);

Page 349: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

348btCons.setBackground(java.awt.Color.lightGray);btCons.setBounds(75,12,60,23);btSair.setActionCommand("button");btSair.setLabel("Sair");add(btSair);btSair.setBackground(java.awt.Color.lightGray);btSair.setBounds(297,12,60,23);add(Saida);Saida.setBounds(24,120,338,90);btLimpar.setActionCommand("button");btLimpar.setLabel("Limpar");add(btLimpar);btLimpar.setBackground(java.awt.Color.lightGray);btLimpar.setBounds(223,12,60,23);

SymMouse aSymMouse = new SymMouse();btSair.addMouseListener(aSymMouse);btIns.addMouseListener(aSymMouse);btList.addMouseListener(aSymMouse);btLimpar.addMouseListener(aSymMouse);

}

public void transmit(int port,String mensagem) { BufferedWriter soutput; BufferedReader cinput; Socket clisoc=null; try { if (clisoc != null) clisoc.close(); clisoc = new

Socket(InetAddress.getByName(getCodeBase().getHost()),port); soutput = new BufferedWriter (new OutputStreamWriter(clisoc.getOutputStream())); cinput = new BufferedReader(new InputStreamReader(clisoc.getInputStream()));

soutput.write(mensagem+"\n"); soutput.flush();

String losRet = cinput.readLine(); while (losRet.charAt(0)!='#') { Saida.setText(Saida.getText()+losRet+"\n"); losRet = cinput.readLine(); } Thread.sleep(500);

Page 350: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

349 soutput.close(); clisoc.close(); } catch(Exception e) {System.err.println(e);} }

class SymMouse extends java.awt.event.MouseAdapter {

public void mouseClicked(java.awt.event.MouseEvent event){ Object object = event.getSource(); if (object == btSair) btSair_MouseClick(event); else if (object == btIns) btIns_MouseClick(event); else if (object == btList) btList_MouseClick(event); else if (object == btLimpar)

btLimpar_MouseClick(event); }}

void btSair_MouseClick(java.awt.event.MouseEvent event) {

System.exit(0); }

void btIns_MouseClick(java.awt.event.MouseEvent event) {

String nome = txtNome.getText();String tel = txtTel.getText();

if (nome.length()>0 && tel.length()>0)transmit(port,"i\n"+nome+"\n"+tel+"\n");

}

void btList_MouseClick(java.awt.event.MouseEvent event) {

transmit(port,"l\n"); }

void btLimpar_MouseClick(java.awt.event.MouseEvent event) {

Saida.setText(""); }}

Page 351: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

350

Capítulo XVI Servlets e JSPServlets e JSP são duas tecnologias desenvolvidas pela Sun para

desenvolvimento de aplicações na Web a partir de componentes Java queexecutem no lado servidor. Essas duas tecnologias fazem parte da plataformaJ2EE (Java 2 Platform Enterprise Edition) que fornece um conjunto detecnologias para o desenvolvimento de soluções escaláveis e robustas para aWeb. Neste livro abordaremos apenas as tecnologias Servlets e JSP, sendo osuficiente para o desenvolvimento de sites dinâmicos de razoável complexidade.Se a aplicação exigir uma grande robustez e escalabilidade o leitor deveconsiderar o uso em conjunto de outras tecnologias da plataforma J2EE.

Servlets

Servlets são classes Java que são instanciadas e executadas emassociação com servidores Web, atendendo requisições realizadas por meio doprotocolo HTTP. Ao serem acionados, os objetos Servlets podem enviar aresposta na forma de uma página HTML ou qualquer outro conteúdo MIME. Naverdade os Servlets podem trabalhar com vários tipos de servidores e não sóservidores Web, uma vez que a API dos Servlets não assume nada a respeito doambiente do servidor, sendo independentes de protocolos e plataformas. Emoutras palavras Servlets é uma API para construção de componentes do ladoservidor com o objetivo de fornecer um padrão para comunicação entre clientese servidores. Os Servlets são tipicamente usados no desenvolvimento de sitesdinâmicos. Sites dinâmicos são sites onde algumas de suas páginas sãoconstruídas no momento do atendimento de uma requisição HTTP. Assim épossível criar páginas com conteúdo variável, de acordo com o usuário, tempo,ou informações armazenadas em um banco de dados.

Servlets não possuem interface gráfica e suas instâncias são executadasdentro de um ambiente Java denominado de Container. O container gerencia asinstâncias dos Servlets e provê os serviços de rede necessários para asrequisições e respostas. O container atua em associação com servidores Webrecebendo as requisições reencaminhada por eles. Tipicamente existe apenasuma instância de cada Servlet, no entanto, o container pode criar vários threadsde modo a permitir que uma única instância Servlet atenda mais de uma

Page 352: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

351

requisição simultaneamente A figura XX fornece uma visão do relacionamentodestes componentes.

Figura XVI-1. Relacionamento entre Servlets, container e servidor Web

Servlets provêem uma solução interessante para o relacionamentocliente/servidor na Internet, tornando-se uma alternativa para a implantação desistemas para a Web. Antes de entrarmos em detalhes na construção de Servlets,compararemos esta solução com outras duas soluções possíveis para implantaçãode aplicações na Internet.

Applets X Servlets

Apesar de ser uma solução robusta existem problemas no uso de Applets paravalidação de dados e envio para o servidor. O programador precisa contar com ofato do usuário possuir um navegador com suporte a Java e na versãoapropriada. Você não pode contar com isso na Internet, principalmente se vocêdeseja estender a um grande número de usuário o acesso às suas páginas. Em setratando de Servlets, no lado do cliente pode existir apenas páginas HTML,evitando restrições de acesso às páginas. Em resumo, o uso de Applets não érecomendado para ambientes com múltiplos navegadores ou quando a semânticada aplicação possa ser expressa por componentes HTML.

ServidorWeb

Requisições

Máquina Virtual Java

Container

Instâncias de ServletsRespostas

Page 353: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

352

CGI X Servlets

Como visto no Capítulo IX, scripts CGI (Common Gateway Interface),acionam programas no servidor. O uso de CGI sobrecarrega o servidor uma vezcada requisição de serviço acarreta a execução de um programa executável (quepode ser escrito em com qualquer linguagem que suporte o padrão CGI) noservidor, além disso, todo o processamento é realizado pelo CGI no servidor. Sehouver algum erro na entrada de dados o CGI tem que produzir uma páginaHTML explicando o problema. Já os Servlets são carregados apenas uma vez ecomo são executados de forma multi-thread podem atender mais de uma mesmasolicitação por simultaneamente. Versões posteriores de CGI contornam estetipo de problema, mas permanecem outros como a falta de portabilidade e ainsegurança na execução de código escrito em uma linguagem como C/C++.

A API Servlet

A API Servlet é composta por um conjunto de interfaces e Classes. Ocomponente mais básico da API é interface Servlet. Ela define ocomportamento básico de um Servlet. A figura XX.XX mostra a interfaceServlet.

public interface Servlet { public void init(ServletConfig config) throws ServletException; public ServletConfig getServletConfig(); public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; public String getServletInfo(); public void destroy();}

Figura XV.XX. Interface Servlet.

O método service() é responsável pelo tratamento de todas dasrequisições dos clientes. Já os métodos init() e destroy() são chamadosquando o Servlet é carregado e descarregado do container, respectivamente. Ométodo getServletConfig() retorna um objeto ServletConfig quecontém os parâmetros de inicialização do Servlet. O método

Page 354: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

353

getServletInfo() retorna um String contendo informações sobre oServlet, como versão e autor.

Tendo como base a interface Servlet o restante da API Servlet seorganiza hierarquicamente como mostra a figura XV.XX.

Figura XV.XX. Hierarquia de classes da API Servlet.

A classe GenericServlet implementa um servidor genérico egeralmente não é usada. A classe HttpServlet é a mais utilizada e foiespecialmente projetada para lidar com o protocolo HTTP. A figura XX.XXmostra a definição da classe interface HttpServlet.

HttpServlet

public abstract class HttpServletextends GenericServletimplements java.io.Serializable

Figura XV.XX. Definição da classe HttpServlet.

Note que a classe HttpServlet é uma classe abstrata. Para criar umServlet que atenda requisições HTTP o programador deve criar uma classederivada da HttpServlet e sobrescrever pelo menos um dos métodosabaixo:

Servlet

GenericServlet

HttpServlet

Page 355: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

354

doGet Trata as requisições HTTP GET.doPost Trata as requisições HTTP POST.doPut Trata as requisições HTTP PUT.doDelete Trata as requisições HTTP DELETE.

Tabela XV.XX. Métodos da classe HttpServlet que devem sersobrescritos para tratar requisições HTTP.

Todos esses métodos são invocados pelo servidor por meio do métodoservice(). O método doGet() trata as requisições GET. Este tipo derequisição pode ser enviada várias vezes, permitindo que seja colocada em umbookmark. O método doPost() trata as requisições POST que permitem que ocliente envie dados de tamanho ilimitado para o servidor Web uma única vez,sendo útil para enviar informações tais como o número do cartão de crédito. Ométodo doPut() trata as requisições PUT. Este tipo de requisição permite queo cliente envie um arquivo para o servidor à semelhança de como é feito viaFTP. O método doPut() trata as requisições DELETE, permitindo que ocliente remova um documento ou uma página do servidor. O métodoservice(), que recebe todas as requisições, em geral não é sobrescrito, sendosua tarefa direcionar a requisição para o método adequado.

Exemplo de Servlet

Para entendermos o que é um Servlet nada melhor que um exemplosimples. O exemplo XV.XX gera uma página HTML em resposta a umarequisição GET. A página HTML gerada contém simplesmente a frase Olamundo!!!. Este é um Servlet bem simples que ilustra as funcionalidades básicasda classe.

import javax.servlet.*;import javax.servlet.http.*;

public class Ola extends HttpServlet{ public String getServletInfo() { return "Ola versão 0.1";}

public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {

Page 356: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

355

res.setContentType("text/html"); java.io.PrintWriter out = res.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet</title>"); out.println("</head>"); out.println("<body>Ola mundo!!!"); out.println("</body>"); out.println("</html>"); out.close(); }}

Exemplo XV.XX. Servlet Ola.

O método doGet() recebe dois objetos: um da classeHttpServletRequest e outro da classe HttpServletResponse. OHttpServletRequest é responsável pela comunicação do cliente para oservidor e o HttpServletResponse é responsável pela comunicação doservidor para o cliente. Sendo o exemplo XV.XX apenas um exemplo simplesele ignora o que foi enviado pelo cliente, tratando apenas de enviar uma páginaHTML como resposta. Para isso é utilizado o objeto da classeHttpServletResponse. Primeiramente é usado o métodosetContentType() para definir o tipo do conteúdo a ser enviado ao cliente.Esse método deve ser usado apenas uma vez e antes de se obter um objeto dotipo PrintWriter ou ServletOutputStream para a resposta. Após issoé usado o método getWriter() para se obter um objeto do tipoPrintWriter que é usado para escrever a resposta. Neste caso os dados daresposta são baseados em caracteres. Se o programador desejar enviar a respostaem bytes deve usar o método getOutputStream() para obter um objetoOutputStream. A partir de então o programa passa usar o objetoPrintWriter para enviar a página HTML.

Compilando o Servlet

A API Servlet ainda não foi incorporado ao SDK, portanto, para compilarum Servlet é preciso adicionar a API Servlet ao pacote SDK. Existem váriasformas de se fazer isso. A Sun fornece a especificação da API e diversosprodutores de software executam a implementação. Atualmente, a especificação

Page 357: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

356

da API Servlet está na versão 2.XX. Uma das implementações da API que podeser baixada gratuitamente pela Internet é a fornecida pelo projeto Jakarta(http://jakarta.apache.org) denominada de Tomcat. Aimplementação da API Servlet feita pelo projeto Jakarta é a implementação dereferência indicada pela Sun. Ou seja, é a implementação que os outrosfabricantes devem seguir para garantir a conformidade com a especificação daAPI. No entanto, uma vez que o Tomcat é a implementação mais atualizada daAPI, é também a menos testada e, por consequência, pode não ser a mais estávele com melhor desempenho.

Instalando o Tomcat

Assim como para se executar um Applet era preciso de um navegadorWeb com Java habilitado no caso de Servlets é preciso de servidor Web queexecute Java ou que passe as requisições feitas a Servlets para programas queexecutem os Servlets. O Tomcat é tanto a implementação da API Servlet como aimplementação de um container, que pode trabalhar em associação com umservidor Web como o Apache ou o IIS, ou pode também trabalhar isoladamente,desempenhando também o papel de um servidor Web. Nos exemplos aquimostrados usaremos o Tomcat isoladamente. Em um ambiente de produção estaconfiguração não é a mais adequada, uma vez que os servidores Web possuemum melhor desempenho no despacho de páginas estáticas. As instruções paraconfigurar o Tomcat para trabalhar em conjunto com um servidor Web podemser encontradas junto às instruções gerais do programa. As figuras XV.XXilustram essas duas situações.

Figura XV.XX. Servidor Web habilitado para Servlet.

Servidor Web

Servlet habilitadoInternet

Page 358: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

357

Figura XV.XX. Servidor Web reencaminhando as requisições para o Servletcontainer.

A versão estável do Tomcat é a 3.2.3.XX é após baixá-la do site doprojeto Jakarta o usuário deve descomprimir o arquivo. Por exemplo, noambiente Windows o usuário pode descomprimir o arquivo na raiz do disco C:,o que gerará a seguinte árvore de diretórios:

C:\ jakarta-tomcat-3.2.3 | |______bin |______conf |______doc |______lib |______logs |______src |______webapps

No diretório bin encontram-se os programas execução e interrupção docontainer Tomcat. No diretório conf encontram-se os arquivos de configuração.No diretório doc encontram-se os arquivos de documentação. No diretório libencontram-se os bytecodes do container e da implementação da API. Nodiretório logs são registradas as mensagens da geradas durante a execução dosistema. No diretório src encontram-se os arquivos fontes do container e daimplementação da API de configuração. Finalmente, No diretório webappsencontram-se as páginas e códigos das aplicações dos usuários.

No ambiente MS-Windows aconselhamos usar um nome dentro doformato 8.3 (oito caracteres para o nome e três para o tipo). Assim o diretóriojakarta-tomcat-3.2.3 poderia ser mudado para simplesmente tomcat.

Internet Servidor Web

Servlet Container

Page 359: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

358

Antes de executar o Tomcat é necessário definir duas variáveis deambiente. Por exemplo, supondo que no MS-Windows o Tomcat foi instalado nodiretório c:\tomcat e que o SDK está instalado no diretório c:\jdk1.3então as seguintes variáveis de ambiente devem ser definidas:

set JAVA_HOME=C:\jdk1.3set TOMCAT_HOME=C:\tomcat

Agora é possível executar o Tomcat por meio do seguinte comando:

C:\tomcat\bin\startup.bat

Para interromper a execução servidor basta executar o arquivo

c:\tomcat\bin\shutdown.bat

Falta de espaço para variáveis de ambienteCaso ao iniciar o servidor apareça a mensagem “sem espaço de ambiente”

clique com o botão direito do mouse no arquivo .bat e edite as propriedades definindo oambiente inicial com 4096. Feche o arquivo é execute novamente.

Ao entrar em execução o servidor lê as configurações constantes noarquivo server.xml e, por default, se anexa à porta 8080. Para verificar se oprograma está funcionando corretamente execute um navegador como oNetscape ou o Internet Explorer e digite a seguinte URL:

http://127.0.0.1:8080/index.html

A figura XX.XX mostra a tela principal do Tomcat.

Page 360: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

359

Figura XV.XX. Tela inicial do Tomcat.

A número porta default para recebimento das requisições HTTP pode seralterada por meio da edição do arquivo server.xml do diretório conf comomostrado abaixo:

<Connector className="org.apache.tomcat.service.PoolTcpConnector"> <Parameter name="handler"

value="org.apache.tomcat.service.http.HttpConnectionHandler"/> <Parameter name="port" value="Número da porta"/></Connector>

No entanto, caso o Tomcat esteja operando em conjunto com umservidor, o ideal é que o Tomcat não responda requisições diretamente.

Preparando para executar o Servlet

Compilando o Servlet

Page 361: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

360

Antes de executar o Servlet e preciso compilá-lo. Para compilá-lo épreciso que as classes que implementam a API Servlet estejam no classpath.Para isso é preciso definir a variável de ambiente. No ambiente MS-Windowsseria

set CLASSPATH=%CLASSPATH%;%TOMCAT_HOME%\lib\servlet.jar

e no ambiente Unix seria

CLASSPATH=${CLASSPATH}:${TOMCAT_HOME}/lib/servlet.jar

Alternativamente, é possível indicar o classpath na própria linha deexecução do compilador Java. Por exemplo, No ambiente MS-Windows ficariana seguinte forma:

javac -classpath "%CLASSPATH%;c:\tomcat\lib\servlet.jar Ola.java

Criando uma aplicação no Tomcat

Agora é preciso definir onde deve ser colocado o arquivo compilado.Para isso é preciso criar uma aplicação no Tomcat ou usar uma das aplicações jáexistentes. Vamos aprender como criar uma aplicação no Tomcat. Para isso épreciso cria a seguinte estrutura de diretórios abaixo do diretório webapps doTomcat:

webapps |_____ Nome aplicação |_____ Web-inf |_____classes

Diretório de AplicaçõesNa verdade é possível definir outro diretório para colocar as aplicações do Tomcat. Para

indicar outro diretório é preciso editar o arquivo server.xml e indicar o diretório por meio dadiretiva home do tag ContextManager.

O diretório de uma aplicação é denominado de contexto da aplicação. Épreciso também editar o arquivo server.xml do diretório conf, incluindo aslinhas:

Page 362: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

361<Context path="/nome aplicação" docBase="webapps/ nome aplicação" debug="0” reloadable="true" ></Context>

Finalmente, é preciso criar (ou copiar de outra aplicação) um arquivoweb.xml no diretório Web-inf com o seguinte conteúdo:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd"><web-app></web-app>

Copie então o arquivo compilado Ola.class para o subdiretório/webapps/nome aplicação/Web-inf/classes do Tomcat.

Executando o Servlet

Invocando diretamente pelo Navegador

Podemos executar um Servlet diretamente digitando a URL do Servlet nonavegador. A URL em geral possui o seguinte formato:

http://máquina:porta/nome aplicação/servlet/nome servlet

A palavra servlet que aparece na URL não indica um subdiretório noservidor. Ela indica que esta é uma requisição para um Servlet. Por exemplo,suponha que o nome da aplicação criada no Tomcat seja teste. Então a URLpara a invocação do Servlet do exemplo XX.XX teria a seguinte forma:

http://localhost:8080/teste/servlet/Ola

A URL para a chamada do Servlet pode ser alterada de modo a ocultarqualquer referência à diretórios ou a tecnologias de implementação. No caso doTomcat essa configuração é no arquivo web.xml do diretório Web-inf daaplicação. Por exemplo, para eliminar a palavra servlet da URL poderíamos

Page 363: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

362

inserir as seguintes linhas no arquivo web.xml entre os tags <web-app> e</web-app>:

<servlet> <servlet-name> Ola </servlet-name> <servlet-class> Ola </servlet-class></servlet><servlet-mapping> <servlet-name> Ola </servlet-name> <url-pattern> /Ola </url-pattern></servlet-mapping>

Invocando em uma página HTML

No caso de uma página HTML basta colocar a URL na forma de link.Por exemplo,

<a href="http://localhost:8080/teste/servlet/Ola>Servlet Ola</a>

Neste caso o Servlet Ola será solicitado quando o link associado ao texto“Servlet Ola” for acionado.

Diferenças entre as requisições GET e POST

Os dois métodos mais comuns, definidos pelo protocolo HTTP, de seenviar uma requisições a um servidor Web são os métodos POST e GET. Apesarde aparentemente cumprirem a mesma função, existem diferenças importantesentre estes dois métodos. O método GET tem por objetivo enviar uma requisiçãopor um recurso. As informações necessárias para a obtenção do recurso (comoinformações digitadas em formulários HTML) são adicionadas à URL e, porconsequência, não são permitidos caracteres inválidos na formação de URLs,

Page 364: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

363

como por espaços em branco e caracteres especiais. Já na requisição POST osdados são enviados no corpo da mensagem.

O método GET possui a vantagem de ser idempotente, ou seja, osservidores Web podem assumir que a requisição pode ser repetida, sendopossível adicionar à URL ao bookmark. Isto é muito útil quando o usuário desejamanter a URL resultante de uma pesquisa. Como desvantagem as informaçõespassadas via GET não podem ser muito longas, um vez o número de caracterespermitidos é por volta de 2K.

Já as requisições POST a princípio podem ter tamanho ilimitado. Noentanto, elas não são idempotente, o que as tornam ideais para formulários ondeos usuários precisam digitar informações confidenciais, como número de cartãode crédito. Desta forma o usuário é obrigado a digitar a informação toda vez quefor enviar a requisição, não sendo possível registrar a requisição em umbookmark.

Concorrência

Uma vez carregado o Servlet não é mais descarregado, a não ser que oservidor Web tenha sua execução interrompida. De modo geral, cada requisiçãoque deve ser direcionada a determinada instância de Servlet é tratada por umthread sobre a instância de Servlet. Isto significa que se existirem duasrequisições simultâneas que devem ser direcionadas para um mesmo objeto ocontainer criará dois threads sobre o mesmo objeto Servlet para tratar asrequisições. A figura XX.XX ilustra esta situação.

Figura XV.XX. Relacionamento entre as instâncias dos Servlets e os threads.

Servlet2

thread1Servlet1

thread2

thread1

usuário1

usuário2

usuário3

Page 365: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

364

Em conseqüência disto temos o benefícios de uma sobrecarga paraservidor, uma vez que a criação de threads é menos onerosa do que a criação deprocessos, e uma aparente melhora no tempo de resposta.

Por outro lado, o fato dos Servlets operarem em modo multi-threadaumenta a complexidade das aplicações e cuidados especiais, como visto nocapítulo sobre concorrência, devem tomados para evitar comportamentoserráticos. Por exemplo, suponha um Servlet que receba um conjunto de númerosinteiros e retorne uma página contendo a soma dos números. A exemplo XX.XXmostra o código do Servlet. O leitor pode imaginar um código muito maiseficiente para computar a soma de números, mas o objetivo do código doexemplo é ilustrar o problema da concorrência em Servlets. O exemplo contémtambém um trecho de código para recebimento de valores de formulários, o queserá discutido mais adiante.

import java.util.*;import javax.servlet.*;import javax.servlet.http.*;

public class Soma extends HttpServlet {

Vector v = new Vector(5); protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, java.io.IOException { v.clear(); Enumeration e = req.getParameterNames();

while (e.hasMoreElements()) { String name = (String)e.nextElement(); String value = req.getParameter(name); if (value != null) v.add(value); }

res.setContentType("text/html"); java.io.PrintWriter out = res.getWriter(); out.println("<html>"); out.println("<head><title>Servlet</title></head>"); out.println("<body>"); out.println("<h1> A soma e'"); int soma =0; for(int i =0; i< v.size() ; i++) { soma += Integer.parseInt((String)v.get(i)); } out.println(soma); out.println("<h1>"); out.println("</body>");

Page 366: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

365

out.println("</html>"); out.close(); }}

Exemplo XX.XX- Servlet com problemas de concorrência.

Note que o Servlet utiliza uma variável de instância para referenciar oVector que armazena os valores. Se não forem usadas primitivas desincronização (como no código do exemplo) e duas requisições simultâneaschegarem ao Servlet o resultado pode ser inconsistente, uma vez que o Vectorpoderá conter parte dos valores de uma requisição e parte dos valores de outrarequisição. Neste caso, para corrigir esse problema basta declarar a variávelcomo local ao método doPost() ou usar primitivas de sincronização.

Obtendo Informações sobre a Requisição

O objeto HttpServletRequest passado para o Servlet contémvárias informações importantes relacionadas com a requisição, como porexemplo o método empregado (POST ou GET), o protocolo utilizado, oendereço remoto, informações contidas no cabeçalho e muitas outras. O Servletdo exemplo XX.XX retorna uma página contendo informações sobre arequisição e sobre o cabeçalho da requisição.

import java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;

public class RequestInfo extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); out.println("<html><head>"); out.println("<title>Exemplo sobre Requisicao de Info </title>"); out.println("</head><body>"); out.println("<h3> Exemplo sobre Requisicao de Info </h3>"); out.println("Metodo: " + req.getMethod()+”<br>”); out.println("Request URI: " + req.getRequestURI()+”<br>”); out.println("Protocolo: " + req.getProtocol()+”<br>”);

Page 367: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

366

out.println("PathInfo: " + req.getPathInfo()+”<br>”); out.println("Endereco remoto: " + req.getRemoteAddr()+”<br><br>”); Enumeration e = req.getHeaderNames(); while (e.hasMoreElements()) { String name = (String)e.nextElement(); String value = req.getHeader(name); out.println(name + " = " + value+"<br>"); } out.println("</body></html>"); }

public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { doGet(req, res); }}

Exemplo XX.XX- Servlet que retorna as informações sobre a requisição.

Note que o método doPost() chama o método doGet(), de modoque o Servlet pode receber os dois tipos de requisição. A figura XX.XX mostra oresultado de uma execução do Servlet do exemplo XX.XX.

Exemplo sobre Requisicao de Info

Metodo: GETRequest URI: /servlet/RequestInfoProtocolo: HTTP/1.0PathInfo: nullEndereco remoto: 127.0.0.1

Connection = Keep-AliveUser-Agent = Mozilla/4.7 [en] (Win95; I)Pragma = no-cacheHost = localhost:8080Accept = image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*Accept-Encoding = gzipAccept-Language = enAccept-Charset = iso-8859-1,*,utf-8

Figura XX.XX- Saída da execução do Servlet que exibe as informações sobre arequisição.

Page 368: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

367

Lidando com Formulários

Ser capaz de lidar com as informações contidas em formulários HTML éfundamental para qualquer tecnologia de desenvolvimento de aplicações paraWeb. É por meio de formulários que os usuários fornecem dados, preenchempedidos de compra e (ainda mais importante) digitam o número do cartão decrédito. As informações digitadas no formulário chegam até o Servlet por meiodo objeto HttpServletRequest e são recuperadas por meio do métodogetParameter() deste objeto. Todo item de formulário HTML possui umnome e esse nome é passado como argumento para o métodogetParameter() que retorna na forma de String o valor do item deformulário.

O Servlet do exemplo XX.XX exibe o valor de dois itens de formuláriosdo tipo text. Um denominado nome e o outro denominado de sobrenome.Em seguida o Servlet cria um formulário contendo os mesmos itens deformulário. Note que um formulário é criado por meio do tag <form>. Comoparâmetros opcionais deste tag temos método da requisição (method), é a URLpara onde será submetida a requisição (action). No caso do exemplo, ométodo adotado é o POST e a requisição será submetida ao próprio ServletForm.

import java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;

public class Form extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { res.setContentType("text/html");

PrintWriter out = res.getWriter(); out.println("<html>"); out.println("<head><title>Trata formulario</title></head>"); out.println("<body bgcolor=\"white\">");

out.println("<h3>Trata formulario</h3>"); String nome = req.getParameter("nome");

Page 369: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

368

String sobreNome = req.getParameter("sobrenome"); if (nome != null || sobreNome != null) { out.println("Nome = " + nome + "<br>"); out.println("Sobrenome = " + sobreNome); } out.println("<P>"); out.print("<form action=\"Form\" method=POST>"); out.println("Nome : <input type=text size=20 name=nome><br>"); out.println("Sobrenome: <input type=text size=20 name=sobrenome><br>"); out.println("<input type=submit>"); out.println("</form>"); out.println("</body></html>"); }

public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { doGet(req, res); }}

Exemplo XX.XX- Servlet para lidar com um formulário simples.

Lidando com Cookies

Um cookie nada mais é que um bloco de informação que é enviado doservidor para o navegador no cabeçalho página. A partir de então, dependendodo tempo de validade do cookie, o navegador reenvia essa informação para oservidor a cada nova requisição. Dependo do caso o cookie é tambémarmazenado no disco da máquina cliente e quando o site é novamente visitado ocookie enviado novamente para o servidor, fornecendo a informação desejada.

Os cookies foram a solução adotada pelos desenvolvedores do Netscapepara implementar a identificação de clientes sobre um protocolo HTTP que nãoé orientado à conexão. Esta solução, apesar das controvérsias sobre apossibilidade de quebra de privacidade, passou ser amplamente adotada e hojeos cookies são parte integrante do padrão Internet, normalizados pela normaRFC 2109.

A necessidade da identificação do cliente de onde partiu a requisição e omonitoramento de sua interação com o site (denominada de sessão) é importantepara o desenvolvimento de sistemas para a Web pelas seguintes razões:

Page 370: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

369

• É necessário associar os itens selecionados para compra com ousuário que deseja adquiri-los. Na maioria da vezes a seleção dositens e compra é feita por meio da navegação de várias páginas dosite e a todo instante é necessário distinguir os usuários que estãorealizando as requisições.

• É necessário acompanhar as interação do usuário com o site paraobservar seu comportamento e, a partir dessas informações, realizaradaptações no site para atrair um maior número de usuários ourealizar campanhas de marketing.

• É necessário saber que usuário está acessando o site para, de acordocom o seu perfil, fornecer uma visualização e um conjunto defuncionalidades adequadas às suas preferências.

Todas essas necessidades não podem ser atendidas com o uso básico doprotocolo HTTP, uma vez que ele não é orientado à sessão ou conexão. Com oscookies é possível contornar essa deficiência, uma vez que as informações quesão neles armazenadas podem ser usadas para identificar os clientes. Existemoutras formas de contornar a deficiência do protocolo de HTTP, como acodificação de URL e o uso de campos escondidos nas páginas HTML, mas ouso de cookies é a técnica mais utiliza, por ser mais simples e padronizada. Noentanto, o usuário pode impedir que o navegador aceite cookies, o que torna oato de navegar pela Web muito desagradável. Neste caso, é necessário utilizar asoutras técnicas para controle de sessão.

A API Servlet permite a manipulação explicita de cookies. Para controlede sessão o programador pode manipular diretamente os cookies, ou usar umaabstração de nível mais alto, implementada por meio do objeto HttpSession.Se o cliente não permitir o uso de cookies a API Servlet fornece métodos para acodificação de URL. O exemplo XX.XX mostra o uso de cookies paraarmazenar as informações digitadas em um formulário.

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class CookieTeste extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponseres) throws IOException, ServletException {

Page 371: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

370 res.setContentType("text/html");

PrintWriter out = res.getWriter(); out.println("<html>"); out.println("<body bgcolor=\"white\">"); out.println("<head><title>Teste de Cookies</title></head>"); out.println("<body>");

out.println("<h3>Teste de Cookies</h3>");

Cookie[] cookies = req.getCookies(); if (cookies.length > 0) { for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; out.print("Cookie Nome: " + cookie.getName() +"<br>"); out.println(" Cookie Valor: " + cookie.getValue() +"<br><br>"); } }

String cName = req.getParameter("cookienome"); String cValor = req.getParameter("cookievalor"); if (cName != null && cValor != null) { Cookie cookie = new Cookie(cName ,cValor); res.addCookie(cookie); out.println("<P>"); out.println("<br>"); out.print("Nome : "+cName +"<br>"); out.print("Valor : "+cValor); }

out.println("<P>"); out.print("<form action=\"CookieTeste\" method=POST>"); out.println("Nome : <input type=text length=20 name=cookienome><br>"); out.println("Valor : <input type=text length=20 name=cookievalor><br>"); out.println("<input type=submit></form>"); out.println("</body>"); out.println("</html>"); }

public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { doGet(req, res); }}

Page 372: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

371

Exemplo XX.XX- Servlet para lidar com Cookies.

Para se criar um cookie é necessário criar um objeto Cookie, passandopara o construtor um nome e um valor, sendo ambos instâncias de String. Ocookie é enviado para o navegador por meio do método addCookie() doobjeto HttpServletResponse. Um vez que os cookies são enviados nocabeçalho da página, o método addCookie() deve ser chamado antes doenvio de qualquer conteúdo para o navegador. Para recuperar os cookiesenviados pelo navegador usa-se o método getCookies() do objetoHttpServletRequest que retorna um array de Cookie. Os métodosgetName() e getvalue() do objeto Cookie são utilizados para recuperaro nome o valor da informação associada ao cookie.

Os objetos da classe Cookie possuem vários métodos para controle douso de cookies. É possível definir tempo de vida máximo do cookie, os domíniosque devem receber o cookie (por default o domínio que deve receber o cookie éo que o criou), o diretório da página que deve receber o cookie, se o cookie deveser enviado somente sob um protocolo seguro e etc. Por exemplo, para definir aidade máxima de um cookie devemos utilizar o método setMaxAge(),passando um inteiro como parâmetro. Se o inteiro for positivo indicará emsegundos o tempo máximo de vida do cookie. Um valor negativo indica que ocookie deve apagado quando o navegador terminar. O valor zero indica que ocookie deve ser apagado imediatamente. O trecho de código exemplo XX.XXmostra algumas alterações no comportamento default de um cookie.

...Cookie cookie = new Cookie(cName ,cValor);cookie.setDomain(“*.uvf.br”); // todos os domínios como dpi.ufv.br mas não *.dpi.ufv.brcookie.setMaxAge (3600); // uma hora de tempo de vida...

Exemplo XX.XX- Mudanças no comportamento default do cookie.

Lidando com Sessões

A manipulação direta de cookies para controle de sessão é um tanto baixonível, uma vez que o usuário deve se preocupar com a identificação, tempo devida e outros detalhes. Por isso a API Servlet fornece um objeto com controles

Page 373: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

372

de nível mais alto para monitorar a sessão, o HttpSession. O objetoHttpSession monitora a sessão utilizando cookies de forma transparente. Noentanto, se o cliente não aceitar o uso de cookies é possível utilizar comoalternativa a codificação de URL para adicionar o identificador da sessão. Essaopção, apesar de ser mais genérica, não á primeira opção devido a possibilidadede criação de gargalos pela necessidade da análise prévia de todas requisiçõesque chegam ao servidor. O exemplo XX.XX mostra o uso de um objetoHttpSession para armazenar as informações digitadas em um formulário.

import java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;

public class SessionTeste extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { resp.setContentType("text/html");

PrintWriter out = resp.getWriter(); out.println("<html><head>"); out.println("<title>Teste de Sessao</title>"); out.println("</head>"); out.println("<body>"); out.println("<h3>Teste de Sessao</h3>"); HttpSession session = req.getSession(true); out.println("Identificador: " + session.getId()); out.println("<br>"); out.println("Data: "); out.println(new Date(session.getCreationTime()) + "<br>"); out.println("Ultimo acesso: "); out.println(new Date(session.getLastAccessedTime()));

String nomedado = req.getParameter("nomedado"); String valordado = req.getParameter("valordado"); if (nomedado != null && valordado != null) { session.setAttribute(nomedado, valordado); }

out.println("<P>"); out.println("Dados da Sessao:" + "<br>"); Enumeration valueNames = session.getAttributeNames();

Page 374: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

373

while (valueNames.hasMoreElements()) { String name = (String)valueNames.nextElement(); String value = (String) session.getAttribute(name); out.println(name + " = " + value+"<br>"); }

out.println("<P>"); out.print("<form action=\"SessionTeste\" method=POST>"); out.println("Nome: <input type=text size=20 name=nomedado><br>"); out.println("Valor: <input type=text size=20 name=valordado><br>"); out.println("<input type=submit>"); out.println("</form>"); out.println("</body></html>"); }

public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { doGet(req, resp); }}

Exemplo XX.XX- Servlet para lidar com Sessões.

Para controlar a sessão é necessário obter um objeto HttpSession pormeio do método getSession() do objeto HttpServletRequest. Opcionalmente, ométodo getSession() recebe como argumento um valor booleano que indica se épara criar o objeto HttpSession se ele não existir (argumento true) ou se é pararetorna null caso ele não exista (argumento false). Para se associar um objeto ouinformação à sessão usa-se o método setAttribute() do objeto HttpSession,passando para o método um String e um objeto que será identificado pelo String.Note que o método aceita qualquer objeto e, portanto, qualquer objeto pode serassociado à sessão. Os objetos associados a uma sessão são recuperados com ouso método getAttribute() do objeto HttpSession, que recebe como argumento onome associado ao objeto. Para se obter uma enumeração do nomes associados àsessão usa-se o método getAttributeNames() do objeto HttpSession.

A figura XX.XX mostra o resultado da execução do exemplo XX.XX.

Page 375: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

374

Teste de Sessao

Identificador: session3Data: Sun May 28 15:19:15 GMT-03:00 2000Ultimo acesso: Sun May 28 15:19:43 GMT-03:00 2000

Dados da Sessao:Alcione = 4Alexandra = 6NomeValor

Figura XVI-1 Saída resultante da execução do Servlet que lida com Sessões.

Enviar Consulta

Page 376: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

375

JSP

Servlets é uma boa idéia, mas você se imaginou montando uma páginacomplexa usando println()? Muitas vezes o desenvolvimento de um site éuma tarefa complexa que envolve vários profissionais. A tarefa de projeto dolayout da página fica a cargo do Web Designer, incluindo a diagramação dostextos e imagens, aplicação de cores, tratamento das imagens, definição daestrutura da informação apresentada no site e dos links para navegação pelamesma. Já o Desenvolvedor Web é responsável pela criação das aplicações quevão executar em um site. O trabalho destes dois profissionais é somado nacriação de um único produto, mas durante o desenvolvimento a interferênciamutua deve ser a mínima possível. Ou seja, um profissional não deve precisaralterar o que é foi feito pelo outro profissional para cumprir sua tarefa. Atecnologia Servlet não nos permite atingir esse ideal. Por exemplo, suponha queum Web Designer terminou o desenvolvimento de uma página e a entregou parao Desenvolvedor Web codificar em um Servlet. Se após a codificação o WebDesigner desejar realizar uma alteração na página será necessário que ele altere ocódigo do Servlet (do qual ele nada entende) ou entregar uma nova página para oDesenvolvedor Web para que ele a codifique totalmente mais uma vez. Qualqueruma dessas alternativas são indesejáveis e foi devido a esse problema a Sundesenvolveu uma tecnologia baseada em Servlets chamada de JSP.

Java Server Pages (JSP) são páginas HTML que incluem código Java eoutros tags especiais. Desta forma as partes estáticas da página não precisam sergeradas por println(). Elas são fixadas na própria página. A parte dinâmicaé gerada pelo código JSP. Assim a parte estática da página pode ser projetadapor um Web Designer que nada sabe de Java.

A primeira vez que uma página JSP é carregada pelo container JSP ocódigo Java é compilado gerando um Servlet que é executado, gerando umapágina HTML que é enviada para o navegador. As chamadas subsequentes sãoenviadas diretamente ao Servlet gerado na primeira requisição, não ocorrendomais as etapas de geração e compilação do Servlet.

A figura XX.XX mostra um esquema das etapas de execução de umapágina JSP na primeira vez que é requisitada. Na etapa (1) a requisição é enviadapara um servidor Web que reencaminha a requisição (etapa 2) para o containerServlet/JSP. Na etapa (3) o container verifica que não existe nenhuma instânciade Servlet correspondente à página JSP. Neste caso, a página JSP é traduzidapara código fonte de uma classe Servlet que será usada na resposta à requisição.Na etapa (4) o código fonte do Servlet é compilado, e na etapa (5) é criada uma

Page 377: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

376

instância da classe. Finalmente, na etapa (6) é invocado o método service()da instância Servlet para gerar a resposta à requisição.

Figura XVI-1 Etapas da primeira execução de uma página JSP.

A idéia de se usar scripts de linguagens de programação em páginasHTML que são processados no lado servidor para gerar conteúdo dinâmico nãoé restrita à linguagem Java. Existem várias soluções desse tipo fornecida poroutros fabricantes. Abaixo segue uma comparação de duas das tecnologias maispopulares com JSP.

PHP X JSP

PHP (Personal Home Pages) é uma linguagem script para ser executadano lado servidor criada em 1994 como um projeto pessoal de Rasmus Lerdorf.Atualmente encontra-se na versão 4. A sintaxe é fortemente baseada em C maspossui elementos de C++, Java e Perl. Possui suporte à programação OO pormeio de classes e objetos. Possui também suporte extensivo à Banco de dadosODBC, MySql, Sybase, Oracle e outros. PHP é uma linguagem mais fácil nodesenvolvimento de pequenas aplicações para Web em relação à JSP, uma vez

ServidorHttp

(1)Requisição de

página JSP

ContainerServlet/JSP Página

jsp

FonteServlet

(3)Traduz

(2)Encaminha a requisição

(5)Instancia e

executa

(6)Resposta àrequisição

Navegador

BytecodeServlet

(4)Compila

Page 378: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

377

que é uma linguagem mais simples e menos rígida do que JSP. No entanto, amedida que passamos para aplicações de maior porte, o uso de PHP não éindicado, uma vez que necessário o uso de linguagens com checagem maisrígidas e com maior suporte à escalabilidade, como é o caso de Java.

ASP X JSP

ASP (Active Server Pages) é a solução desenvolvida pela Microsoft®para atender as requisições feitas à servidores Web. Incorporada inicialmenteapenas ao Internet Information Server (IIS), no entanto, atualmente já ésuportada por outros servidores populares, como o Apache. O desenvolvimentode páginas que usam ASP envolve a produção de um script contendo HTMLmisturado com blocos de código de controle ASP. Este código de controle podeconter scripts em JavaScript ou VBScript. A primeira vantagem de JSP sobreASP é que a parte dinâmica é escrita em Java e não Visual Basic ou outralinguagem proprietária da Microsoft, portanto JSP é mais poderoso e fácil deusar. Em segundo lugar JSP é mais portável para outros sistemas operacionais eservidores WEB que não sejam Microsoft.

Primeiro exemplo em JSP

Para que o leitor possa ter uma idéia geral da tecnologia JSPapresentaremos agora a versão JSP do Olá mundo. O exemplo XX.XX mostra ocódigo da página.

<html> <head> <title>Exemplo JSP</title> </head> <body> <% String x = "Ol&aacute; Mundo!"; %> <%=x%> </body></html>

Exemplo XX.XX- Versão JSP do Olá mundo.

Page 379: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

378

Quem está habituado aos tags HTML notará que se trata basicamente deuma página HTML contendo código Java delimitado pelos símbolos “<%” e“%>”. Para facilitar a visualização destacamos os scripts Java com negrito. Noprimeiro trecho de script é declarada uma variável x com o valor “Olá mundo”(a seqüência &acute; é denota ‘á’ em HTML). No segundo trecho de script oconteúdo da variável x é extraído e colocado na página resultante da execuçãodo Servlet correspondente. Em seguida mostraremos como executar o exemploXX.XX.

Executando o arquivo JSP

Para executar o exemplo XX.XX salve-o com a extensão .jsp. Porexemplo ola.jsp. Se você estiver usando o servidor Tomcat, coloque-oarquivo no subdiretório /webapps/examples/jsp do Tomcat. Por exemploexamples/jsp/teste. Para invocar o arquivo JSP basta embutir a URL emuma página ou digitar diretamente a seguinte URL no navegador.

http://localhost:8080/examples/jsp/ola.jsp

Usamos o diretório /webapps/examples/jsp para testar rapidamenteo exemplo. Para desenvolver uma aplicação é aconselhável criar um diretórioapropriado como mostrado na seção que tratou de Servlets.

O Servlet criado a partir da página JSP é colocado em um diretório detrabalho. No caso do Tomcat o Servlet é colocado em subdiretório associado àaplicação subordinado ao diretório /work do Tomcat. O exemplo XX.XXmostra os principais trechos do Servlet criado a partir da tradução do arquivoola.jsp pelo tradutor do Tomcat. Note que o Servlet é subclasse de umaclasse HttpJspBase e não da HttpServlet. Além disso, o método queexecutado em resposta à requisição é o método _jspService() e não ométodo service(). Note também que todas as partes estáticas da página JSPsão colocadas como argumentos do método write() do objeto referenciadoout.

Page 380: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

379

public class _0002fjsp_0002fola_00032_0002ejspola_jsp_0 extends HttpJspBase { ....public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { .... PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; ... try { ... out.write("<html>\r\n <head>\r\n <title>Exemplo JSP</title>\r\n</head>\r\n <body>\r\n"); String x = "Ol&aacute; Mundo!";

out.write("\r\n"); out.print(x); out.write("\r\n </body>\r\n</html>\r\n"); ... } catch (Exception ex) { ... } }}

Exemplo XX.XX- Servlet correspondente à página JSP do Olá mundo.

Objetos implícitos

No exemplo XX.XX pode-se ver a declaração de variáveis quereferenciam a alguns objetos importantes. Estas variáveis estão disponíveis parao projetista da página JSP. As variáveis mais importantes são:

Classe VariávelHttpServletRequestHttpServletResponsePageContextServletContextHttpSessionJspWriter

requestresponsepageContextapplicationsessionout

Page 381: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

380

Os objetos referenciados pelas variáveis request e response játiveram seu uso esclarecido na seção sobre Servlets. O objeto do tipoJspWriter tem a mesma função do PrinterWriter do Servlet. Os outrosobjetos terão sua função esclarecida mais adiante.

Tags JSP

Os tags JSP possuem a seguinte forma geral:

<% Código JSP %>

O primeiro caractere % pode ser seguido de outros caracteres quedeterminam o significado preciso do código dentro do tag. Os tags JSP possuemcorrespondência com os tags XML. Existem cinco categorias de tags JSP:

ExpressõesScriptletsDeclaraçõesDiretivasComentários

Em seguida comentaremos cada uma dessas categorias.

Expressões

<%= expressões %>

Expressões são avaliadas, convertidas para String e colocadas napágina enviada. A avaliação é realizada em tempo de execução, quando a páginaé requisitada.

Exemplos:<%= new java.util.Date() %><%= request.getMethod() %>

No primeiro exemplo será colocado na página a data corrente emmilésimo de segundos e no segundo será colocado o método usado na

Page 382: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

381

requisição. Note que cada expressão contém apenas um comando Java. Notetambém que o comando Java não é terminado pelo caractere ‘;’.

Scriptlets

<% código Java %>

Quando é necessário mais de um comando Java ou o resultado dacomputação não é para ser colocado na página de resposta é preciso usar outracategoria de tags JSP: os Scriptlets . Os Scriptlets permitem inserir trechos decódigo em Java na página JSP. O exemplo XX.XX mostra uma página JSPcontendo um Scriptlet que transforma a temperatura digitada em celcius para oequivalente em Fahrenheit.

<html><head><title>Conversao Celcius Fahrenheit </title></head><body>

<% String valor = request.getParameter("celcius"); if (valor != null ) { double f = Double.parseDouble(valor)*9/5 +32; out.println("<P>"); out.println("<h2>Valor em Fahrenheit:" +f +"<h2><br>"); }%><form action=conversao.jsp method=POST> Celcius: <input type=text size=20 name=celcius><br> <input type=submit></form>

</body></html>

Exemplo XX.XX- Página JSP que converte graus Celcius para Fahrenheit.

Note o uso das variáveis request e out sem a necessidade dedeclaração. Todo o código digitado é inserido no método _jspService(). Afigura XX.XX mostra o resultado da requisição após a digitação do valor 30 nacaixa de texto do formulário.

Page 383: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

382

Figura XVI-XX Resultado da conversão de 30 graus celcius.

O código dentro do scriptlet é inserido da mesma forma que é escrito etodo o texto HTML estático antes e após ou um scriptlet é convertido paracomandos print(). Desta forma o scriptlets não precisa conter comandos paracódigo estático e blocos de controle abertos afetam o código HTML envolvidospor scriptlets. O exemplo XX.XX mostra dois formas de se produzir o mesmoefeito. No código da esquerda os Scriplets se intercalam com código HTML. Ocódigo HTML, quando da tradução da página JSP para Servlet é inserido comoargumentos de métodos println() gerando o código da direita. Ambas asformas podem ser usadas em páginas JSP e produzem o mesmo efeito.

Previs&atilde;o do Tempo<% if (Math.random() < 0.5) { %>Hoje vai <B>fazer sol</B>!<% } else { %>Hoje vai <B>chover</B>!<% } %>

out.println("Previs&atilde;o do Tempo");if (Math.random() < 0.5) { out.println(" Hoje vai <B>fazer sol</B>!");} else { out.println(" Hoje vai <B>chover</B>!");}

Exemplo XX.XX- Dois códigos equivalentes.

Declarações

<%! Código Java %>

Valor em Fahrenheit:86.0

Celcius:

Enviar Consulta

Page 384: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

383

Uma declaração JSP permite definir variáveis ou métodos que sãoinseridos no corpo do Servlet. Como as declarações não geram saída, elas sãonormalmente usadas em combinação com expressões e scriptlets. O ExemploXX.XX mostra a declaração de uma variável que é usada para contar o númerode vezes que a página corrente foi requisitada desde que foi carregada.

<%! Private int numAcesso = 0; %>Acessos desde carregada:<%= ++ numAcesso %>

Exemplo XX.XX- Declaração de uma variável usando o tag de declaração.

As variáveis declaradas desta forma serão variáveis de instância. Já asvariáveis declaradas em Scriptlets são variáveis locais ao método_jspService(). Por isso é possível contar o número de requisições com oexemplo XX.XX. Se variável fosse declarada em um Scriptlet a variável serialocal ao método _jspService() e, portanto, teria seu valor reinicializado acada chamada.

Como já foi dito, os tags de declarações permitem a declaração demétodos. O Exemplo XX.XX mostra a declaração de um método que convertecelcius para Fahrenheit.

<%! private double converte(double c) { return c*9/5 +32; } %>

Exemplo XX.XX- Declaração de um método para a conversão de celcius paraFahrenheit.

Comentários

Page 385: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

384

Existem dois tipos de comentários utilizados em páginas JSP. O primeiroexclui todo o bloco comentado da saída gerada pelo processamento da página. Aforma geral deste tipo de comentário é a seguinte:

<%--comentário --%>

O segundo tipo de comentário é o utilizado em páginas HTML. Nestecaso o comentário é enviado dentro da página de resposta. A forma geral destetipo de comentário é a seguinte:

<!—comentário -->

Diretivas

Diretivas são mensagens para JSP container. Elas não enviam nada para apágina mas são importantes para definir atributos JSP e dependências com o JSPcontainer. A forma geral da diretivas é a seguinte:

<%@ Diretiva atributo="valor" %>

ou<%@ Diretiva atributo1 ="valor1" atributo2 ="valor2" ... atributoN =" valorN " %>

Em seguida comentaremos as principais diretivas.

Diretiva page

<%@ page atributo1 ="valor1" ... atributoN =" valorN " %>

A diretiva page permite a definição dos seguintes atributos:

importcontentTypeisThreadSafe

Page 386: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

385

sessionbufferautoflushinfoerrorPageisErrorPagelanguage

Segue a descrição de cada um desses atributos.

Atributo e Forma Geral Descriçãoimport="package.class"

ou

import="package.class1,...,package.classN"

Permite especificar os pacotes que devem serimportados para serem usados na página JSP.

Exemplo:

<%@ page import="java.util.*" %>

contentType="MIME-Type" Especifica o tipo MIME da saída. O default é text/html.

Exemplo:

<%@ page contentType="text/plain" %>

possui o mesmo efeito do scriptlet

<%response.setContentType("text/plain");%>

isThreadSafe="true|false" Um valor true (default) indica um processamentonormal do Servlet, onde múltiplas requisições sãoprocessadas simultaneamente. Um valor false indica queo processamento deve ser feito por instancias separadasdo Servlet ou serialmente.

session="true|false” Um valor true (default) indica que a variávelpredefinida session (HttpSession) deve serassociada à sessão, se existir, caso contrário uma novasessão deve ser criada e associada a ela. Um valor falseindica que nenhuma sessão será usada.

buffer="sizekb|none" Especifica o tamanho do buffer para escrita usado peloobjeto JspWriter. O tamanho default não é menor que8k..

autoflush="true|false” Um valor true (default) indica que o buffer deve ser

Page 387: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

386

esvaziado quando estiver cheio.info="mensagem" Define uma cadeia de caracteres que pode ser

recuperada via getServletInfo().errorPage="url” Especifica a página JSP que deve ser processada em

caso de exceções não capturadas.isErrorPage="true|false” Indica se a página corrente pode atuar como página de

erro para outra página JSP. O default é false.Language="java” Possibilita definir a linguagem que está sendo usada. No

momento a única possibilidade é Java.

Tabela XVI.XX –Atributos da diretiva page.

Diretiva include

<%@ include file="relative url" %>

Permite incluir arquivos no momento em que a página JSP é traduzidaem um Servlet.

Exemplo:

<%@ include file="/meuarq.html" %>

Extraindo Valores de Formulários

Uma página JSP, da mesma forma que um Servlet, pode usar o objetoreferenciado pela variável request para obter os valores dos parâmetros de umformulário. O exemplo XX.XX usado para converter graus Celcius emFahrenheit fez uso deste recurso. O exemplo XX.XX mostra outra página JSPcom formulário. Note que o scriptlet é usado para obter o nome e os valores detodos os parâmetros contidos no formulário. Como o métodogetParameterNames() retorna uma referência a um objetoEnumeration é preciso importar o pacote java.util, por meio da diretivapage.

<%@ page import="java.util.*" %><html><body><H1>Formulário</H1><%

Page 388: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

387 Enumeration campos = request.getParameterNames(); While(campos.hasMoreElements()) { String campo = (String)campos.nextElement(); String valor = request.getParameter(campo); %> <li><%= campo %> = <%= valor %></li><% } %>

<form method="POST" action="form.jsp"> Nome: <input type="text" size="20" name="nome" ><br> Telefone: <input type="text" size="20" name="telefone"><br> <INPUT TYPE=submit name=submit value="envie"> </form></body></html>

Exemplo XVI.XX – Página JSP com formulário.

A figura XX.XX mostra o resultado da requisição após a digitação dosvalores Alcione e 333-3333 nas caixas de texto do formulário.

Figura XVI.XX- Saída do exemplo XX.XX.

Criando e Modificando Cookies

Formulário

• telefone = 333-3333• nome = Alcione• submit = envie

Nome:

Telefone:

envie

Page 389: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

388

Da mesma for que em Servlets os cookies em JSP são tratados por meioda classe Cookie. Para recuperar os cookies enviados pelo navegador usa-se ométodo getCookies() do objeto HttpServletRequest que retorna umarranjo de Cookie. Os métodos getName() e getvalue() do objetoCookie são utilizados para recuperar o nome o valor da informação associadaao cookie. O cookie é enviado para o navegador por meio do métodoaddCookie() do objeto HttpServletResponse. O exemplo XX.XXmostra uma página JSP que exibe todos os cookies recebidos em uma requisiçãoe adiciona mais um na resposta.

<html><body><H1>Session id: <%= session.getId() %></H1><% Cookie[] cookies = request.getCookies(); For(int i = 0; i < cookies.length; i++) { %> Cookie name: <%= cookies[i].getName() %> <br> Value: <%= cookies[i].getValue() %><br> antiga idade máxima em segundos: <%= cookies[i].getMaxAge() %><br> <% cookies[i].setMaxAge(5); %> nova idade máxima em segundos: <%= cookies[i].getMaxAge() %><br><% } %><%! Int count = 0; int dcount = 0; %><% response.addCookie(new Cookie(”Cookie " + count++, ”Valor " + dcount++)); %></body></html>

Exemplo XVI.XX – Página JSP que exibe os cookies recebidos.

A figura XX.XX mostra o resultado após três acessos seguidos à páginaJSP. Note que existe um cookie a mais com o nome JSESSIONID e valor igualà sessão. Este cookie é o usado pelo container para controlar a sessão.

Session id: 9ppfv0lsl1Cookie name: Cookie 0value: Valor 0antiga idade máxima em segundos: -1nova idade máxima em segundos: 5Cookie name: Cookie 1

Page 390: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

389

value: Valor 1antiga idade máxima em segundos: -1nova idade máxima em segundos: 5Cookie name: JSESSIONIDvalue: 9ppfv0lsl1antiga idade máxima em segundos: -1nova idade máxima em segundos: 5

Figura XVI.XX- Saída do exemplo XX.XX após três acessos.

Lidando com sessões

O atributos de uma sessão são mantidos em um objeto HttpSessionreferenciado pela variável session. Pode-se armazenar valores em uma sessãopor meio do método setAttribute() e recuperá-los por meio do métodogetAttribute(). O tempo de duração default de uma sessão inativa (sem orecebimento de requisições do usuário) é 30 minutos mas esse valor pode seralterado por meio do método setMaxInactiveInterval(). O exemploXX.XX mostra duas páginas JSP. A primeira apresenta um formulário ondepodem ser digitados dois valores recebe dois valores de digitados em umformulário e define o intervalo máximo de inatividade de uma sessão em 10segundos. A segunda página recebe a submissão do formulário, insere os valoresna sessão e apresenta os valores relacionados com a sessão assim como aidentificação da sessão.

<%@ page import="java.util.*" %><html><body><H1>Formulário</H1><H1>Id da sess&atilde;o: <%= session.getId() %></H1><H3><li>Essa sess&atilde;o foi criada em<%= session.getCreationTime() %></li></H3>

<H3><li>Antigo intervalo de inatividade = <%= session.getMaxInactiveInterval() %></li><% session.setMaxInactiveInterval(10); %><li>Novo intervalo de inatividade= <%= session.getMaxInactiveInterval() %></li></H3>

Page 391: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

390

<% Enumeration atribs = session.getAttributeNames(); while(atribs.hasMoreElements()) { String atrib = (String)atribs.nextElement(); String valor = (String)session.getAttribute(atrib); %> <li><%= atrib %> = <%= valor %></li><% } %>

<form method="POST" action="sessao2.jsp"> Nome: <input type="text" size="20" name="nome" ><br> Telefone: <input type="text" size="20" name="telefone" > <br> <INPUT TYPE=submit name=submit value="envie"> </form></body></html>

<html><body><H1>Id da sess&atilde;o: <%= session.getId() %></H1><% String nome = request.getParameter("nome"); String telefone = request.getParameter("telefone");

if (nome !=null && nome.length()>0) session.setAttribute("nome",nome); if (telefone !=null &&telefone.length()>0) session.setAttribute("telefone",telefone);%>

<FORM TYPE=POST ACTION=sessao1.jsp><INPUT TYPE=submit name=submit Value="Retorna"></FORM></body></html>

Exemplo XVI.XX – Exemplo do uso de sessão.

O exemplo XX.XX mostra que a sessão é mantida mesmo quandoo usuário muda de página. As figura XX.XX e XX.XX mostram o resultado darequisição após a digitação dos valores Alcione e 333-3333 nas caixas detexto do formulário, à submissão para página sessao2.jsp e o retorno àpágina sessao1.jsp.

Page 392: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

391

Figura XVI.XX- Tela da página sessao1.jsp.

Figura XVI.XX- Tela da página sessao2.jsp.

O Uso de JavaBeans

FormulárioId da sessão: soo8utc4m1Essa sessão foi criada em 1002202317590Antigo intervalo de inatividade = 1800Novo intervalo de inatividade= 10

telefone = 333-3333nome = Alcione

Nome:

Telefone:

envie

Id da sessão: soo8utc4m1Retorna

Page 393: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

392

A medida que o código Java dentro do HTML torna-se cada vez maiscomplexo o desenvolvedor pode-se perguntar: Java em HTML não é o problemainvertido do HTML em Servlet? O resultado não será tão complexo quantoproduzir uma página usando println()? Em outras palavras, estounovamente misturando conteúdo com forma?

Para solucionar esse problema a especificação de JSP permite o uso deJavaBeans para manipular a parte dinâmica em Java. JavaBeans já foramdescritos detalhadamente em um capítulo anterior, mas podemos encarar umJavaBean como sendo apenas uma classe Java que obedece a uma certapadronização de nomeação de métodos, formando o que é denominado depropriedade. As propriedades de um bean são acessadas por meio de métodosque obedecem a convenção getXxxx e setXxxx. , onde Xxxx é o nome dapropriedade. Por exemplo, getItem() é o método usado para retornar o valorda propriedade item. A sintaxe para o uso de um bean em uma página JSP é:

<jsp:useBean id="nome" class="package.class" />

Onde nome é o identificador da variável que conterá uma referência parauma instância do JavaBean. Você também pode modificar o atributo scopepara estabelecer o escopo do bean além da página corrente.

<jsp:useBean id="nome" scope="session" class="package.class" />

Para modificar as propriedades de um JavaBean você pode usar ojsp:setProperty ou chamar um método explicitamente em umscriptlet. Para recuperar o valor de uma propriedade de um JavaBean vocêpode usar o jsp:getProperty ou chamar um método explicitamente emum scriptlet. Quando é dito que um bean tem uma propriedade prop dotipo T significa que o bean deve prover um método getProp() e um métododo tipo setProp(T). O exemplo XX.XX mostra uma página JSP e umJavaBean. A página instancia o JavaBean, altera a propriedade mensagem erecupera o valor da propriedade, colocando-o na página.

Página bean.jsp

<HTML> <HEAD><TITLE>Uso de beans</TITLE></HEAD> <BODY> <CENTER>

Page 394: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

393

<TABLE BORDER=5> <TR><TH CLASS="TITLE"> Uso de JavaBeans </TABLE></CENTER> <P><jsp:useBean id="teste" class=”curso.BeanSimples" /><jsp:setProperty name="teste" property="mensagem" value=”Ola mundo!" /><H1> Mensagem: <I><jsp:getProperty name="teste" property="mensagem" /> </I></H1></BODY> </HTML>

Arquivo Curso/BeanSimples.java

package curso;

public class BeanSimples { private String men = "Nenhuma mensagem";

public String getMensagem() { return(men); }

public void setMensagem(String men) { this.men = men; }}

Exemplo XVI.XX – Exemplo do uso de JavaBean.

A figura XX.XX mostra o resultado da requisição dirigida à páginabean.jsp.

Figura XVI.XX- Resultado da requisição à página bean.jsp.

Se no tag setProperty usarmos o valor “*” para o atributoproperty então todos os valores de elementos de formulários que possuíremnomes iguais à propriedades serão transferidos para as respectivas propriedades

Mensagem: Ola mundo!

Uso de JavaBeans

Page 395: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

394

no momento do processamento da requisição. Por exemplo, seja uma página jspcontendo um formulário com uma caixa de texto com nome mensagem, comomostrado no exemplo XX.XX. Note que, neste caso, a propriedade mensagemdo JavaBean tem seu valor atualizado para o valor digitado na caixa de texto,sem a necessidade de uma chamada explícita no tag setProperty. Osvalores são automaticamente convertidos para o tipo correto no bean.

<HTML> <HEAD><TITLE>Uso de beans</TITLE> </HEAD><BODY> <CENTER><TABLE BORDER=5> <TR><TH CLASS="TITLE"> Uso de JavaBeans </TABLE></CENTER> <P><jsp:useBean id="teste" class="curso.BeanSimples" /><jsp:setProperty name="teste" property="*" /><H1> Mensagem: <I><jsp:getProperty name="teste" property="mensagem" /></I></H1>

<form method="POST" action="bean2.jsp"> Texto: <input type="text" size="20" name="mensagem" ><br> <INPUT TYPE=submit name=submit value="envie"></form>

</BODY> </HTML>

Exemplo XVI.XX – Exemplo de atualização automática da propriedade.

A figura XX.XX mostra o resultado da requisição dirigida à páginabean2.jsp após a digitação do texto Olá!

Figura XVI.XX- Resultado da requisição à página bean2.jsp.

Mensagem: Ola!

Uso de JavaBeans

envie

Texto:

Page 396: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

395

Escopo

Existem quatro valores possíveis para o escopo de um objeto: page,request, session e application. O default é page. A tabelaXX.XX descreve cada tipo de escopo.

Escopo Descriçãopage Objetos declarados com nesse escopo são válidos até a

resposta ser enviada ou a requisição ser encaminhadapara outro programa no mesmo ambiente, ou seja, sópodem ser referenciados nas páginas onde foremdeclarados. Objetos declarados com escopo page sãoreferenciados pelo objeto pagecontext.

request Objetos declarados com nesse escopo são válidos durantea requisição e são acessíveis mesmo quando a requisiçãoé encaminhada para outro programa no mesmo ambiente.Objetos declarados com escopo request sãoreferenciados pelo objeto request.

session Objetos declarados com nesse escopo são válidos durantea sessão desde que a página seja definida para funcionarem uma sessão. Objetos declarados com escoposession são referenciados pelo objeto session.

application Objetos declarados com nesse escopo são acessíveis porpáginas no mesmo servidor de aplicação. Objetosdeclarados com escopo application sãoreferenciados pelo objeto application.

Tabela XVI.XX –Escopo dos objetos nas páginas JSP.

Implementação de um Carrinho de compras

O exemplo abaixo ilustra o uso de JSP para implementar um carrinho decompras virtual. O carrinho de compras virtual simula um carrinho de comprasde supermercado, onde o cliente vai colocando os produtos selecionados paracompra até se dirigir para o caixa para fazer o pagamento. No carrinho decompras virtual os itens selecionados pelo usuário são armazenados em umaestrutura de dados até que o usuário efetue o pagamento. Esse tipo de exemplo

Page 397: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

396

exige que a página JSP funcione com o escopo session para manter ocarrinho de compras durante a sessão. O exemplo XX.XX mostra um exemplosimples de implementação de carrinho de compras. O exemplo é composto pordois arquivos: um para a página JSP e um para o JavaBean que armazena ositens selecionados.

Página compras.jsp

<html><jsp:useBean id="carrinho" scope="session" class="compra.Carrinho" /><jsp:setProperty name="carrinho" property="*" /><body bgcolor="#FFFFFF">

<% carrinho.processRequest(request); String[] items = carrinho.getItems(); if (items.length>0) {%> <font size=+2 color="#3333FF">Voc&ecirc; comprou os seguintes itens:</font> <ol> <% for (int i=0; i<items.length; i++) { out.println("<li>"+items[i]); } }%></ol><hr><form type=POST action= compras.jsp> <br><font color="#3333FF" size=+2>Entre um item para adicionar ou remover: </font><br> <select NAME="item"> <option>Televis&atilde;o <option>R&aacute;dio <option>Computador <option>V&iacute;deo Cassete </select> <p><input TYPE=submit name="submit" value="adicione"> <input TYPE=submit name="submit" value="remova"></form></body></html>

JavaBean compra/Carrinho.java

package compra;

Page 398: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

397

import javax.servlet.http.*;import java.util.Vector;import java.util.Enumeration;

public class Carrinho { Vector v = new Vector(); String submit = null; String item = null;

private void addItem(String name) {v.addElement(name); }

private void removeItem(String name) {v.removeElement(name); }

public void setItem(String name) {item = name; }

public void setSubmit(String s) { submit = s; }

public String[] getItems() { String[] s = new String[v.size()]; v.copyInto(s); return s; }

private void reset() { submit = null; item = null; }

public void processRequest(HttpServletRequest request) { if (submit == null) return;

if (submit.equals("adicione")) addItem(item); else if (submit.equals("remova")) removeItem(item); reset(); }}

Exemplo XVI.XX – Implementação de um carrinho de compras Virtual.

O exemplo XX.XX implementa apenas o carrinho de compras, deixandode fora o pagamento dos itens, uma vez que esta etapa depende de cada sistema.Geralmente o que é feito é direcionar o usuário para outra página onde eledigitará o número do cartão de crédito que será transmitido por meio de umaconexão segura para o servidor. Existem outras formas de pagamento, como

Page 399: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

398

boleto bancário e dinheiro virtual. O próprio carrinho de compras geralmente émais complexo, uma vez que os para compra devem ser obtidos dinamicamentede um banco de dados. A figura XX.XX mostra a tela resultante de algumasinterações com o carrinho de compras.

Figura XVI.XX- Carrinho de compras virtual.

Page 400: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

399

Reencaminhando ou Redirecionando requisições

Existem algumas situações onde pode ser desejável transferir umarequisição para outra URL. Isto é feito com frequência em sistemas quecombinam o uso de Servlets juntamente com JSP. No entanto, a transferênciapode ser para qualquer recurso. Assim, podemos transferir uma requisição de umServlet para uma página JSP, HTML ou um Servlet. Da mesma forma umapágina JSP pode transferir uma requisição para uma página JSP, HTML ou umServlet.

Existem dois tipos de transferência de requisição: o redirecionamento e oreencaminhamento. O redirecionamento é obtido usando o métodosendRedirect() de uma instância HttpServletResponse, passandocomo argumento a URL de destino. O exemplo XX.XX mostra o código de umServlet redirecionando para uma página HTML.

import javax.servlet.*;import javax.servlet.http.*;import java.io.*;

public class Redireciona extends HttpServlet{ public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.sendRedirect("/test/index.html"); }}

Exemplo XVI.XX – Redirecionamento de requisição.

Note pelo exemplo que é preciso passar o contexto do recurso(/teste). No caso de redirecionamento o a requisição corrente é perdida e umanova requisição é feita para a URL de destino. Por isso não se deve associarnenhum objeto à requisição, uma vez que o objeto HttpServletRequestcorrente será perdido. O que ocorre na prática é que o servidor envia umamensagem HTTP 302 de volta para o cliente informando que o recurso foitransferido para outra URL e o cliente envia uma nova requisição para a URLinformada.

Já no caso de reencaminhamento a requisição é encaminhada diretamentepara a nova URL mantendo todos os objetos associados e evitando uma nova ida

Page 401: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

400

ao cliente. Portanto, o uso de reencaminhamento é mais eficiente do que o usode redirecionamento. O reencaminhamento é obtido usando o métodoforward() de uma instância RequestDispatcher, passando comoargumento os objetos HttpServletRequest e HttpServletResponsepara a URL de destino. Uma instância RequestDispatcher é obtida pormeio do método getRequestDispatcher()de uma instânciaServletContext , que é obtido, por sua vez, por meio do métodogetServletContext() do Servlet. O exemplo XX.XX mostra o código deum Servlet reencaminhando a requisição para uma página JSP.

import javax.servlet.*;import javax.servlet.http.*;

public class Reencaminha extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) { try { getServletContext().getRequestDispatcher("/index.html"). forward(request,response); }catch (Exception e) { System.out.println("Servlet falhou: "); e.printStackTrace(); } }}

Exemplo XVI.XX – Reencaminhamento de requisição.

Note que não é necessário passar o contexto na URL, como é feito noredirecionamento, uma vez que a requisição é encaminhada no contextocorrente.

Page 402: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

401

Uma Arquitetura para comércio eletrônico

O projeto de uma solução para comércio eletrônico é uma tarefacomplexa e deve atender diversos requisitos. Nesta seção mostraremos umamodelo de arquitetura básico para comércio eletrônico que pode ser adaptadopara soluções mais específicas. Este modelo implementa o padrão de projetoMVC, procurando, desta forma, isolar esses aspectos de um sistema decomputação.

Tipos de aplicações na WEB

Podemos enquadra as aplicações na Web em um dos seguintes tipos:

• Business-to-consumer (B2C) – entre empresa e consumidor. Exemplo: umapessoa compra um livro na Internet.

• Business-to-business (B2B) – Troca de informações e serviços entreempresas. Exemplo: o sistema de estoque de uma empresa de automóveisdetecta que um item de estoque precisa ser resposta e faz o pedidodiretamente ao sistema de produção do fornecedor de autopeças. Neste tipode aplicação a linguagem XML possui um papel muito importante, uma vezque existe a necessidade de uma padronização dos tags para comunicação deconteúdo.

• User-to-data – acesso à bases de informação. Exemplo: uma usuárioconsulta uma base de informação.

• User-to-user – chat, e troca de informações entre usuários (Morpheus).

O exemplo que mostraremos é tipicamente um caso de User-to-data,(agenda eletrônica na Web) mas possui a mesma estrutura de um B2C.

Arquitetura MVC para a Web

A figura XX.XX contém um diagrama de blocos que mostra aparticipação de Servlets, JSP e JavaBeans na arquitetura proposta. A idéia éisolar cada aspecto do modelo MVC com a tecnologia mais adequada. A página

Page 403: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

402

JSP é ótima para fazer o papel da visão, uma vez que possui facilidades para ainserção de componentes visuais e para a apresentação de informação. Noentanto, é um pouco estranho usar uma página JSP para receber e tratar umarequisição. Esta tarefa, que se enquadra no aspecto de controle do modelo MVCé mais adequada a um Servlet, uma vez que neste momento componentes deapresentação são indesejáveis. Finalmente, é desejável que a modelagem donegócio fique isolada dos aspectos de interação. A proposta é que a modelagemdo negócio fique contida em classes de JavaBeans. Em aplicações maissofisticadas a modelagem do negócio deve ser implementada por classes deEnterprise JavaBeans (EJB), no entanto esta forma de implementação foge aoescopos deste livro. Cada componente participa da seguinte forma:

• Servlets – Atuam como controladores, recebendo as requisições dosusuários. Após a realização das análises necessária sobre a requisição,instancia o JavaBean e o armazena no escopo adequado (ou não caso o beanjá tenha sido criado no escopo) e encaminha a requisição para a página JSP.

• JavaBeans – Atuam como o modelo da solução, independente da requisiçãoe da forma de apresentação. Comunicam-se com a camada intermediária queencapsula a lógica do problema.

• JSP – Atuam na camada de apresentação utilizando os JavaBeans paraobtenção dos dados a serem exibidos, isolando-se assim de como os dadossão obtidos. O objetivo é minimizar a quantidade de código colocado napágina.

• Camada Intermediária (Middleware) – Incorporam a lógica de acesso aosdados. Permitem isolar os outros módulos de problemas como estratégias deacesso aos dados e desempenho. O uso de EJB (Enterprise JavaBeans) érecomendado para a implementação do Middleware, uma vez que os EJBspossuem capacidades para gerência de transações e persistência. Isto implicana adoção de um servidor de aplicação habilitado para EJB.

A figura XX.XX mostra a interação entre os componentes.

Page 404: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

403

Figura XV.XX. Arquitetura de uma aplicação para Comércio Eletrônico.

Essa arquitetura possui as seguintes vantagens:

1. Facilidade de manutenção: a distribuição lógica das funções entre osmódulos do sistema isola o impacto das modificações.

2. Escalabilidade: Modificações necessária para acompanhar o aumento dademanda de serviços (database pooling, clustering, etc) ficam concentradasna camada intermediária.

A figura abaixo mostra a arquitetura física de uma aplicação de comércioeletrônico.

Navegador Web

JSP(Apresentação)

RequisiçãoServlet

(controlador)

Resposta

JavaBean(modelo)

Cria uma instância

Servidor de Aplicação1

54

3

2

SGBD

JDBC

MiddleWare

Page 405: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

404

Figura XV.XX. Arquitetura física de uma aplicação para Comércio Eletrônico.

Demilitarized Zone (DMZ) é onde os servidores HTTP são instalados. ADMZ é protegida da rede púbica por um firewall, também chamado de firewallde protocolo. O firewall de protocolo deve ser configurado para permitir tráfegoapenas através da porta 80. Um segundo firewall, também chamado de firewallde domínio separa a DMZ da rede interna. O firewall de domínio deve serconfigurado para permitir comunicação apenas por meio das portas do servidorde aplicação

Agenda Web: Um Exemplo de uma aplicação Web usando aarquitetura MVC

O exemplo a seguir mostra o desenvolvimento da agenda eletrônica parao funcionamento na Web. A arquitetura adotada é uma implementação domodelo MVC. Apenas, para simplificar a solução, a camada intermediária foisimplificada e é implementada por um JavaBean que tem a função de gerenciar aconexão com o banco de dados. O banco de dados será composto por duastabelas, uma para armazenar os usuários autorizados a usar a tabela e outra paraarmazenar os itens da agenda. A figura XX.XX mostra o esquema conceitual dobanco de dados e a figura XX.XX mostra o comando para a criação das tabelas.Note que existe um relacionamento entre a tabela USUARIO e a tabela PESSOA,mostrando que os dados pessoais sobre o usuário ficam armazenados na agenda.

USUARIO PESSOA

Page 406: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

405

Figura XV.XX. Esquema conceitual do banco de dados para a agenda.

As tabelas do BD devem ser criadas de acordo com o seguinte script:

CREATE TABLE PESSOA (ID INT PRIMARY KEY, NOME VARCHAR(50) NOT NULL, TELEFONE VARCHAR(50), ENDERECO VARCHAR(80), EMAIL VARCHAR(50), HP VARCHAR(50), CELULAR VARCHAR(20), DESCRICAO VARCHAR(80));

CREATE TABLE USUARIO (ID INT PRIMARY KEY, LOGIN VARCHAR(20) NOT NULL, SENHA VARCHAR(20) NOT NULL, CONSTRAINT FK_USU FOREIGN KEY (ID) REFERENCES PESSOA(ID));

Figura XV.XX. Script para criação das tabelas.

Para se usar a agenda é necessário que exista pelo menos um usuáriocadastrado. Como no exemplo não vamos apresentar uma tela para cadastro deusuários será preciso cadastrá-los por meio comandos SQL. Os comandos dafigura XX.XX mostram como cadastrar um usuário.

INSERT INTO PESSOA(ID,NOME,TELEFONE,ENDERECO,EMAIL)VALUES(0,'Alcione de Paiva Oliveira','3899-1769', 'PH Rolfs','[email protected]');

INSERT INTO USUARIO(ID,LOGIN,SENHA) VALUES(0,'Alcione','senha');

Figura XV.XX. Script para cadastra um usuário.

O sistema e-agenda é composta pelos seguintes arquivos:

1:1 1:1

Page 407: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

406

Arquivo Descriçãoagenda.html Página inicial do site, contendo o formulário para a

entrada do login e senha para entrar no restante dosite.

principal.jsp Página JSP contendo o formulário para entrada dedados para inserção, remoção ou consulta de itens daagenda.

LoginBean.java JavaBean responsável por verificar se o usuário estáautorizado a acessar a agenda.

AgendaServlet.java Servlet responsável pelo tratamento de requisiçõessobre alguma função da agenda (consulta, inserção eremoção)

AcaoBean.java JavaBean responsável pela execução da açãosolicitada pelo usuário.

ConnectionBean.java JavaBean responsável pelo acesso ao DB e controledas conexões.

Tabela XV.XX. Arquivos do sistema e-agenda.

O diagrama de colaboração abaixo mostra as interação entre oscomponentes do sistema.

Figura XV.XX. Interação entre os componentes do sistema.

1 e 4 – Requisições2 e 6 – instanciações4 – reencaminhamento de

requisições3,5,7 e 8 – Chamadas de métodos

agenda.html AgendaServlet

ConnectionBeanLoginBean

AcaoBean

principal.jsp

1

24

5

78

36

Page 408: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

407

Descreveremos agora cada componente da aplicação. O exemplo XX.XXmostra código HTML da página agenda.html. Esta é a página inicial daaplicação. Ela contém o formulário para a entrada do login e senha para entrarno restante do site.

123456789101112131415161718192021222324252627282920313233343536373839

<HTML><HEAD> <TITLE>Agenda</TITLE></HEAD>

<BODY BGCOLOR="#FFFFFF"><P align="center"><IMG src="tit.gif" width="350" height="100" border="0"></P><BR>

<CENTER> <FORM method="POST" name="TesteSub" onsubmit="return TestaVal()"action="/agenda/agenda"><BR> Login:<INPUT size="20" type="text" name="login"><BR><BR> Senha:<INPUT size="20" type="password" name="senha"><BR><BR><BR> <INPUT type="submit" name="envia" value="Enviar"> <INPUT size="3" type="Hidden" name="corrente" value="0"><BR> </FORM></CENTER><SCRIPT language="JavaScript"><!--function TestaVal(){ if (document.TesteSub.login.value == "") { alert ("Campo Login nao Preenchido...Form nao Submetido") return false } else if (document.TesteSub.senha.value == "") { alert ("Campo Senha nao Preenchido...Form nao Submetido") return false } else { return true }}//--></SCRIPT></BODY></HTML>

Page 409: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

408

Exemplo XVI.XX – agenda.html.

O formulário está definido nas linha 11 a 17. Na linha 12 o parâmetroaction indica a URL que dever receber a requisição. A URL é virtual e suaassociação com o Servlet AgendaServlet será definida no arquivoweb.xml. Na linha 16 é definido um campo oculto (Hidden) como o nome decorrente e valor 0. Ele será usado pelo AgendaServlet reconhecer apágina de onde saiu a requisição. As linha 19 a 31 definem uma função emJavaScript que será usada para verificar se o usuário digitou o nome e a senhaantes de enviar a requisição ao usuário. O uso de JavaScript no lado cliente paracriticar a entrada do usuário é muito comum pois diminui a sobrecarga doservidor.

O exemplo XX.XX mostra código da página principal.jsp. Estapágina contém o formulário para entrada de dados para inserção, remoção ouconsulta de itens da agenda. Na linha 4 a diretiva page define que o servidordeve acompanhar a sessão do usuário e importa o pacote agenda. Na linha 7um objeto da classe agenda.LoginBean é recuperado da sessão por meio dométodo getAttribute(). Para recuperar o objeto é preciso passar para ométodo o nome que está associado ao objeto na sessão. De forma semelhante, nalinha 8 um objeto da classe agenda.AcaoBean é recuperado da requisiçãopor meio do método getAttribute(). Este objeto é recuperado darequisição porque cada requisição possui uma ação diferente associada. Na linha9 é verificado se objeto agenda.LoginBean foi recuperado e se o retorno dométodo getStatus() é true. Se o objeto agenda.LoginBean não foirecuperado significa que existe uma tentativa de acesso direto à páginaprincipal.jsp sem passar primeiro pela página agenda.html ou que asessão se esgotou. Se o método getStatus() retornar false significa que ousuário não está autorizado a acessar essa página. Nestes casos é processado ocódigo associado ao comando else da linha 51 que apaga a sessão por meio dométodo invalidate() do objeto HttpSession (linha 53) e mostra amensagem “Usuário não autorizado” (linha 55). Caso o objeto indique que ousuário está autorizado os comandos internos ao if são executados. Na linha 11é mostrada uma mensagem com o nome do usuário obtido por meio do métodogetNome() do objeto agenda.LoginBean . Na linha 13 é mostrado oresultado da ação anterior por meio do método toString() do objetoagenda.AcaoBean. A ação pode ter sido de consulta, inserção de um novoitem na agenda e remoção de um item na agenda. No primeiro caso é mostradouma lista dos itens que satisfizeram a consulta. No segundo e terceiro casos éexibida uma mensagem indicado se a operação foi bem sucedida.

Page 410: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

409

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253

<HTML><HEAD><TITLE>Tela da Agenda </TITLE></HEAD><BODY bgcolor="#FFFFFF"><%@ page session="true" import="agenda.*" %>

<% agenda.LoginBean lb = (agenda.LoginBean) session.getAttribute("loginbean"); agenda.AcaoBean ab = (agenda.AcaoBean) request.getAttribute("acaobean"); if (lb != null && lb.getStatus()) { %> <H2>Sess&atilde;o do <%= lb.getNome() %></H2> <% if (ab!=null) out.println(ab.toString()); %>

<P><BR></P> <FORM method="POST" name="formprin" onsubmit="return TestaVal()"action="/agenda/agenda"> Nome: <INPUT size="50" type="text" name="nome"><BR> Telefone: <INPUT size="20" type="text" name="telefone"><BR> Endere&ccedil;o: <INPUT size="50" type="text" name="endereco"><BR> Email: <INPUT size="50" type="text" name="email"><BR><BR> P&aacute;gina: <INPUT size="50" type="text" name="pagina"><BR> Celular: <INPUT size="20" type="text" name="celular"><BR> Descri&ccedil;&atilde;o: <INPUT size="20" type="text" name="descricao"> <BR><CENTER> <INPUT type="submit" name="acao" value="Consulta"> <INPUT type="submit" name="acao" value="Insere"> <INPUT type="submit" name="acao" value="Apaga"></CENTER> <INPUT size="3" type="Hidden" name="corrente" value="1"></FORM>

<SCRIPT language="JavaScript"><!--function TestaVal(){ if (document.formprin.nome.value == "" && document.formprin.descricao.value== "") { alert ("Campo Nome ou Descricao devem ser Preenchidos!") return false } else { return true }}//--></SCRIPT>

<%}else{ session.invalidate();

Page 411: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

410545556575859

%><H1>Usu&aacute;rio n&atilde;o autorizado</H1><%}%></BODY></HTML>

Exemplo XVI.XX – principal.jsp.

As linhas 17 a 31 definem o código do formulário de entrada. Nas linhas17 e 18 são definidos os atributos do formulário. O atributo method indica arequisição será enviada por meio do método POST. O atributo name define onome do formulário como sendo formprin. O atributo onsubmit define quea função javaSript TestaVal() deve ser executada quando o formulário forsubmetido. Finalmente, o atributo action define a URL para onde a requisiçãodeve ser enviada. Neste caso a URL é agenda/agenda que está mapeada parao Servlet AgendaServlet. O mapeamento é feito no arquivo web.xml dodiretório web-inf do contexto agenda, como mostrado na figura XX.XX. Aslinhas 19 a 25 definem os campos de texto para entrada dos valores. As linhas 27a 29 definem os botões de submit. Todos possuem o mesmo nome, de forma queo Servlet precisa apenas examinar o valor do parâmetro acao para determinarqual ação foi solicitada Na linha 30 é definido um campo oculto (Hidden)como o nome de corrente e valor 0. Ele será usado pelo AgendaServletreconhecer a página de onde saiu a requisição. As linha 33 a 47 definem umafunção em JavaScript que será usada para verificar se o usuário entrou comvalores nos campos de texto nome ou decricao. No mínimo um dessescampos deve ser preenchido para que uma consulta possa ser realizada.

O exemplo XX.XX mostra código do JavaBean usado para intermediar aconexão com o banco de dados. O JavaBean ConnectionBean tem aresponsabilidade de abrir uma conexão com o banco de dados, retornar umareferência desta conexão quando solicitado e registrar se a conexão esta livre ouocupada. Neste exemplo o se encarrega apenas de obter a conexão e fechá-la, noentanto, em aplicação com maior número de acessos ao banco de dados pode sernecessário um maior controle sobre o uso das conexões, mantendo-as em umaestrutura de dados denominada de pool de conexões. Na linha 12 podemosobservar que o construtor da classe foi declarado com o modificador de acessoprivate. Isto significa que não é possível invocar o construtor por meio de umobjeto de outra classe. Isto é feito para que se possa ter um controle sobre acriação de instâncias da classe. No nosso caso permitiremos apenas que umainstância da classe seja criada, de modo que todas as referências apontem para

Page 412: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

411

esse objeto. Esta técnica de programação, onde se permite uma única instânciade uma classe é denominada de padrão de projeto Singleton. O objetivo deutilizarmos este padrão é porque desejamos que apenas um objeto controle aconexão com o banco de dados. Ma se o construtor não pode ser chamadointernamente como uma instância da classe é criada e sua referência é passadapara outros objetos? Esta é a tarefa do método estático getInstance()(linhas 14 a 19). Este método verifica se já existe a instância e retorna areferência. Caso a instância não exista ela é criada antes de se retornar areferência. O método init() (linhas 21 a 27) é chamado pelo construtor paraestabelecer a conexão com o SGBD. Ele carrega o driver JDBC do tipo 4 paraHSQLDB e obtém uma conexão com o SGBD. O métododevolveConnection() (linhas 29 a 34) é chamado quando se desejadevolver a conexão. Finalmente, o método getConnection() (linhas 36 a46) é chamado quando se deseja obter a conexão.

1234567891011121314151617181920212223242526272829

package agenda;

import java.sql.*;import java.lang.*;import java.util.*;

public class ConnectionBean { private Connection con=null; private static int clients=0; static private ConnectionBean instance=null;

private ConnectionBean() { init(); }

static synchronized public ConnectionBean getInstance() { if (instance == null) { instance = new ConnectionBean(); } return instance; }

private void init() { try { Class.forName("org.hsqldb.jdbcDriver"); con= DriverManager.getConnection("jdbc:hsqldb:hsql://localhost","sa",""); } catch(Exception e){System.out.println(e.getMessage());}; }

public synchronized void devolveConnection(Connection con) {

Page 413: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

412

303132333435363738394041424344454647

if (this.con==con) { clients--; notify(); } }

public synchronized Connection getConnection() { if(clients>0) { try { wait(5000); } catch (InterruptedException e) {}; if(clients>0) return null; } clients ++; return con; }}

Exemplo XVI.XX – ConnectionBean.java.

O exemplo XX.XX mostra código do JavaBean usado para verificar se ousuário está autorizado a usar a agenda. O JavaBean LoginBean recebe onome e a senha do usuário, obtém a conexão com o SGBD e verifica se ousuário está autorizado, registrando o resultado da consulta na variável status(linha 10). Tudo isso é feito no construtor da classe (linhas 12 a 35). Note que naconstrução do comando SQL (linhas 17 a 20) é inserido uma junção entre astabelas PESSOA e USUARIO de modo a ser possível recuperar os dadosrelacionados armazenados em ambas as tabelas. Os métodos getLogin(),getNome() e getStatus() (linhas 36 a 38) são responsáveis pelo retornodo login, nome e status da consulta respectivamente.

1234567891011

package agenda;

import java.sql.*;import java.lang.*;import java.util.*;

public class LoginBean { protected String nome = null; protected String login= null; protected boolean status= false;

Page 414: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

413

12131415161718192021222324252627282930313233343536373839

public LoginBean(String login, String senha) { this.login = login; Connection con=null; Statement stmt =null; String consulta = "SELECT NOME FROM PESSOA, USUARIO "+ "WHERE USUARIO.ID = PESSOA.ID AND "+ "USUARIO.SENHA ='"+senha+"' AND "+ "USUARIO.LOGIN ='"+login+"'"; try { con=ConnectionBean.getInstance().getConnection(); stmt = con.createStatement(); ResultSet rs =stmt.executeQuery(consulta); if(rs.next()) { status = true; nome = rs.getString("NOME"); } } catch(Exception e){System.out.println(e.getMessage());} finally { ConnectionBean.getInstance().devolveConnection(con); try{stmt.close();}catch(Exception ee){}; }

} public String getLogin(){return login;} public String getNome(){return nome;} public boolean getStatus(){return status;}}

Exemplo XVI.XX – LoginBean.java.

O exemplo XX.XX mostra código do Servlet que implementa a camadade controle do modelo MVC. O Servlet AgendaServlet recebe asrequisições e, de acordo com os parâmetros, instância os JavaBeans apropriadose reencaminha as requisições para as páginas corretas. Tanto o métododoGet() (linhas 9 a 12) quanto o método doPost()(linhas 13 a 17) invocamo método performTask()(linhas 19 a 61) que realiza o tratamento darequisição. Na linhas 24 a 26 do método performTask() é obtido o valor doparâmetro corrente que determina a página que originou a requisição. Se ovalor for nulo é assumido o valor default zero. Na linha 30 é executado umcomando switch sobre esse valor, de modo a desviar para bloco de comandosadequado. O bloco que vai da linha 32 até a linha 43 trata a requisição originadaem uma página com a identificação 0 (página agenda.html). Nas linhas 32 e33 são recuperados o valor de login e senha digitados pelo usuário. Se algum

Page 415: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

414

desses valores for nulo então a requisição deve ser reencaminhada para a páginade login (agenda.html) novamente (linha 35). Caso contrário é instanciadoum objeto LoginBean, inserido na sessão corrente e definida a páginaprincipal.jsp como a página para o reencaminhamento da requisição(linhas 38 a 41). Já o bloco que vai da linha 44 até a linha 54 trata a requisiçãooriginada em uma página com a identificação 1 (página principal.jsp). Nalinha 44 é recuperado o objeto HttpSession corrente. O argumento false éutilizado para impedir a criação de um novo objeto HttpSession caso nãoexista um corrente. Se o valor do objeto for null, então a requisição deve serreencaminhada para a página de login (linha 47). Caso contrário é instanciadoum objeto AcaoBean, inserido na requisição corrente e definida a páginaprincipal.jsp como a página para o reencaminhamento da requisição(linhas 50 a 52). Na linha 56 a requisição é reencaminhada para a páginadefinida (página agenda.html ou principal.jsp).

12345678910111213141516171819202122232425262728

package agenda;

import javax.servlet.*;import javax.servlet.http.*;import agenda.*;

public class AgendaServlet extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) { performTask(request,response); } public void doPost(HttpServletRequest request, HttpServletResponse response) { performTask(request,response); }

public void performTask(HttpServletRequest request, HttpServletResponse response) { String url; HttpSession sessao; String corrente = request.getParameter("corrente"); int icorr=0; if (corrente != null) icorr = Integer.parseInt(corrente);

try

Page 416: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

415

29303132333435363738394041424344454647484950515253545556575859606162

{ switch(icorr) { case 0: String login = request.getParameter("login"); String senha = request.getParameter("senha"); if (login == null||senha == null) url= "/agenda.html"; else { sessao = request.getSession(true); sessao.setAttribute("loginbean", new agenda.LoginBean(login,senha)); url= "/principal.jsp"; }; break; case 1: sessao = request.getSession(false); if (sessao == null) url= "/agenda.html"; else { request.setAttribute("acaobean", new agenda.AcaoBean(request)); url= "/principal.jsp"; }; break; } getServletContext().getRequestDispatcher(url).forward(request,response); }catch (Exception e) { System.out.println("AgendaServlet falhou: "); e.printStackTrace(); } }}

Exemplo XVI.XX – AgendaServlet.java.

O exemplo XX.XX mostra código do JavaBean usado para realizar amanutenção da agenda. O JavaBean AcaoBean é responsável pela consulta,remoção e inserção de novos itens na agenda. Um objeto StringBufferreferenciado pela variável retorno é utilizado pelo JavaBean para montar oresultado da execução. O construtor (linhas 16 a 27) verifica o tipo de requisiçãoe invoca o método apropriado.

O método consulta() (linhas 29 a 77) é responsável pela realizaçãode consultas. As consultas podem ser realizadas sobre o campo nome ou

Page 417: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

416

descrição e os casamentos podem ser parciais, uma vez que é usado o operadorLIKE. A consulta SQL é montada nas linhas 40 a 47. Na linha 50 é obtida umaconexão com SGBD por meio do objeto ConnectionBean. Na linha 57 ocomando SQL é executado e as linhas 59 a 72 montam o resultado da consulta.

O método insere() (linhas 79 a 148) é responsável por inserir umitem na agenda. Na linha 95 é obtida uma conexão com SGBD por meio doobjeto ConnectionBean. Para inserir um novo item é preciso obter o númerodo último identificador usado, incrementar o identificador e inserir na base oitem com o identificador incrementado. Esta operação requer que não sejaacrescentado nenhum identificador entre a operação de leitura do últimoidentificador e a inserção de um novo item. Ou seja, é necessário que essasoperações sejam tratadas como uma única transação e o isolamento entre astransações sejam do nível Repeatable Read. A definição do inicio da transação éfeita no comando da linha 102. A mudança do nível de isolamento é feita peloscomandos codificados nas linha 103 a 109. Na linha 112 é invocado o métodoobtemUltimo() (linhas 150 a 171) para obter o último identificadorutilizado. As linhas 114 a 128 montam o comando SQL para a execução. Ocomando SQL é executado na linha 131. O fim da transação é definido pelocomando da linha 132. Ao fim da transação, de forma a não prejudicar aconcorrência, o nível de isolamento deve retornar para um valor mais baixo. Istoé feito pelos comandos das linhas 133 a 137.

O método apaga() (linhas 173 a 201) é responsável por remover umitem da agenda. As linhas 175 a 180 contém o código para verificar se o usuáriodigitou o nome associado ao item que deve ser removido. A linha 181 montam ocomando SQL para a execução. Na linha 184 é obtida uma conexão com SGBDpor meio do objeto ConnectionBean. O comando SQL é executado na linha191.

12345678910111213

package agenda;

import java.lang.*;import java.util.*;import java.sql.*;

public class AcaoBean{ private Connection con=null; private StringBuffer retorno = null; private Statement stmt=null; private String [] legenda= {"C&oacute;digo","Nome","Telefone", "Endere&ccedil;o", "email","hp",

Page 418: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

417

14151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162

"celular","Descri&ccedil;&atilde;o"};

public AcaoBean(javax.servlet.http.HttpServletRequest request) { String acao = request.getParameter("acao"); if (acao.equals("Consulta")) { String nome = request.getParameter("nome"); String descri = request.getParameter("descricao"); consulta(nome,descri); } else if (acao.equals("Insere")) insere(request); else if (acao.equals("Apaga")) apaga(request); }

private void consulta(String nome,String descri) { String consulta = null;

if ((nome == null||nome.length()<1) && (descri == null|| descri.length()<1)) { retorno = new StringBuffer("Digite o nome ou descricao!"); return; }

if (descri == null|| descri.length()<1) consulta = "SELECT * FROM PESSOA WHERE NOME LIKE '%"+ nome+"%'"+" ORDER BY NOME"; else if (nome == null|| nome.length()<1) consulta = "SELECT * FROM PESSOA WHERE DESCRICAO LIKE '%"+ descri+"%'"+" ORDER BY NOME"; else consulta="SELECT * FROM PESSOA WHERE DESCRICAO LIKE '%"+ descri+"%' AND NOME LIKE '%"+nome+"%' ORDER BY NOME"; try { con=ConnectionBean.getInstance().getConnection(); if (con == null) { retorno = new StringBuffer("Servidor ocupado. Tente mais tarde.!"); return; } stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(consulta);

retorno = new StringBuffer(); retorno.append("<br><h3>Resultado</h3><br>"); while(rs.next()) {

Page 419: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

418

63646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111

retorno.append("ID:").append(rs.getString("id")); retorno.append("<br>Nome:").append(rs.getString("Nome")); retorno.append("<br>Telefone:").append(rs.getString("Telefone")); retorno.append("<br>Endereco:").append(rs.getString("Endereco")); retorno.append("<br>email:").append(rs.getString("email")); retorno.append("<br>hp:").append(rs.getString("hp")); retorno.append("<br>celular:").append(rs.getString("celular")); retorno.append("<br>descricao:").append(rs.getString("descricao")); retorno.append("<br><br>"); } } catch(Exception e){System.out.println(e.getMessage());} finally {ConnectionBean.getInstance().devolveConnection(con); try{stmt.close();}catch(Exception ee){}; } }

private void insere(javax.servlet.http.HttpServletRequest request) { String[] par = {"telefone","endereco","email","hp","celular","descricao"};

StringBuffer comando = new StringBuffer("INSERT INTO PESSOA("); StringBuffer values = new StringBuffer(" VALUES(");

String aux = request.getParameter("nome"); if (aux == null || aux.length()<1) { retorno = new StringBuffer("<br><h3>Digite o nome!</h3><br>"); return; }

try { con=ConnectionBean.getInstance().getConnection(); if (con == null) { retorno = new StringBuffer("Servidor ocupado. Tente mais tarde!"); return; }

con.setAutoCommit(false); DatabaseMetaData meta=con.getMetaData();

if(meta.supportsTransactionIsolationLevel( con.TRANSACTION_REPEATABLE_READ)) { con.setTransactionIsolation( con.TRANSACTION_REPEATABLE_READ); }

Page 420: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

419

112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160

int ultimo = obtemUltimo(con); if (ultimo==-1) return; ultimo++; comando.append("id,nome"); values.append(ultimo+",'").append(aux).append("'");

for(int i=0;i<par.length;i++) { aux = request.getParameter(par[i]); if (aux != null && aux.length()>0) { comando.append(",").append(par[i]); values.append(",'").append(aux).append("'"); } } comando.append(")"); values.append(")"); aux = comando.toString()+values.toString(); stmt = con.createStatement(); stmt.executeUpdate(aux); con.setAutoCommit(true); if(meta.supportsTransactionIsolationLevel( con.TRANSACTION_READ_COMMITTED)) { con.setTransactionIsolation( con.TRANSACTION_READ_COMMITTED); } retorno = new StringBuffer("<br><h3>Inserido!</h3><br>"); return; } catch(Exception e) {retorno = new StringBuffer("<br><h3>Erro:"+e.getMessage()+"!</h3><br>"); } finally { ConnectionBean.getInstance().devolveConnection(con); try{stmt.close();}catch(Exception ee){}; } }

private int obtemUltimo(Connection con) { String consulta = "SELECT MAX(ID) AS maior FROM PESSOA"; try { if (con == null) { retorno = new StringBuffer("Servidor ocupado. Tente mais tarde.!"); return -1; }

Page 421: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

420

161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205

stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(consulta); if(rs.next()) return Integer.parseInt(rs.getString("maior")); else return 0; } catch(Exception e) { retorno = new StringBuffer("<br><h3>Erro:"+e.getMessage()+"!</h3><br>"); return -1; } finally {try{stmt.close();}catch(Exception ee){};} }

private void apaga(javax.servlet.http.HttpServletRequest request) { String aux = request.getParameter("nome"); if (aux == null || aux.length()<1) { retorno = new StringBuffer("<br><h3>Digite o nome!</h3><br>"); return; } String consulta = "DELETE FROM PESSOA WHERE NOME ='"+aux+"'"; try { con=ConnectionBean.getInstance().getConnection(); if (con == null) { retorno = new StringBuffer("Servidor ocupado. Tente mais tarde.!"); return; } stmt = con.createStatement(); stmt.executeUpdate(consulta);

retorno = new StringBuffer("<br><h3>Removido!</h3><br>"); return; } catch(Exception e){ retorno = new StringBuffer("<br><h3>Erro:"+e.getMessage()+"!</h3><br>"); } finally { ConnectionBean.getInstance().devolveConnection(con); try{stmt.close();}catch(Exception ee){};} }

public String[] getLeg(){return legenda;} public String toString(){return retorno.toString();}}

Exemplo XVI.XX – AcaoBean.java.

Page 422: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

421

Instalação do SGBD

O HSQLDB (www.hsqldb.org) é um SGBD de código abertodesenvolvido em Java. Ele obedece os padrões SQL e JDBC. Possui as seguintescaracterísticas:

• Tamanho pequeno (≅ 100KB).• Funciona como servidor, standalone e in-memory.• Suporta transação.• Integridade referencial.• Procedimentos Armazenados em Java.• Direitos de acessos

Para instalá-lo em no MS-Windows execute as seguintes etapas:

1) Descompacte o arquivo hsqldb_v.1.61.zip em um diretório qualquer. Porexemplo : c:\sgbd

2) Coloque o seguinte comando em seu autoexec.bat

SET CLASSPATH=%CLASSPATH%;c:\sgbd\hsqldb_v.1.61\lib\hsqldb.jar

Execução em modo servidor

c:\sgbd\hsqldb_v.1.61\demo\runServer.bat

Execução do gerenciador gráfico

c:\sgbd\hsqldb_v.1.61\demo\runManager.bat

Instalação da Aplicação

Para instalar crie a seguinte estrutura de diretório abaixo do diretóriowebapps do Tomcat:

Servlets eJavaBeans

páginasHTML e JSP

arquivoweb.xml

Page 423: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

422

webapps |_____ agenda |_____ Web-inf |_____classes |_______agenda

Figura XV.XX. Estrutura de diretórios para a aplicação agenda.

O arquivo web.xml deve ser alterado para conter mapeamento entre aURL agenda e o Servlet AgendaServlet.

...<web-app> <servlet> <servlet-name> agenda </servlet-name> <servlet-class> agenda.AgendaServlet </servlet-class> </servlet>

<servlet-mapping> <servlet-name> agenda </servlet-name> <url-pattern> /agenda </url-pattern> </servlet-mapping>...</web-app>

Figura XV.XX. Arquivo web.xml para a agenda.

Considerações sobre a solução

Page 424: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

423

A aplicação acima implementa uma agenda que pode ser acessada por meioda Internet, no entanto, devido à falta de espaço e à necessidade de destacarmosos pontos principais, alguns detalhes foram deixados de lado, como por exemplouma melhor interface com o usuário. Abaixo seguem alguns comentários sobrealgumas particularidades da aplicação:

1. O JavaBean da classe LoginBean é armazenado na sessão parapermitir a verificação se o acesso ao site é autorizado. Isto impede que osusuários tentem acessar diretamente a página principal.jsp daagenda. Caso tentem fazer isso, a sessão não conterá um objetoLoginBean associado e, portanto, o acesso será recusado.

2. O JavaBean da classe AcaoBean é armazenado no objeto requestuma vez que sua informações são alteradas a cada requisição. Uma formamais eficiente seria manter o objeto AcaoBean na sessão e cada novorequisição invocar um método do AcaoBean para gerar os resultados.No entanto, o objetivo da nossa implementação não é fazer a aplicaçãomais eficiente possível, e sim mostrar para o leitor uma aplicação comvariadas técnicas.

3. Apesar de termos adotado o padrão MVC de desenvolvimento aaplicação não exibe uma separação total da camada de apresentação(Visão) em relação à camada do modelo. Parte do código HTML davisão é inserido pelo AcaoBean no momento da construção da Stringcontendo o resultado da ação. Isto foi feito para minimizar a quantidadede código Java na página JSP. Pode-se argumentar que neste caso apromessa da separação entre as camadas não é cumprida totalmente.Uma solução para o problema seria gerar o conteúdo em XML e utilizarum analisador de XML para gerar a página de apresentação. No entanto,o uso da tecnologia XML foge ao escopo deste livro.

4. A solução apresenta código redundante para criticar as entradas dousuário. Existe código JavaScript nas páginas, e código Java no Servlet eJavaBeans. O uso de código JavaScript nas páginas para críticas deentrada é indispensável para aliviarmos a carga sobre o servidor. Já ocódigo para crítica no servidor não causa impacto perceptível e útil paraevitar tentativas de violação.

Page 425: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

424

Capítulo XVII Perguntas FrequentesComo executar um programa a partir de uma aplicação em Java?

Resposta: isso pode ser feito com o método de instância exec da classeRuntime.

Como criar um TextField que não exiba o que está sendo digitado parase usado como campo de entrada de senhas?

Resposta: use o método setEchoChar() do TextField para definir qualcaractere que deve ser ecoado.

Como aumentar a área de ambiente do DOS para caber o CLASSPATH?

Resposta: coloque a seguinte linha no autoexec.bat

set shell=c:\command.com /e:4096

Page 426: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

425

BibliografiaEckel B. Thinking in Java. 2nd Ed. New Jersey : Prentice Hall, 2000.

Gosling J., Joy W., Steele G. The Java Language Specification. Massachusetts :Addison-Wesley, 1996.

Oaks S. Java Security. California : O’Reilly & Associates, Inc, 1998.

Oaks S., Wong H. Java Threads. 2ª Ed. California : O’Reilly & Associates, Inc,1999.

Watt D. A. Programming Language Concepts and Paradigms. Great Britain :Prentice Hall, 1990.

Ethan H., Lycklama E. How do you Plug Java Memory Leaks? Dr. Dobb´sJournal, San Francisco, CA, No. 309, February 2000.

Wahli U. e outros. Servlet and JSP Programming with IBM WebSphere Studioand VisualAge for Java, IBM RedBooks, California, May 2000.

Sadtler C. e outros. Patterns for e-business: User-to-Business Patterns for Topology1 and 2 using WebSphere Advanced Edition, IBM RedBooks, California, April2000.

Bagwel D. e outros. An Approach to Designing e-business Solutions, IBMRedBooks, California, December 1998.

Page 427: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

426

LinksRevistas

http://www.javaworld.com/Revista online sobre Java.

Livroshttp://www.eckelobjects.com/Página do autor do livro Thinking in Java, atualmente em segunda edição. Olivro pode ser baixado gratuitamente no site.

http://www.redbooks.ibm.com/booklist.htmlLivros da IBM

Servidoreshttp://jakarta.apache.orgPágina do projeto Jakarta que desenvolveu o Tomcat.

http://www.metronet.com/~wjm/tomcatLista Tomcat

http://www.jboss.orgServidor de aplicação gratuito habilitado para EJB

Dicas Java e recursoshttp://java.sun.com/Página da Sun com informações, tutoriais e produtos Java.

http://gamelan.earthweb.com/Página da com informações, Applets, Lista de discussão, tutoriais.

http://www.inquiry.com/techtips/java_proAsk the Java Pro

http://www.jguru.com/jGuru.com(Home): Your view of the Java universe

http://www.soujava.org.br

Page 428: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

427

Bem Vindo ao SouJava!

Servlets e JSPhttp://www.servlet.com/srvdev.jhtmlServlet Inc : Developers Forum

http://www.servlets.comServlets.com

http://www.jspin.com/homeJspin.com - The JSP Resource Index

http://www.burridge.net/jsp/jspinfo.htmlWeb Development with JSP: JSP, Java Servlet, and Java BeanInformation

http://www.apl.jhu.edu/~hall/java/Servlet-TutorialA Tutorial on Java Servlets and Java Server Pages (JSP)

Page 429: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

428

ÍndiceA

Acesso Direto.........................................128Acesso Sequencial .................................123Agregação ................................................25Arrays .............................................37, 142ASP ........................................................378Assert ...................................................63Assertivas ......................Consulte AssertAssinatura dos métodos .....................18, 21Associação comum ..................................23Atribuição ...............................................49atributos ...................................................67Atributos ..................................................11AWT ......................................................165

B

Bloco........................................................52boolean.....................................................33booleanos

boolean................................................37break .....................................................60Button .................................................201Bytecodes.............................................7, 28

C

cadeias de caracteres ......... Consulte StringsCalendar ................................................1Caractere

char......................................................37cardinalidade da relação...........................23casting ............ Consulte Conversão de tiposCGI ........................................................353char ..........................................................33Classe .................................................11, 66classe anônima .......................................180clone.........................................................81Coleta de Lixo............................................8Color ...................................................197Comentários ...........................................51Component ..........................................199Construtor ................................................16Construtores ...........................................68Containers ..............................................206

contexto da aplicação ............................ 361continue.............................................. 60Convenções ............................................. 10Conversão de Tipos ............................... 41Cookies.................................................. 369Cópia profunda...........Consulte deep copyCópia rasa ..............Consulte Shallow copyCORBA ................................................. 323Criptografia ............................................... 9

D

Date ..................................................... 145deep copy................................................. 81Demilitarized Zone................................ 405Diagrama de Classes................................ 20DMZ.............. Consulte Demilitarized Zonedouble ...................................................... 32do-while .................................................. 58

E

EJB ........................................................ 403Enterprise JavaBeans..............Consulte EJBescape ...................................................... 34Escopo..................................................... 52Estruturas de Controle.......................... 53extends..................................................... 17

F

final ..................................................... 76finally .............................................. 112float.......................................................... 32for............................................................ 59Frame ................................................... 209

G

Garbage Collection..Consulte coleta de lixoGeneralização .......................................... 25

H

Hashtable ......................................... 139Herança.............................................. 12, 14hexadecimal............................................. 31

Page 430: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

1I

Identificadores........................................29if.............................................................53Instância ...................................................11Inteiros

int 36

J

J2EE.........................................................10J2ME........................................................10JAR ........................................................234java.io...............................................123JavaBean ................................................239JCE.............................................................9JDK..........................................................10JSP .................................................351, 376

L

Label ...................................................202linha de comando ...................................61List......................................................203Literais ....................................................31

M

main .........................................................28Máquina Virtual .........................................7método de classe ......................................71método de instância..................................71métodos....................................................67Métodos ...................................................15Modificadores de acesso ........................72Mudança de Contexto..........................259MVC ......................................147, 402, 405

N

native ...................................................78Níveis de isolamento..............................339Nível de Isolamento ...............................337null........................................................34

O

Object.......................................................19Objeto

Comportamento...................................12Objetos...............................................11, 69Observable .......................................147Observer ....................................148, 150

octal ......................................................... 31Ocultação de informação................... 14, 16Olá mundo ............................................... 27Operadores............................................. 43

P

Palavras Reservadas.............................. 30Panel ................................................... 208PHP ....................................................... 377Polimorfismo ........................................... 19Ponteiro ..................................................... 7Ponto Flutuante

float, double ........................................ 36pool de conexões ................................... 411Precedência entre Operadores ............. 50Prepared Statements .............................. 341private...................................................... 16Procedimentos Armazenados ................ 342Propriedades ............................................ 11

R

RandomAccessFile......................... 128recursão ................................................... 57Referências Compartilhadas ................ 78return .................................................. 69RMI ....................................................... 323

S

separadores .............................................. 34Servlets .................................................. 351shallow copy ............................................ 81Singleton................................................ 412sites dinâmicos ...................................... 351Smalltalk.................................................... 7Sobrecarga............................................... 18Sobrescrita ............................................... 18Stack ................................................... 137static .................................................. 74Stored Procedures.................................. 342String ....................................................... 33StringBuffer .................................... 79Strings..................................................... 39StringTokenizer ........................... 152super ..................................................... 73Superclasse .............................................. 12switch .................................................. 55synchronized .................................... 78

Page 431: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

2T

TextArea ....................................178, 205TextField ..................................178, 204this........................................................82Tipos de dados ........................................35toString()..................................................42Transação ...............................................337Tratamento de Eventos...........................168

U

UML.........................................................20

Unicode ................................................... 29Unidade de Compilação .......................... 67

V

Vector ................................................ 134Visibilidade ............................................. 22void ....................................................... 69

W

while ..................................................... 57widgets................................................... 165

Page 432: Apostila de java na pratica

Java na Prática

Alcione de P. Oliveira, Vinícius V. Maciel - UFV

1